// 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) {
len = pos_now - pos_prev;
if (len) {
++hash->data_n;
}
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->tbl_size; 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) && 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;
} else {
// 同一文字列
if (0 == strcmp_ignore(hash->table[index], str) && hash->mode == AMD_MUSI) {
return EC_Normal; // 追加しない
}
}
}
// 追加先をみつけられなかったら、エラー
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) {
r = r * hash->tbl_size + *s;
r %= hash->tbl_size;
++s;
}
return r;
}
int hashfunc_p(char *s, HASH_DATA * hash)
{
int r = 0;
int m = 0;
while (*s) {
r *= hash->tbl_size;
m = m * hash->tbl_size + *s;
r += m / hash->tbl_size;
m %= hash->tbl_size;
r %= hash->tbl_size;
++s;
}
return r == 0 ? 1 : r;
}
// End of cs_161_165.c
Ly8gY3NfMTYxXzE2NS5jCi8qCiAgICBDL0MrK+OBruWuv+mhjOeJh+S7mOOBkeOBvuOBmSAxNjHku6Pnm64KICAgIGh0dHA6Ly90Li4uY29udGVudC1hdmFpbGFibGUtdG8tYXV0aG9yLW9ubHkuLi5oLm5ldC90ZXN0L3JlYWQuY2dpL3RlY2gvMTM1NDA3MDI3OC8xNjUKICovCgojaW5jbHVkZSA8c3RkaW8uaD4KI2luY2x1ZGUgPHN0ZGxpYi5oPgojaW5jbHVkZSA8c3RyaW5nLmg+CiNpbmNsdWRlIDxjdHlwZS5oPgoKLyog5YWx6YCa44Ko44Op44O844Kz44O844OJICovCnR5cGVkZWYgZW51bSB7CiAgICBFQ19Ob3JtYWwsICAgICAgICAgICAgICAgICAgLy8g5q2j5bi457WC5LqGCiAgICBFQ19GaWxlT3BlbiwgICAgICAgICAgICAgICAgLy8g44OV44Kh44Kk44Or44Kq44O844OX44Oz5aSx5pWXCiAgICBFQ19NZW1BbGxvYywgICAgICAgICAgICAgICAgLy8g44Oh44Oi44Oq56K65L+d5aSx5pWXCiAgICBFQ19DYW50QWRkSGFzaCwgICAgICAgICAgICAgLy8gSGFzaOODhuODvOODluODq+OBi+OCieODh+ODvOOCv+i/veWKoOWFiOOCkuimi+OBpOOBkeOCieOCjOOBquOBi+OBo+OBnwp9IEVSUl9DT0RFOwoKY2hhciAqZ2V0U3RyX0VSUl9DT0RFKEVSUl9DT0RFIGVjKQp7CiAgICBzd2l0Y2ggKGVjKSB7CiAgICBjYXNlIEVDX05vcm1hbDoKICAgICAgICByZXR1cm4gIuato+W4uOe1guS6hiI7CiAgICBjYXNlIEVDX0ZpbGVPcGVuOgogICAgICAgIHJldHVybiAi44OV44Kh44Kk44Or44Kq44O844OX44Oz5aSx5pWXIjsKICAgIGNhc2UgRUNfTWVtQWxsb2M6CiAgICAgICAgcmV0dXJuICLjg6Hjg6Ljg6rnorrkv53lpLHmlZciOwogICAgY2FzZSBFQ19DYW50QWRkSGFzaDoKICAgICAgICByZXR1cm4gIkhhc2jjg4bjg7zjg5bjg6vjgYvjgonjg4fjg7zjgr/ov73liqDlhYjjgpLopovjgaTjgZHjgonjgozjgarjgYvjgaPjgZ8iOwogICAgfQogICAgcmV0dXJuICIiOwp9CgovKiDph43opIfmmYLjga7ov73liqDli5XkvZwgKi8KdHlwZWRlZiBlbnVtIHsKICAgIEFNRF9BREQsICAgICAgICAgICAgICAgICAgICAvLyDov73liqDjgZnjgosKICAgIEFNRF9NVVNJLCAgICAgICAgICAgICAgICAgICAvLyDov73liqDjgZfjgarjgYQKfSBBRERfTU9ERTsKCmNoYXIgKmdldFN0cl9BRERfTU9ERShBRERfTU9ERSBjb2RlKQp7CiAgICBzd2l0Y2ggKGNvZGUpIHsKICAgIGNhc2UgQU1EX0FERDoKICAgICAgICByZXR1cm4gIui/veWKoOOBmeOCiyI7CiAgICBjYXNlIEFNRF9NVVNJOgogICAgICAgIHJldHVybiAi6L+95Yqg44GX44Gq44GEIjsKICAgIH0KICAgIHJldHVybiAiIjsKfQoKLyogZGF0YSAqLwp0eXBlZGVmIHN0cnVjdCB7CiAgICBBRERfTU9ERSBtb2RlOyAgICAgICAgICAgICAgLy8gKOaJi+WLleioreWuminph43opIfmmYLjga7ov73liqDli5XkvZwKICAgIGludCBmbGFnX3Jlc19vdXQ7ICAgICAgICAgICAvLyAo5omL5YuV6Kit5a6aKee1kOaenOWHuuWKm+aZguOAgeepuuOBruODhuODvOODluODq+imgee0oOOCkuWHuuWKm+OBmeOCi+OBi+OBqeOBhuOBquOBruOBiygxIG9yIDApCiAgICBpbnQgZGF0YV9uOyAgICAgICAgICAgICAgICAgLy8g5paH5a2X5YiX5pWwCiAgICBpbnQgbGVuX21heDsgICAgICAgICAgICAgICAgLy8g5pyA5aSn5paH5a2X6ZW3CiAgICBpbnQgdGJsX3NpemU7ICAgICAgICAgICAgICAgLy8g44OP44OD44K344Ol44OG44O844OW44Or44K144Kk44K6CiAgICBjaGFyICoqdGFibGU7ICAgICAgICAgICAgICAgLy8g44OP44OD44K344Ol44OG44O844OW44OrCiAgICBpbnQgKnJlZl9zZWFyY2hfY291bnQ7ICAgICAgLy8gdGFibGVbXSDmjqLntKLlj4Lnhafjgqvjgqbjg7Pjgr8KfSBIQVNIX0RBVEE7CgovKiBwcm90b3R5cGUgKi8KZXh0ZXJuIGludCBoYXNoZnVuY19oKGNoYXIgKnMsIEhBU0hfREFUQSAqIGhhc2gpOwpleHRlcm4gaW50IGhhc2hmdW5jX3AoY2hhciAqcywgSEFTSF9EQVRBICogaGFzaCk7CmV4dGVybiBFUlJfQ09ERSBoYXNoX2NyZWF0KEhBU0hfREFUQSAqIGhhc2gsIGNoYXIgKmZpbGVuYW1lKTsKZXh0ZXJuIEVSUl9DT0RFIGhhc2hfbWFrZShIQVNIX0RBVEEgKiBoYXNoLCBjaGFyICpmaWxlbmFtZSk7CmV4dGVybiBFUlJfQ09ERSBoYXNoX2FkZChIQVNIX0RBVEEgKiBoYXNoLCBjaGFyICpzdHIpOwpleHRlcm4gdm9pZCBoYXNoX3Nob3coSEFTSF9EQVRBICogaGFzaCwgY2hhciAqc3JjX2ZpbGVuYW1lKTsKZXh0ZXJuIHZvaWQgaGFzaF9kZWxldGUoSEFTSF9EQVRBICogaGFzaCk7CmV4dGVybiBpbnQgc3RyY21wX2lnbm9yZShjaGFyICpzMSwgY2hhciAqczIpOwoKLyoKICogICAgICBtYWluCiAqLwppbnQgbWFpbihpbnQgYXJnYywgY2hhciAqYXJndltdKQp7CiAgICBpbnQgcmVzID0gKGludCkgRUNfTm9ybWFsOwogICAgSEFTSF9EQVRBIGhkOwoKICAgIC8vIOWIneacn+WMlgogICAgbWVtc2V0KCZoZCwgMHgwMCwgc2l6ZW9mKEhBU0hfREFUQSkpOwogICAgaGQubW9kZSA9IEFNRF9NVVNJOyAgICAgICAgIC8vICjmiYvli5XoqK3lrpop6YeN6KSH5pmC44Gu6L+95Yqg5YuV5L2cCiAgICBoZC5mbGFnX3Jlc19vdXQgPSAxOyAgICAgICAgLy8gKOaJi+WLleioreWuminntZDmnpzlh7rlipvmmYLjgIHnqbrjga7jg4bjg7zjg5bjg6vopoHntKDjgpLlh7rlipvjgZnjgovjgYvjganjgYbjgarjga7jgYsoMSBvciAwKQogICAgaWYgKEVDX05vcm1hbCAhPSAocmVzID0gaGFzaF9jcmVhdCgmaGQsIGFyZ3ZbMV0pKSkgewogICAgICAgIGdvdG8gRU5EX21haW47CiAgICB9CiAgICAvLyDjg4/jg4Pjgrfjg6XkvZzmiJAKICAgIGlmIChFQ19Ob3JtYWwgIT0gKHJlcyA9IGhhc2hfbWFrZSgmaGQsIGFyZ3ZbMV0pKSkgewogICAgICAgIGdvdG8gRU5EX21haW47CiAgICB9CiAgICAvLyDntZDmnpzooajnpLoKICAgIGhhc2hfc2hvdygmaGQsIGFyZ3ZbMV0pOwogICAgLy8g57WC5LqGCiAgICByZXMgPSAoaW50KSBFQ19Ob3JtYWw7CiAgRU5EX21haW46CiAgICBoYXNoX2RlbGV0ZSgmaGQpOwogICAgaWYgKHJlcyAhPSBFQ19Ob3JtYWwpIHsKICAgICAgICBmcHJpbnRmKHN0ZGVyciwgIkVyciA6JXNcbiIsIGdldFN0cl9FUlJfQ09ERShyZXMpKTsKICAgIH0KICAgIHJldHVybiByZXM7Cn0KCi8qIOWkp+Wwj+aWh+Wtl+WMuuWIpeOBquOBl+aWh+Wtl+WIl+avlOi8gyAo6LKgOnMxPHMyLCDmraM6czE+czIsIDA6czE9PXMyKQogKiAg4oC7IHMxPSIzMjEiLCBzMj0iMzIxMDAwIuOBruOBqOOBjeOBr+OAgXMxIDwgczIKICovCmludCBzdHJjbXBfaWdub3JlKGNoYXIgKnMxLCBjaGFyICpzMikKewogICAgaW50IGNtcDsKICAgIHdoaWxlICgxKSB7CiAgICAgICAgY21wID0gdG9sb3dlcigoaW50KSAqczEpIC0gdG9sb3dlcigoaW50KSAqczIpOwogICAgICAgIGlmIChjbXApIHsKICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgfQogICAgICAgIGlmICgqczEgPT0gJ1wwJyAmJiAqczIgPT0gJ1wwJykgewogICAgICAgICAgICBicmVhazsKICAgICAgICB9CiAgICAgICAgczErKzsKICAgICAgICBzMisrOwogICAgfQoKICAgIHJldHVybiBjbXA7Cn0KCi8qCiAqICAgICAgSEFTSF9EQVRBIG9wZXJhdGlvbgogKi8KLy8g44OV44Kh44Kk44OrIGZpbGVuYW1lIOOCkuino+aekOOBl+OBpuOAgUhBU0hfREFUQeOCkuWIneacn+WMlgoKRVJSX0NPREUgaGFzaF9jcmVhdChIQVNIX0RBVEEgKiBoYXNoLCBjaGFyICpmaWxlbmFtZSkKewogICAgRklMRSAqZnA7CiAgICBpbnQgbGVuLCBwb3Nfbm93LCBwb3NfcHJldjsKICAgIGludCBjOwoKICAgIC8vIOWNmOiqnuaVsOOCq+OCpuODs+ODiAogICAgaWYgKE5VTEwgPT0gKGZwID0gZm9wZW4oZmlsZW5hbWUsICJyIikpKSB7CiAgICAgICAgcmV0dXJuIEVDX0ZpbGVPcGVuOwogICAgfQogICAgcG9zX25vdyA9IHBvc19wcmV2ID0gMDsKICAgIHdoaWxlIChjID0gZmdldGMoZnApKSB7CiAgICAgICAgaWYgKGMgPT0gJyAnIHx8IGMgPT0gJ1x0JyB8fCBjID09ICdccicgfHwgYyA9PSAnXG4nIHx8IGMgPT0gRU9GKSB7CiAgICAgICAgICAgIGxlbiA9IHBvc19ub3cgLSBwb3NfcHJldjsKICAgICAgICAgICAgaWYgKGxlbikgewogICAgICAgICAgICAgICAgKytoYXNoLT5kYXRhX247CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKGhhc2gtPmxlbl9tYXggPCBsZW4pIHsKICAgICAgICAgICAgICAgIGhhc2gtPmxlbl9tYXggPSBsZW47CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcG9zX3ByZXYgPSBwb3Nfbm93ICsgMTsKICAgICAgICAgICAgaWYgKGMgPT0gRU9GKSB7CiAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBwb3Nfbm93Kys7CiAgICB9CiAgICBmY2xvc2UoZnApOwogICAgLy8gSGFzaFRhYmxl44K144Kk44K65rG644KBICjljZjoqp7mlbDjga4y5YCN5Lul5LiKIOOBi+OBpCDntKDmlbApCiAgICBpbnQgbjsKICAgIGhhc2gtPnRibF9zaXplID0gaGFzaC0+ZGF0YV9uICogMjsKICAgIHdoaWxlICgxKSB7CiAgICAgICAgZm9yIChuID0gMjsgKG4gKiBuIDwgaGFzaC0+dGJsX3NpemUpICYmIChoYXNoLT50Ymxfc2l6ZSAlIG4pOyArK24pOwogICAgICAgIGlmIChoYXNoLT50Ymxfc2l6ZSAlIG4pIHsgICAvKiDntKDmlbAgKi8KICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgfQogICAgICAgICsraGFzaC0+dGJsX3NpemU7CiAgICB9CiAgICAvLyDnorrkv50KICAgIGlmIChOVUxMID09IChoYXNoLT50YWJsZSA9IChjaGFyICoqKSBtYWxsb2Moc2l6ZW9mKGNoYXIgKikgKiBoYXNoLT50Ymxfc2l6ZSkpKSB7CiAgICAgICAgcmV0dXJuIEVDX01lbUFsbG9jOwogICAgfQogICAgbWVtc2V0KGhhc2gtPnRhYmxlLCAweDAwLCBzaXplb2YoY2hhciAqKSAqIGhhc2gtPnRibF9zaXplKTsKICAgIGlmIChOVUxMID09IChoYXNoLT5yZWZfc2VhcmNoX2NvdW50ID0gKGludCAqKSBtYWxsb2Moc2l6ZW9mKGludCkgKiBoYXNoLT50Ymxfc2l6ZSkpKSB7CiAgICAgICAgcmV0dXJuIEVDX01lbUFsbG9jOwogICAgfQogICAgbWVtc2V0KGhhc2gtPnJlZl9zZWFyY2hfY291bnQsIDB4MDAsIHNpemVvZihpbnQpICogaGFzaC0+dGJsX3NpemUpOwoKICAgIHJldHVybiBFQ19Ob3JtYWw7Cn0KCnZvaWQgaGFzaF9kZWxldGUoSEFTSF9EQVRBICogaGFzaCkKewogICAgaW50IGk7CiAgICBpZiAoaGFzaCkgewogICAgICAgIGlmIChoYXNoLT50YWJsZSkgewogICAgICAgICAgICBmb3IgKGkgPSAwOyBpIDwgaGFzaC0+dGJsX3NpemU7IGkrKykgewogICAgICAgICAgICAgICAgaWYgKGhhc2gtPnRhYmxlW2ldKSB7CiAgICAgICAgICAgICAgICAgICAgZnJlZShoYXNoLT50YWJsZVtpXSk7CiAgICAgICAgICAgICAgICAgICAgaGFzaC0+dGFibGVbaV0gPSBOVUxMOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIGZyZWUoaGFzaC0+dGFibGUpOwogICAgICAgICAgICBoYXNoLT50YWJsZSA9IE5VTEw7CiAgICAgICAgfQogICAgICAgIGlmIChoYXNoLT5yZWZfc2VhcmNoX2NvdW50KSB7CiAgICAgICAgICAgIGZyZWUoaGFzaC0+cmVmX3NlYXJjaF9jb3VudCk7CiAgICAgICAgICAgIGhhc2gtPnJlZl9zZWFyY2hfY291bnQgPSBOVUxMOwogICAgICAgIH0KICAgICAgICBtZW1zZXQoaGFzaCwgMHgwMCwgc2l6ZW9mKEhBU0hfREFUQSkpOwogICAgfQp9CgpFUlJfQ09ERSBoYXNoX21ha2UoSEFTSF9EQVRBICogaGFzaCwgY2hhciAqZmlsZW5hbWUpCnsKICAgIEZJTEUgKmZwID0gTlVMTDsKICAgIGNoYXIgKmJ1ZiA9IE5VTEwsICpwOwogICAgaW50IGM7CiAgICBFUlJfQ09ERSByZXMgPSBFQ19Ob3JtYWw7CgogICAgLy8g44OQ44OD44OV44Kh56K65L+dCiAgICBpZiAoTlVMTCA9PSAoYnVmID0gKGNoYXIgKikgbWFsbG9jKHNpemVvZihjaGFyKSAqIChoYXNoLT5sZW5fbWF4ICsgMikpKSkgewogICAgICAgIHJlcyA9IEVDX01lbUFsbG9jOwogICAgICAgIGdvdG8gRU5EX2hhc2hfbWFrZTsKICAgIH0KICAgIC8vIOiqreOBv+i+vOOBvyDvvIYg44OP44OD44K344Ol44Gr6L+95YqgCiAgICBmcCA9IGZvcGVuKGZpbGVuYW1lLCAiciIpOwogICAgcCA9ICZidWZbMF07CiAgICB3aGlsZSAoYyA9IGZnZXRjKGZwKSkgewogICAgICAgIGlmIChjID09ICcgJyB8fCBjID09ICdcdCcgfHwgYyA9PSAnXHInIHx8IGMgPT0gJ1xuJyB8fCBjID09IEVPRikgewogICAgICAgICAgICAqcCA9ICdcMCc7CiAgICAgICAgICAgIHAgPSAmYnVmWzBdOwogICAgICAgICAgICBpZiAoc3RybGVuKGJ1ZikpIHsKICAgICAgICAgICAgICAgIGlmIChFQ19Ob3JtYWwgIT0gKHJlcyA9IGhhc2hfYWRkKGhhc2gsICZidWZbMF0pKSkgewogICAgICAgICAgICAgICAgICAgIGdvdG8gRU5EX2hhc2hfbWFrZTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAoYyA9PSBFT0YpIHsKICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICB9CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgKnArKyA9IChjaGFyKSBjOwogICAgICAgIH0KICAgIH0KICAgIC8vIOe1guS6hgogICAgcmVzID0gRUNfTm9ybWFsOwogIEVORF9oYXNoX21ha2U6CiAgICBpZiAoYnVmKSB7CiAgICAgICAgZnJlZShidWYpOwogICAgICAgIGJ1ZiA9IE5VTEw7CiAgICB9CiAgICBpZiAoZnApIHsKICAgICAgICBmY2xvc2UoZnApOwogICAgICAgIGZwID0gTlVMTDsKICAgIH0KCiAgICByZXR1cm4gcmVzOwp9CgpFUlJfQ09ERSBoYXNoX2FkZChIQVNIX0RBVEEgKiBoYXNoLCBjaGFyICpzdHIpCnsKICAgIGludCBpbmRleDsgICAgICAgICAgICAgICAgICAvLyDov73liqDlhYgKICAgIGludCBuZXh0X3N0ZXA7ICAgICAgICAgICAgICAvLyDooZ3nqoHmmYLov73liqDlhYjmjqLntKLjgrnjg4bjg4Pjg5cKICAgIGludCBsaW1pdDsgICAgICAgICAgICAgICAgICAvLyDov73liqDlhYjjgYzopovjgaTjgYvjgonjgarjgYTloLTlkIjjgbjjga7lgpnjgYgKCiAgICAvLyBoYXNo5YCk5Y+W5b6XCiAgICBpbmRleCA9IGhhc2hmdW5jX2goc3RyLCBoYXNoKTsKICAgIGhhc2gtPnJlZl9zZWFyY2hfY291bnRbaW5kZXhdKys7ICAgIC8vIOaOoue0ouWPgueFp+OCq+OCpuODs+OCvwogICAgLy8g6KGd56qBCiAgICBpZiAoaGFzaC0+dGFibGVbaW5kZXhdKSB7CiAgICAgICAgLy8g5ZCM5LiA5paH5a2X5YiXCiAgICAgICAgaWYgKDAgPT0gc3RyY21wX2lnbm9yZShoYXNoLT50YWJsZVtpbmRleF0sIHN0cikgJiYgaGFzaC0+bW9kZSA9PSBBTURfTVVTSSkgewogICAgICAgICAgICByZXR1cm4gRUNfTm9ybWFsOyAgIC8vIOi/veWKoOOBl+OBquOBhAogICAgICAgIH0KICAgICAgICAvLyDooZ3nqoHmmYLjga7ov73liqDlhYjmjqLntKIKICAgICAgICBuZXh0X3N0ZXAgPSBoYXNoZnVuY19wKHN0ciwgaGFzaCk7CiAgICAgICAgZm9yIChsaW1pdCA9IDA7IGxpbWl0IDwgaGFzaC0+dGJsX3NpemU7IGxpbWl0KyspIHsKICAgICAgICAgICAgaW5kZXggPSAoaW5kZXggKyBuZXh0X3N0ZXApICUgaGFzaC0+dGJsX3NpemU7CiAgICAgICAgICAgIGhhc2gtPnJlZl9zZWFyY2hfY291bnRbaW5kZXhdKys7ICAgIC8vIOaOoue0ouWPgueFp+OCq+OCpuODs+OCvwogICAgICAgICAgICBpZiAoTlVMTCA9PSBoYXNoLT50YWJsZVtpbmRleF0pIHsKICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgLy8g5ZCM5LiA5paH5a2X5YiXCiAgICAgICAgICAgICAgICBpZiAoMCA9PSBzdHJjbXBfaWdub3JlKGhhc2gtPnRhYmxlW2luZGV4XSwgc3RyKSAmJiBoYXNoLT5tb2RlID09IEFNRF9NVVNJKSB7CiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIEVDX05vcm1hbDsgICAvLyDov73liqDjgZfjgarjgYQKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICAvLyDov73liqDlhYjjgpLjgb/jgaTjgZHjgonjgozjgarjgYvjgaPjgZ/jgonjgIHjgqjjg6njg7wKICAgICAgICBpZiAobGltaXQgPj0gaGFzaC0+dGJsX3NpemUpIHsKICAgICAgICAgICAgcmV0dXJuIEVDX0NhbnRBZGRIYXNoOwogICAgICAgIH0KICAgIH0KICAgIC8vIOi/veWKoAogICAgaWYgKE5VTEwgPT0gKGhhc2gtPnRhYmxlW2luZGV4XSA9IChjaGFyICopIG1hbGxvYyhzaXplb2YoY2hhcikgKiBzdHJsZW4oc3RyKSArIDEpKSkgewogICAgICAgIHJldHVybiBFQ19NZW1BbGxvYzsKICAgIH0KICAgIHN0cmNweShoYXNoLT50YWJsZVtpbmRleF0sIHN0cik7CgogICAgLy8gZW5kCiAgICByZXR1cm4gRUNfTm9ybWFsOwp9Cgp2b2lkIGhhc2hfc2hvdyhIQVNIX0RBVEEgKiBoYXNoLCBjaGFyICpzcmNfZmlsZW5hbWUpCnsKICAgIGludCBpOwogICAgY2hhciBiWzI1Nl07CiAgICBpbnQga2V0YV9jZWxsOyAgICAgICAgICAgICAgLy8g44K744Or55Wq5Y+35qGB5pWwCiAgICBpbnQga2V0YV9yZWY7ICAgICAgICAgICAgICAgLy8g5Y+C54Wn5Zue5pWw5qGB5pWwCiAgICBpbnQgbTsKCiAgICAvLyDmoYHmlbDoqIjnrpcKICAgIGtldGFfY2VsbCA9IHNwcmludGYoYiwgIiVkIiwgaGFzaC0+dGJsX3NpemUpOwogICAgZm9yIChpID0gbSA9IDA7IGkgPCBoYXNoLT50Ymxfc2l6ZTsgaSsrKSB7CiAgICAgICAgaWYgKG0gPCBoYXNoLT5yZWZfc2VhcmNoX2NvdW50W2ldKSB7CiAgICAgICAgICAgIG0gPSBoYXNoLT5yZWZfc2VhcmNoX2NvdW50W2ldOwogICAgICAgIH0KICAgIH0KICAgIGtldGFfcmVmID0gc3ByaW50ZihiLCAiJWQiLCBtKTsKCiAgICAvLyDlh7rlipsKICAgIGZwcmludGYoc3Rkb3V0LCAi44O75YWl5Yqb44OV44Kh44Kk44OrICAgICA6ICVzXG4iLCBzcmNfZmlsZW5hbWUpOwogICAgZnByaW50ZihzdGRvdXQsICLjg7vmnIDlpKfmloflrZfplbcgICAgICAgOiAlZFxuIiwgaGFzaC0+bGVuX21heCk7CiAgICBmcHJpbnRmKHN0ZG91dCwgIuODu+aWh+Wtl+WIl+aVsCAgICAgICAgIDogJWTlgItcbiIsIGhhc2gtPmRhdGFfbik7CiAgICBmcHJpbnRmKHN0ZG91dCwgIuODu0hhc2jjg4bjg7zjg5bjg6vmlbAgICA6ICVk5YCLXG4iLCBoYXNoLT50Ymxfc2l6ZSk7CiAgICBmcHJpbnRmKHN0ZG91dCwgIuODu0hhc2jov73liqDjg6Ljg7zjg4kgICA6IOWQjOS4gOaWh+Wtl+WIl+OCkuOAgSVzXG4iLCBnZXRTdHJfQUREX01PREUoaGFzaC0+bW9kZSkpOwogICAgZnByaW50ZihzdGRvdXQsICLjg7vlvZPntZDmnpzlh7rlipvjg6Ljg7zjg4kgOiDnqbrjga7jg4bjg7zjg5bjg6vopoHntKDjgpLlh7rlipslc1xuIiwgaGFzaC0+ZmxhZ19yZXNfb3V0ID8gIuOBmeOCiyIgOiAi44GX44Gq44GEIik7CiAgICBmb3IgKGkgPSAwOyBpIDwgaGFzaC0+dGJsX3NpemU7IGkrKykgewogICAgICAgIGlmIChoYXNoLT5mbGFnX3Jlc19vdXQgfHwgaGFzaC0+dGFibGVbaV0pIHsKICAgICAgICAgICAgZnByaW50ZihzdGRvdXQsICJbJTAqZF0g5Y+C54Wn5Zue5pWwID0gJTAqZCwg5qC857SN5paH5a2XID0gWyVzXVxuIiwga2V0YV9jZWxsLCBpLCBrZXRhX3JlZiwgaGFzaC0+cmVmX3NlYXJjaF9jb3VudFtpXQogICAgICAgICAgICAgICAgICAgICwgaGFzaC0+dGFibGVbaV0gPyBoYXNoLT50YWJsZVtpXSA6ICIiKTsKICAgICAgICB9CiAgICB9Cn0KCi8qCiAqICAgICAgaGFzaCBmdW5jdGlvbnMKICovCgppbnQgaGFzaGZ1bmNfaChjaGFyICpzLCBIQVNIX0RBVEEgKiBoYXNoKQp7CiAgICBpbnQgciA9IDA7CiAgICB3aGlsZSAoKnMpIHsKICAgICAgICAqcyA9IHRvbG93ZXIoKnMpOwogICAgICAgIHIgPSByICogaGFzaC0+dGJsX3NpemUgKyAqczsKICAgICAgICByICU9IGhhc2gtPnRibF9zaXplOwogICAgICAgICsrczsKICAgIH0KICAgIHJldHVybiByOwp9CgppbnQgaGFzaGZ1bmNfcChjaGFyICpzLCBIQVNIX0RBVEEgKiBoYXNoKQp7CiAgICBpbnQgciA9IDA7CiAgICBpbnQgbSA9IDA7CgogICAgd2hpbGUgKCpzKSB7CiAgICAgICAgKnMgPSB0b2xvd2VyKCpzKTsKICAgICAgICByICo9IGhhc2gtPnRibF9zaXplOwogICAgICAgIG0gPSBtICogaGFzaC0+dGJsX3NpemUgKyAqczsKICAgICAgICByICs9IG0gLyBoYXNoLT50Ymxfc2l6ZTsKICAgICAgICBtICU9IGhhc2gtPnRibF9zaXplOwogICAgICAgIHIgJT0gaGFzaC0+dGJsX3NpemU7CiAgICAgICAgKytzOwogICAgfQogICAgcmV0dXJuIHIgPT0gMCA/IDEgOiByOwp9CgovLyBFbmQgb2YgY3NfMTYxXzE2NS5jCg==