// cs_161_165.c
/*
C/C++の宿題片付けます 161代目
http://t...content-available-to-author-only...h.net/test/read.cgi/tech/1354070278/165
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
/* 共通エラーコード */
typedef enum {
EC_Normal, // 正常終了
EC_FileOpen, // ファイルオープン失敗
EC_MemAlloc, // メモリ確保失敗
EC_CantAddHash, // Hashテーブル記録先が見つけられなかった(衝突時のハッシュ関数が甘い)
} ERR_CODE;
char *getStr_ERR_CODE(ERR_CODE ec)
{
switch (ec) {
case EC_Normal :return "正常終了";
case EC_FileOpen :return "ファイルオープン失敗";
case EC_MemAlloc :return "メモリ確保失敗";
case EC_CantAddHash :return "Hashテーブル記録先が見つけられなかった(衝突時のハッシュ関数が甘い)";
}
return "";
}
/* 重複文字列があったときに、追加するか無視するか */
typedef enum {
AMD_ADD, // 追加する
AMD_MUSI, // 追加しない
} ADD_MODE;
char *getStr_ADD_MODE(ADD_MODE code)
{
switch (code) {
case AMD_ADD :return "追加する";
case AMD_MUSI :return "追加しない";
}
return "";
}
/* data */
typedef struct {
ADD_MODE mode; // (手動設定)重複時の動作
int flag_res_out; // (手動設定)結果出力時、空のテーブル要素を出力するかどうなのか(1 or 0)
int data_n; // 文字列数
int len_max; // 文字列最大長
int tbl_size; // ハッシュテーブルサイズ
char **table; // ハッシュテーブル
int *ref_search_count; // table[] 探索参照カウンタ
} HASH_DATA;
/* prototype */
extern int hashfunc_h(char *s, HASH_DATA * hash);
extern int hashfunc_p(char *s, HASH_DATA * hash);
extern ERR_CODE hash_creat(HASH_DATA * hash, char *filename);
extern ERR_CODE hash_make(HASH_DATA * hash, char *filename);
extern ERR_CODE hash_add(HASH_DATA * hash, char *str);
extern void hash_show(HASH_DATA * hash, char *src_filename);
extern void hash_delete(HASH_DATA * hash);
extern int strcmp_ignore(char *s1, char *s2);
/*
* main
*/
int main(int argc, char *argv[])
{
int res = (int) EC_Normal;
HASH_DATA hd;
// 初期化
memset(&hd
, 0x00, sizeof(HASH_DATA
)); hd.mode = AMD_MUSI; // (手動設定)重複時の動作
hd.flag_res_out = 1; // (手動設定)結果出力時、空のテーブル要素を出力するかどうなのか(1 or 0)
if (EC_Normal != (res = hash_creat(&hd, argv[1]))) {
goto END_main;
}
// ハッシュ作成
if (EC_Normal != (res = hash_make(&hd, argv[1]))) {
goto END_main;
}
// 結果表示
hash_show(&hd, argv[1]);
// 終了
res = (int) EC_Normal;
END_main:
hash_delete(&hd);
if (res != EC_Normal) {
fprintf(stderr
, "Err :%s\n", getStr_ERR_CODE
(res
)); }
return res;
}
/* 大小文字区別なし文字列比較 (負:s1<s2, 正:s1>s2, 0:s1==s2)
* ※ s1="321", s2="321000"のときは、s1 < s2
*/
int strcmp_ignore(char *s1, char *s2)
{
int cmp;
while (1) {
if (cmp) {
break;
}
if (*s1 == '\0' && *s2 == '\0') {
break;
}
s1++;
s2++;
}
return cmp;
}
/*
* HASH_DATA operation
*/
// ファイル filename を解析して、HASH_DATAを初期化
ERR_CODE hash_creat(HASH_DATA * hash, char *filename)
{
FILE *fp;
int len, pos_now, pos_prev;
int c;
// 単語数カウント
if (NULL
== (fp
= fopen(filename
, "r"))) { return EC_FileOpen;
}
pos_now = pos_prev = 0;
if (c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == EOF) {
++hash->data_n;
len = pos_now - pos_prev;
if (hash->len_max < len) {
hash->len_max = len;
}
pos_prev = pos_now + 1;
if (c == EOF) {
break;
}
}
pos_now++;
}
// HashTableサイズ決め (単語数の2倍以上 かつ 素数)
int n;
hash->tbl_size = hash->data_n * 2;
while (1) {
for (n = 2; (n * n < hash->tbl_size) && (hash->tbl_size % n); ++n);
if (hash->tbl_size % n) { /* 素数 */
break;
}
++hash->tbl_size;
}
// 確保
if (NULL
== (hash
->table
= (char **) malloc(sizeof(char *) * hash
->tbl_size
))) { return EC_MemAlloc;
}
memset(hash
->table
, 0x00, sizeof(char *) * hash
->tbl_size
); if (NULL
== (hash
->ref_search_count
= (int *) malloc(sizeof(int) * hash
->tbl_size
))) { return EC_MemAlloc;
}
memset(hash
->ref_search_count
, 0x00, sizeof(int) * hash
->tbl_size
);
return EC_Normal;
}
void hash_delete(HASH_DATA * hash)
{
int i;
if (hash) {
if (hash->table) {
for (i = 0; i < hash->len_max; i++) {
if (hash->table[i]) {
hash->table[i] = NULL;
}
}
hash->table = NULL;
}
if (hash->ref_search_count) {
free(hash
->ref_search_count
); hash->ref_search_count = NULL;
}
memset(hash
, 0x00, sizeof(HASH_DATA
)); }
}
ERR_CODE hash_make(HASH_DATA * hash, char *filename)
{
FILE *fp = NULL;
char *buf = NULL, *p;
int c;
ERR_CODE res = EC_Normal;
// バッファ確保
if (NULL
== (buf
= (char *) malloc(sizeof(char) * (hash
->len_max
+ 2)))) { res = EC_MemAlloc;
goto END_hash_make;
}
// 読み込み & ハッシュに追加
fp
= fopen(filename
, "r"); p = &buf[0];
if (c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == EOF) {
*p = '\0';
p = &buf[0];
if (EC_Normal != (res = hash_add(hash, &buf[0]))) {
goto END_hash_make;
}
}
if (c == EOF) {
break;
}
} else {
*p++ = (char) c;
}
}
// 終了
res = EC_Normal;
END_hash_make:
if (buf) {
buf = NULL;
}
if (fp) {
fp = NULL;
}
return res;
}
ERR_CODE hash_add(HASH_DATA * hash, char *str)
{
int index; // 記録先
int next_step; // 衝突時書き込み先探索ステップ
int limit; // 記録先が見つからない場合への備え
// hash値取得
index = hashfunc_h(str, hash);
hash->ref_search_count[index]++; // 探索参照カウンタ
// 衝突
if (hash->table[index]) {
// 同一文字列
if (0 == strcmp_ignore(hash->table[index], str)) {
if (hash->mode == AMD_MUSI) {
return EC_Normal;
}
}
// 衝突後 入れ先探索
next_step = hashfunc_p(str, hash);
for (limit = 0; limit < hash->tbl_size; limit++) {
index = (index + next_step) % hash->tbl_size;
hash->ref_search_count[index]++; // 探索参照カウンタ
if (NULL == hash->table[index]) {
break;
}
}
if (limit >= hash->tbl_size) {
return EC_CantAddHash;
}
}
// 追加
if (NULL
== (hash
->table
[index
] = (char *) malloc(sizeof(char) * strlen(str
) + 1))) { return EC_MemAlloc;
}
strcpy(hash
->table
[index
], str
);
// end
return EC_Normal;
}
void hash_show(HASH_DATA * hash, char *src_filename)
{
int i;
char b[256];
int keta_cell; // セル番号桁数
int keta_ref; // 参照回数桁数
int m;
// 桁数計算
keta_cell
= sprintf(b
, "%d", hash
->tbl_size
); for (i = m = 0; i < hash->tbl_size; i++) {
if (m > hash->ref_search_count[i]) {
m = hash->ref_search_count[i];
}
}
// 出力
fprintf(stdout
, "・入力ファイル : %s\n", src_filename
); fprintf(stdout
, "・最大文字列長 : %d\n", hash
->len_max
); fprintf(stdout
, "・文字列数 : %d個\n", hash
->data_n
); fprintf(stdout
, "・Hashテーブル数 : %d個\n", hash
->tbl_size
); fprintf(stdout
, "・Hash追加モード : 同一文字列を、%s\n", getStr_ADD_MODE
(hash
->mode
)); fprintf(stdout
, "・当結果出力モード : 空のテーブル要素を出力%s\n", hash
->flag_res_out
? "する" : "しない"); for (i = 0; i < hash->tbl_size; i++) {
if (hash->flag_res_out || hash->table[i]) {
fprintf(stdout
, "[%0*d] 参照回数 = %0*d, 格納文字 = [%s]\n", keta_cell
, i
, keta_ref
, hash
->ref_search_count
[i
] , hash->table[i] ? hash->table[i] : "");
}
}
}
/*
* hash functions
*/
int hashfunc_h(char *s, HASH_DATA * hash)
{
int r = 0;
while (*s) {
if ('a' <= *s && *s <= 'z') {
r = r * 26 + (*s - 'a');
r %= hash->tbl_size;
}
++s;
}
return r;
}
int hashfunc_p(char *s, HASH_DATA * hash)
{
return 1;
}
// End of cs_161_165.c
Ly8gY3NfMTYxXzE2NS5jCi8qCiAgICBDL0MrK+OBruWuv+mhjOeJh+S7mOOBkeOBvuOBmSAxNjHku6Pnm64KICAgIGh0dHA6Ly90Li4uY29udGVudC1hdmFpbGFibGUtdG8tYXV0aG9yLW9ubHkuLi5oLm5ldC90ZXN0L3JlYWQuY2dpL3RlY2gvMTM1NDA3MDI3OC8xNjUKICovCgojaW5jbHVkZSA8c3RkaW8uaD4KI2luY2x1ZGUgPHN0ZGxpYi5oPgojaW5jbHVkZSA8c3RyaW5nLmg+CiNpbmNsdWRlIDxjdHlwZS5oPgoKLyog5YWx6YCa44Ko44Op44O844Kz44O844OJICovCnR5cGVkZWYgZW51bSB7CiAgICBFQ19Ob3JtYWwsICAgICAgICAgICAgICAgICAgLy8g5q2j5bi457WC5LqGCiAgICBFQ19GaWxlT3BlbiwgICAgICAgICAgICAgICAgLy8g44OV44Kh44Kk44Or44Kq44O844OX44Oz5aSx5pWXCiAgICBFQ19NZW1BbGxvYywgICAgICAgICAgICAgICAgLy8g44Oh44Oi44Oq56K65L+d5aSx5pWXCiAgICBFQ19DYW50QWRkSGFzaCwgICAgICAgICAgICAgLy8gSGFzaOODhuODvOODluODq+iomOmMsuWFiOOBjOimi+OBpOOBkeOCieOCjOOBquOBi+OBo+OBnyjooZ3nqoHmmYLjga7jg4/jg4Pjgrfjg6XplqLmlbDjgYznlJjjgYQpCn0gRVJSX0NPREU7CmNoYXIgKmdldFN0cl9FUlJfQ09ERShFUlJfQ09ERSBlYykKewogICAgc3dpdGNoIChlYykgewogICAgY2FzZSBFQ19Ob3JtYWwgICAgICA6cmV0dXJuICLmraPluLjntYLkuoYiOwogICAgY2FzZSBFQ19GaWxlT3BlbiAgICA6cmV0dXJuICLjg5XjgqHjgqTjg6vjgqrjg7zjg5fjg7PlpLHmlZciOwogICAgY2FzZSBFQ19NZW1BbGxvYyAgICA6cmV0dXJuICLjg6Hjg6Ljg6rnorrkv53lpLHmlZciOwogICAgY2FzZSBFQ19DYW50QWRkSGFzaCA6cmV0dXJuICJIYXNo44OG44O844OW44Or6KiY6Yyy5YWI44GM6KaL44Gk44GR44KJ44KM44Gq44GL44Gj44GfKOihneeqgeaZguOBruODj+ODg+OCt+ODpemWouaVsOOBjOeUmOOBhCkiOwogICAgfQogICAgcmV0dXJuICIiOwp9CgovKiDph43opIfmloflrZfliJfjgYzjgYLjgaPjgZ/jgajjgY3jgavjgIHov73liqDjgZnjgovjgYvnhKHoppbjgZnjgovjgYsgKi8KdHlwZWRlZiBlbnVtIHsKICAgIEFNRF9BREQsICAgICAgICAgICAgICAgICAgICAvLyDov73liqDjgZnjgosKICAgIEFNRF9NVVNJLCAgICAgICAgICAgICAgICAgICAvLyDov73liqDjgZfjgarjgYQKfSBBRERfTU9ERTsKY2hhciAqZ2V0U3RyX0FERF9NT0RFKEFERF9NT0RFIGNvZGUpCnsKICAgIHN3aXRjaCAoY29kZSkgewogICAgY2FzZSBBTURfQUREICAgIDpyZXR1cm4gIui/veWKoOOBmeOCiyI7CiAgICBjYXNlIEFNRF9NVVNJICAgOnJldHVybiAi6L+95Yqg44GX44Gq44GEIjsKICAgIH0KICAgIHJldHVybiAiIjsKfQoKLyogZGF0YSAqLwp0eXBlZGVmIHN0cnVjdCB7CiAgICBBRERfTU9ERSBtb2RlOyAgICAgICAgICAgICAgLy8gKOaJi+WLleioreWuminph43opIfmmYLjga7li5XkvZwKICAgIGludCBmbGFnX3Jlc19vdXQ7ICAgICAgICAgICAvLyAo5omL5YuV6Kit5a6aKee1kOaenOWHuuWKm+aZguOAgeepuuOBruODhuODvOODluODq+imgee0oOOCkuWHuuWKm+OBmeOCi+OBi+OBqeOBhuOBquOBruOBiygxIG9yIDApCiAgICBpbnQgZGF0YV9uOyAgICAgICAgICAgICAgICAgLy8g5paH5a2X5YiX5pWwCiAgICBpbnQgbGVuX21heDsgICAgICAgICAgICAgICAgLy8g5paH5a2X5YiX5pyA5aSn6ZW3CiAgICBpbnQgdGJsX3NpemU7ICAgICAgICAgICAgICAgLy8g44OP44OD44K344Ol44OG44O844OW44Or44K144Kk44K6CiAgICBjaGFyICoqdGFibGU7ICAgICAgICAgICAgICAgLy8g44OP44OD44K344Ol44OG44O844OW44OrCiAgICBpbnQgKnJlZl9zZWFyY2hfY291bnQ7ICAgICAgLy8gdGFibGVbXSDmjqLntKLlj4Lnhafjgqvjgqbjg7Pjgr8KfSBIQVNIX0RBVEE7CgovKiBwcm90b3R5cGUgKi8KZXh0ZXJuIGludCBoYXNoZnVuY19oKGNoYXIgKnMsIEhBU0hfREFUQSAqIGhhc2gpOwpleHRlcm4gaW50IGhhc2hmdW5jX3AoY2hhciAqcywgSEFTSF9EQVRBICogaGFzaCk7CmV4dGVybiBFUlJfQ09ERSBoYXNoX2NyZWF0KEhBU0hfREFUQSAqIGhhc2gsIGNoYXIgKmZpbGVuYW1lKTsKZXh0ZXJuIEVSUl9DT0RFIGhhc2hfbWFrZShIQVNIX0RBVEEgKiBoYXNoLCBjaGFyICpmaWxlbmFtZSk7CmV4dGVybiBFUlJfQ09ERSBoYXNoX2FkZChIQVNIX0RBVEEgKiBoYXNoLCBjaGFyICpzdHIpOwpleHRlcm4gdm9pZCBoYXNoX3Nob3coSEFTSF9EQVRBICogaGFzaCwgY2hhciAqc3JjX2ZpbGVuYW1lKTsKZXh0ZXJuIHZvaWQgaGFzaF9kZWxldGUoSEFTSF9EQVRBICogaGFzaCk7CmV4dGVybiBpbnQgc3RyY21wX2lnbm9yZShjaGFyICpzMSwgY2hhciAqczIpOwoKLyoKICogICAgICBtYWluCiAqLwppbnQgbWFpbihpbnQgYXJnYywgY2hhciAqYXJndltdKQp7CiAgICBpbnQgcmVzID0gKGludCkgRUNfTm9ybWFsOwogICAgSEFTSF9EQVRBIGhkOwoKICAgIC8vIOWIneacn+WMlgogICAgbWVtc2V0KCZoZCwgMHgwMCwgc2l6ZW9mKEhBU0hfREFUQSkpOwogICAgaGQubW9kZSA9IEFNRF9NVVNJOyAgICAgICAgIC8vICjmiYvli5XoqK3lrpop6YeN6KSH5pmC44Gu5YuV5L2cCiAgICBoZC5mbGFnX3Jlc19vdXQgPSAxOyAgICAgICAgLy8gKOaJi+WLleioreWuminntZDmnpzlh7rlipvmmYLjgIHnqbrjga7jg4bjg7zjg5bjg6vopoHntKDjgpLlh7rlipvjgZnjgovjgYvjganjgYbjgarjga7jgYsoMSBvciAwKQogICAgaWYgKEVDX05vcm1hbCAhPSAocmVzID0gaGFzaF9jcmVhdCgmaGQsIGFyZ3ZbMV0pKSkgewogICAgICAgIGdvdG8gRU5EX21haW47CiAgICB9CiAgICAvLyDjg4/jg4Pjgrfjg6XkvZzmiJAKICAgIGlmIChFQ19Ob3JtYWwgIT0gKHJlcyA9IGhhc2hfbWFrZSgmaGQsIGFyZ3ZbMV0pKSkgewogICAgICAgIGdvdG8gRU5EX21haW47CiAgICB9CiAgICAvLyDntZDmnpzooajnpLoKICAgIGhhc2hfc2hvdygmaGQsIGFyZ3ZbMV0pOwogICAgLy8g57WC5LqGCiAgICByZXMgPSAoaW50KSBFQ19Ob3JtYWw7CiAgRU5EX21haW46CiAgICBoYXNoX2RlbGV0ZSgmaGQpOwogICAgaWYgKHJlcyAhPSBFQ19Ob3JtYWwpIHsKICAgICAgICBmcHJpbnRmKHN0ZGVyciwgIkVyciA6JXNcbiIsIGdldFN0cl9FUlJfQ09ERShyZXMpKTsKICAgIH0KICAgIHJldHVybiByZXM7Cn0KCi8qIOWkp+Wwj+aWh+Wtl+WMuuWIpeOBquOBl+aWh+Wtl+WIl+avlOi8gyAo6LKgOnMxPHMyLCDmraM6czE+czIsIDA6czE9PXMyKQogKiAg4oC7IHMxPSIzMjEiLCBzMj0iMzIxMDAwIuOBruOBqOOBjeOBr+OAgXMxIDwgczIKICovCmludCBzdHJjbXBfaWdub3JlKGNoYXIgKnMxLCBjaGFyICpzMikKewogICAgaW50IGNtcDsKICAgIHdoaWxlICgxKSB7CiAgICAgICAgY21wID0gdG9sb3dlcigoaW50KSAqczEpIC0gdG9sb3dlcigoaW50KSAqczIpOwogICAgICAgIGlmIChjbXApIHsKICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgfQogICAgICAgIGlmICgqczEgPT0gJ1wwJyAmJiAqczIgPT0gJ1wwJykgewogICAgICAgICAgICBicmVhazsKICAgICAgICB9CiAgICAgICAgczErKzsKICAgICAgICBzMisrOwogICAgfQoKICAgIHJldHVybiBjbXA7Cn0KCi8qCiAqICAgICAgSEFTSF9EQVRBIG9wZXJhdGlvbgogKi8KLy8g44OV44Kh44Kk44OrIGZpbGVuYW1lIOOCkuino+aekOOBl+OBpuOAgUhBU0hfREFUQeOCkuWIneacn+WMlgoKRVJSX0NPREUgaGFzaF9jcmVhdChIQVNIX0RBVEEgKiBoYXNoLCBjaGFyICpmaWxlbmFtZSkKewogICAgRklMRSAqZnA7CiAgICBpbnQgbGVuLCBwb3Nfbm93LCBwb3NfcHJldjsKICAgIGludCBjOwoKICAgIC8vIOWNmOiqnuaVsOOCq+OCpuODs+ODiAogICAgaWYgKE5VTEwgPT0gKGZwID0gZm9wZW4oZmlsZW5hbWUsICJyIikpKSB7CiAgICAgICAgcmV0dXJuIEVDX0ZpbGVPcGVuOwogICAgfQogICAgcG9zX25vdyA9IHBvc19wcmV2ID0gMDsKICAgIHdoaWxlIChjID0gZmdldGMoZnApKSB7CiAgICAgICAgaWYgKGMgPT0gJyAnIHx8IGMgPT0gJ1x0JyB8fCBjID09ICdccicgfHwgYyA9PSAnXG4nIHx8IGMgPT0gRU9GKSB7CiAgICAgICAgICAgICsraGFzaC0+ZGF0YV9uOwogICAgICAgICAgICBsZW4gPSBwb3Nfbm93IC0gcG9zX3ByZXY7CiAgICAgICAgICAgIGlmIChoYXNoLT5sZW5fbWF4IDwgbGVuKSB7CiAgICAgICAgICAgICAgICBoYXNoLT5sZW5fbWF4ID0gbGVuOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHBvc19wcmV2ID0gcG9zX25vdyArIDE7CiAgICAgICAgICAgIGlmIChjID09IEVPRikgewogICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgcG9zX25vdysrOwogICAgfQogICAgZmNsb3NlKGZwKTsKICAgIC8vIEhhc2hUYWJsZeOCteOCpOOCuuaxuuOCgSAo5Y2Y6Kqe5pWw44GuMuWAjeS7peS4iiDjgYvjgaQg57Sg5pWwKQogICAgaW50IG47CiAgICBoYXNoLT50Ymxfc2l6ZSA9IGhhc2gtPmRhdGFfbiAqIDI7CiAgICB3aGlsZSAoMSkgewogICAgICAgIGZvciAobiA9IDI7IChuICogbiA8IGhhc2gtPnRibF9zaXplKSAmJiAoaGFzaC0+dGJsX3NpemUgJSBuKTsgKytuKTsKICAgICAgICBpZiAoaGFzaC0+dGJsX3NpemUgJSBuKSB7ICAgLyog57Sg5pWwICovCiAgICAgICAgICAgIGJyZWFrOwogICAgICAgIH0KICAgICAgICArK2hhc2gtPnRibF9zaXplOwogICAgfQogICAgLy8g56K65L+dCiAgICBpZiAoTlVMTCA9PSAoaGFzaC0+dGFibGUgPSAoY2hhciAqKikgbWFsbG9jKHNpemVvZihjaGFyICopICogaGFzaC0+dGJsX3NpemUpKSkgewogICAgICAgIHJldHVybiBFQ19NZW1BbGxvYzsKICAgIH0KICAgIG1lbXNldChoYXNoLT50YWJsZSwgMHgwMCwgc2l6ZW9mKGNoYXIgKikgKiBoYXNoLT50Ymxfc2l6ZSk7CiAgICBpZiAoTlVMTCA9PSAoaGFzaC0+cmVmX3NlYXJjaF9jb3VudCA9IChpbnQgKikgbWFsbG9jKHNpemVvZihpbnQpICogaGFzaC0+dGJsX3NpemUpKSkgewogICAgICAgIHJldHVybiBFQ19NZW1BbGxvYzsKICAgIH0KICAgIG1lbXNldChoYXNoLT5yZWZfc2VhcmNoX2NvdW50LCAweDAwLCBzaXplb2YoaW50KSAqIGhhc2gtPnRibF9zaXplKTsKCiAgICByZXR1cm4gRUNfTm9ybWFsOwp9Cgp2b2lkIGhhc2hfZGVsZXRlKEhBU0hfREFUQSAqIGhhc2gpCnsKICAgIGludCBpOwogICAgaWYgKGhhc2gpIHsKICAgICAgICBpZiAoaGFzaC0+dGFibGUpIHsKICAgICAgICAgICAgZm9yIChpID0gMDsgaSA8IGhhc2gtPmxlbl9tYXg7IGkrKykgewogICAgICAgICAgICAgICAgaWYgKGhhc2gtPnRhYmxlW2ldKSB7CiAgICAgICAgICAgICAgICAgICAgZnJlZShoYXNoLT50YWJsZVtpXSk7CiAgICAgICAgICAgICAgICAgICAgaGFzaC0+dGFibGVbaV0gPSBOVUxMOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIGZyZWUoaGFzaC0+dGFibGUpOwogICAgICAgICAgICBoYXNoLT50YWJsZSA9IE5VTEw7CiAgICAgICAgfQogICAgICAgIGlmIChoYXNoLT5yZWZfc2VhcmNoX2NvdW50KSB7CiAgICAgICAgICAgIGZyZWUoaGFzaC0+cmVmX3NlYXJjaF9jb3VudCk7CiAgICAgICAgICAgIGhhc2gtPnJlZl9zZWFyY2hfY291bnQgPSBOVUxMOwogICAgICAgIH0KICAgICAgICBtZW1zZXQoaGFzaCwgMHgwMCwgc2l6ZW9mKEhBU0hfREFUQSkpOwogICAgfQp9CgpFUlJfQ09ERSBoYXNoX21ha2UoSEFTSF9EQVRBICogaGFzaCwgY2hhciAqZmlsZW5hbWUpCnsKICAgIEZJTEUgKmZwID0gTlVMTDsKICAgIGNoYXIgKmJ1ZiA9IE5VTEwsICpwOwogICAgaW50IGM7CiAgICBFUlJfQ09ERSByZXMgPSBFQ19Ob3JtYWw7CgogICAgLy8g44OQ44OD44OV44Kh56K65L+dCiAgICBpZiAoTlVMTCA9PSAoYnVmID0gKGNoYXIgKikgbWFsbG9jKHNpemVvZihjaGFyKSAqIChoYXNoLT5sZW5fbWF4ICsgMikpKSkgewogICAgICAgIHJlcyA9IEVDX01lbUFsbG9jOwogICAgICAgIGdvdG8gRU5EX2hhc2hfbWFrZTsKICAgIH0KICAgIC8vIOiqreOBv+i+vOOBvyDvvIYg44OP44OD44K344Ol44Gr6L+95YqgCiAgICBmcCA9IGZvcGVuKGZpbGVuYW1lLCAiciIpOwogICAgcCA9ICZidWZbMF07CiAgICB3aGlsZSAoYyA9IGZnZXRjKGZwKSkgewogICAgICAgIGlmIChjID09ICcgJyB8fCBjID09ICdcdCcgfHwgYyA9PSAnXHInIHx8IGMgPT0gJ1xuJyB8fCBjID09IEVPRikgewogICAgICAgICAgICAqcCA9ICdcMCc7CiAgICAgICAgICAgIHAgPSAmYnVmWzBdOwogICAgICAgICAgICBpZiAoc3RybGVuKGJ1ZikpIHsKICAgICAgICAgICAgICAgIGlmIChFQ19Ob3JtYWwgIT0gKHJlcyA9IGhhc2hfYWRkKGhhc2gsICZidWZbMF0pKSkgewogICAgICAgICAgICAgICAgICAgIGdvdG8gRU5EX2hhc2hfbWFrZTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAoYyA9PSBFT0YpIHsKICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICB9CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgKnArKyA9IChjaGFyKSBjOwogICAgICAgIH0KICAgIH0KICAgIC8vIOe1guS6hgogICAgcmVzID0gRUNfTm9ybWFsOwogIEVORF9oYXNoX21ha2U6CiAgICBpZiAoYnVmKSB7CiAgICAgICAgZnJlZShidWYpOwogICAgICAgIGJ1ZiA9IE5VTEw7CiAgICB9CiAgICBpZiAoZnApIHsKICAgICAgICBmY2xvc2UoZnApOwogICAgICAgIGZwID0gTlVMTDsKICAgIH0KCiAgICByZXR1cm4gcmVzOwp9CgpFUlJfQ09ERSBoYXNoX2FkZChIQVNIX0RBVEEgKiBoYXNoLCBjaGFyICpzdHIpCnsKICAgIGludCBpbmRleDsgICAgICAgICAgICAgICAgICAvLyDoqJjpjLLlhYgKICAgIGludCBuZXh0X3N0ZXA7ICAgICAgICAgICAgICAvLyDooZ3nqoHmmYLmm7jjgY3ovrzjgb/lhYjmjqLntKLjgrnjg4bjg4Pjg5cKICAgIGludCBsaW1pdDsgICAgICAgICAgICAgICAgICAvLyDoqJjpjLLlhYjjgYzopovjgaTjgYvjgonjgarjgYTloLTlkIjjgbjjga7lgpnjgYgKCiAgICAvLyBoYXNo5YCk5Y+W5b6XCiAgICBpbmRleCA9IGhhc2hmdW5jX2goc3RyLCBoYXNoKTsKICAgIGhhc2gtPnJlZl9zZWFyY2hfY291bnRbaW5kZXhdKys7ICAgIC8vIOaOoue0ouWPgueFp+OCq+OCpuODs+OCvwogICAgLy8g6KGd56qBCiAgICBpZiAoaGFzaC0+dGFibGVbaW5kZXhdKSB7CiAgICAgICAgLy8g5ZCM5LiA5paH5a2X5YiXCiAgICAgICAgaWYgKDAgPT0gc3RyY21wX2lnbm9yZShoYXNoLT50YWJsZVtpbmRleF0sIHN0cikpIHsKICAgICAgICAgICAgaWYgKGhhc2gtPm1vZGUgPT0gQU1EX01VU0kpIHsKICAgICAgICAgICAgICAgIHJldHVybiBFQ19Ob3JtYWw7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgLy8g6KGd56qB5b6MIOWFpeOCjOWFiOaOoue0ogogICAgICAgIG5leHRfc3RlcCA9IGhhc2hmdW5jX3Aoc3RyLCBoYXNoKTsKICAgICAgICBmb3IgKGxpbWl0ID0gMDsgbGltaXQgPCBoYXNoLT50Ymxfc2l6ZTsgbGltaXQrKykgewogICAgICAgICAgICBpbmRleCA9IChpbmRleCArIG5leHRfc3RlcCkgJSBoYXNoLT50Ymxfc2l6ZTsKICAgICAgICAgICAgaGFzaC0+cmVmX3NlYXJjaF9jb3VudFtpbmRleF0rKzsgICAgLy8g5o6i57Si5Y+C54Wn44Kr44Km44Oz44K/CiAgICAgICAgICAgIGlmIChOVUxMID09IGhhc2gtPnRhYmxlW2luZGV4XSkgewogICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgaWYgKGxpbWl0ID49IGhhc2gtPnRibF9zaXplKSB7CiAgICAgICAgICAgIHJldHVybiBFQ19DYW50QWRkSGFzaDsKICAgICAgICB9CiAgICB9CiAgICAvLyDov73liqAKICAgIGlmIChOVUxMID09IChoYXNoLT50YWJsZVtpbmRleF0gPSAoY2hhciAqKSBtYWxsb2Moc2l6ZW9mKGNoYXIpICogc3RybGVuKHN0cikgKyAxKSkpIHsKICAgICAgICByZXR1cm4gRUNfTWVtQWxsb2M7CiAgICB9CiAgICBzdHJjcHkoaGFzaC0+dGFibGVbaW5kZXhdLCBzdHIpOwoKICAgIC8vIGVuZAogICAgcmV0dXJuIEVDX05vcm1hbDsKfQoKdm9pZCBoYXNoX3Nob3coSEFTSF9EQVRBICogaGFzaCwgY2hhciAqc3JjX2ZpbGVuYW1lKQp7CiAgICBpbnQgaTsKICAgIGNoYXIgYlsyNTZdOwogICAgaW50IGtldGFfY2VsbDsgICAgICAgICAgICAgIC8vIOOCu+ODq+eVquWPt+ahgeaVsAogICAgaW50IGtldGFfcmVmOyAgICAgICAgICAgICAgIC8vIOWPgueFp+WbnuaVsOahgeaVsAogICAgaW50IG07CgogICAgLy8g5qGB5pWw6KiI566XCiAgICBrZXRhX2NlbGwgPSBzcHJpbnRmKGIsICIlZCIsIGhhc2gtPnRibF9zaXplKTsKICAgIGZvciAoaSA9IG0gPSAwOyBpIDwgaGFzaC0+dGJsX3NpemU7IGkrKykgewogICAgICAgIGlmIChtID4gaGFzaC0+cmVmX3NlYXJjaF9jb3VudFtpXSkgewogICAgICAgICAgICBtID0gaGFzaC0+cmVmX3NlYXJjaF9jb3VudFtpXTsKICAgICAgICB9CiAgICB9CiAgICBrZXRhX3JlZiA9IHNwcmludGYoYiwgIiVkIiwgbSk7CgogICAgLy8g5Ye65YqbCiAgICBmcHJpbnRmKHN0ZG91dCwgIuODu+WFpeWKm+ODleOCoeOCpOODqyAgICAgOiAlc1xuIiwgc3JjX2ZpbGVuYW1lKTsKICAgIGZwcmludGYoc3Rkb3V0LCAi44O75pyA5aSn5paH5a2X5YiX6ZW3ICAgICA6ICVkXG4iLCBoYXNoLT5sZW5fbWF4KTsKICAgIGZwcmludGYoc3Rkb3V0LCAi44O75paH5a2X5YiX5pWwICAgICAgICAgOiAlZOWAi1xuIiwgaGFzaC0+ZGF0YV9uKTsKICAgIGZwcmludGYoc3Rkb3V0LCAi44O7SGFzaOODhuODvOODluODq+aVsCAgIDogJWTlgItcbiIsIGhhc2gtPnRibF9zaXplKTsKICAgIGZwcmludGYoc3Rkb3V0LCAi44O7SGFzaOi/veWKoOODouODvOODiSAgIDog5ZCM5LiA5paH5a2X5YiX44KS44CBJXNcbiIsIGdldFN0cl9BRERfTU9ERShoYXNoLT5tb2RlKSk7CiAgICBmcHJpbnRmKHN0ZG91dCwgIuODu+W9k+e1kOaenOWHuuWKm+ODouODvOODiSA6IOepuuOBruODhuODvOODluODq+imgee0oOOCkuWHuuWKmyVzXG4iLCBoYXNoLT5mbGFnX3Jlc19vdXQgPyAi44GZ44KLIiA6ICLjgZfjgarjgYQiKTsKICAgIGZvciAoaSA9IDA7IGkgPCBoYXNoLT50Ymxfc2l6ZTsgaSsrKSB7CiAgICAgICAgaWYgKGhhc2gtPmZsYWdfcmVzX291dCB8fCBoYXNoLT50YWJsZVtpXSkgewogICAgICAgICAgICBmcHJpbnRmKHN0ZG91dCwgIlslMCpkXSDlj4Lnhaflm57mlbAgPSAlMCpkLCDmoLzntI3mloflrZcgPSBbJXNdXG4iLCBrZXRhX2NlbGwsIGksIGtldGFfcmVmLCBoYXNoLT5yZWZfc2VhcmNoX2NvdW50W2ldCiAgICAgICAgICAgICAgICAgICAgLCBoYXNoLT50YWJsZVtpXSA/IGhhc2gtPnRhYmxlW2ldIDogIiIpOwogICAgICAgIH0KICAgIH0KfQoKLyoKICogICAgICBoYXNoIGZ1bmN0aW9ucwogKi8KCmludCBoYXNoZnVuY19oKGNoYXIgKnMsIEhBU0hfREFUQSAqIGhhc2gpCnsKICAgIGludCByID0gMDsKICAgIHdoaWxlICgqcykgewogICAgICAgICpzID0gdG9sb3dlcigqcyk7CiAgICAgICAgaWYgKCdhJyA8PSAqcyAmJiAqcyA8PSAneicpIHsKICAgICAgICAgICAgciA9IHIgKiAyNiArICgqcyAtICdhJyk7CiAgICAgICAgICAgIHIgJT0gaGFzaC0+dGJsX3NpemU7CiAgICAgICAgfQogICAgICAgICsrczsKICAgIH0KICAgIHJldHVybiByOwp9CgppbnQgaGFzaGZ1bmNfcChjaGFyICpzLCBIQVNIX0RBVEEgKiBoYXNoKQp7CiAgICByZXR1cm4gMTsKfQoKLy8gRW5kIG9mIGNzXzE2MV8xNjUuYwo=