// 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->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+ODiAogICAgaWYgKE5VTEwgPT0gKGZwID0gZm9wZW4oZmlsZW5hbWUsICJyIikpKSB7CiAgICAgICAgcmV0dXJuIEVDX0ZpbGVPcGVuOwogICAgfQogICAgcG9zX25vdyA9IHBvc19wcmV2ID0gMDsKICAgIHdoaWxlIChjID0gZmdldGMoZnApKSB7CiAgICAgICAgaWYgKGMgPT0gJyAnIHx8IGMgPT0gJ1x0JyB8fCBjID09ICdccicgfHwgYyA9PSAnXG4nIHx8IGMgPT0gRU9GKSB7CiAgICAgICAgICAgICsraGFzaC0+ZGF0YV9uOwogICAgICAgICAgICBsZW4gPSBwb3Nfbm93IC0gcG9zX3ByZXY7CiAgICAgICAgICAgIGlmIChoYXNoLT5sZW5fbWF4IDwgbGVuKSB7CiAgICAgICAgICAgICAgICBoYXNoLT5sZW5fbWF4ID0gbGVuOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHBvc19wcmV2ID0gcG9zX25vdyArIDE7CiAgICAgICAgICAgIGlmIChjID09IEVPRikgewogICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgcG9zX25vdysrOwogICAgfQogICAgZmNsb3NlKGZwKTsKICAgIC8vIEhhc2hUYWJsZeOCteOCpOOCuuaxuuOCgSAo5Y2Y6Kqe5pWw44GuMuWAjeS7peS4iiDjgYvjgaQg57Sg5pWwKQogICAgaW50IG47CiAgICBoYXNoLT50Ymxfc2l6ZSA9IGhhc2gtPmRhdGFfbiAqIDI7CiAgICB3aGlsZSAoMSkgewogICAgICAgIGZvciAobiA9IDI7IChuICogbiA8IGhhc2gtPnRibF9zaXplKSAmJiAoaGFzaC0+dGJsX3NpemUgJSBuKTsgKytuKTsKICAgICAgICBpZiAoaGFzaC0+dGJsX3NpemUgJSBuKSB7ICAgLyog57Sg5pWwICovCiAgICAgICAgICAgIGJyZWFrOwogICAgICAgIH0KICAgICAgICArK2hhc2gtPnRibF9zaXplOwogICAgfQogICAgLy8g56K65L+dCiAgICBpZiAoTlVMTCA9PSAoaGFzaC0+dGFibGUgPSAoY2hhciAqKikgbWFsbG9jKHNpemVvZihjaGFyICopICogaGFzaC0+dGJsX3NpemUpKSkgewogICAgICAgIHJldHVybiBFQ19NZW1BbGxvYzsKICAgIH0KICAgIG1lbXNldChoYXNoLT50YWJsZSwgMHgwMCwgc2l6ZW9mKGNoYXIgKikgKiBoYXNoLT50Ymxfc2l6ZSk7CiAgICBpZiAoTlVMTCA9PSAoaGFzaC0+cmVmX3NlYXJjaF9jb3VudCA9IChpbnQgKikgbWFsbG9jKHNpemVvZihpbnQpICogaGFzaC0+dGJsX3NpemUpKSkgewogICAgICAgIHJldHVybiBFQ19NZW1BbGxvYzsKICAgIH0KICAgIG1lbXNldChoYXNoLT5yZWZfc2VhcmNoX2NvdW50LCAweDAwLCBzaXplb2YoaW50KSAqIGhhc2gtPnRibF9zaXplKTsKCiAgICByZXR1cm4gRUNfTm9ybWFsOwp9Cgp2b2lkIGhhc2hfZGVsZXRlKEhBU0hfREFUQSAqIGhhc2gpCnsKICAgIGludCBpOwogICAgaWYgKGhhc2gpIHsKICAgICAgICBpZiAoaGFzaC0+dGFibGUpIHsKICAgICAgICAgICAgZm9yIChpID0gMDsgaSA8IGhhc2gtPnRibF9zaXplOyBpKyspIHsKICAgICAgICAgICAgICAgIGlmIChoYXNoLT50YWJsZVtpXSkgewogICAgICAgICAgICAgICAgICAgIGZyZWUoaGFzaC0+dGFibGVbaV0pOwogICAgICAgICAgICAgICAgICAgIGhhc2gtPnRhYmxlW2ldID0gTlVMTDsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICBmcmVlKGhhc2gtPnRhYmxlKTsKICAgICAgICAgICAgaGFzaC0+dGFibGUgPSBOVUxMOwogICAgICAgIH0KICAgICAgICBpZiAoaGFzaC0+cmVmX3NlYXJjaF9jb3VudCkgewogICAgICAgICAgICBmcmVlKGhhc2gtPnJlZl9zZWFyY2hfY291bnQpOwogICAgICAgICAgICBoYXNoLT5yZWZfc2VhcmNoX2NvdW50ID0gTlVMTDsKICAgICAgICB9CiAgICAgICAgbWVtc2V0KGhhc2gsIDB4MDAsIHNpemVvZihIQVNIX0RBVEEpKTsKICAgIH0KfQoKRVJSX0NPREUgaGFzaF9tYWtlKEhBU0hfREFUQSAqIGhhc2gsIGNoYXIgKmZpbGVuYW1lKQp7CiAgICBGSUxFICpmcCA9IE5VTEw7CiAgICBjaGFyICpidWYgPSBOVUxMLCAqcDsKICAgIGludCBjOwogICAgRVJSX0NPREUgcmVzID0gRUNfTm9ybWFsOwoKICAgIC8vIOODkOODg+ODleOCoeeiuuS/nQogICAgaWYgKE5VTEwgPT0gKGJ1ZiA9IChjaGFyICopIG1hbGxvYyhzaXplb2YoY2hhcikgKiAoaGFzaC0+bGVuX21heCArIDIpKSkpIHsKICAgICAgICByZXMgPSBFQ19NZW1BbGxvYzsKICAgICAgICBnb3RvIEVORF9oYXNoX21ha2U7CiAgICB9CiAgICAvLyDoqq3jgb/ovrzjgb8g77yGIOODj+ODg+OCt+ODpeOBq+i/veWKoAogICAgZnAgPSBmb3BlbihmaWxlbmFtZSwgInIiKTsKICAgIHAgPSAmYnVmWzBdOwogICAgd2hpbGUgKGMgPSBmZ2V0YyhmcCkpIHsKICAgICAgICBpZiAoYyA9PSAnICcgfHwgYyA9PSAnXHQnIHx8IGMgPT0gJ1xyJyB8fCBjID09ICdcbicgfHwgYyA9PSBFT0YpIHsKICAgICAgICAgICAgKnAgPSAnXDAnOwogICAgICAgICAgICBwID0gJmJ1ZlswXTsKICAgICAgICAgICAgaWYgKHN0cmxlbihidWYpKSB7CiAgICAgICAgICAgICAgICBpZiAoRUNfTm9ybWFsICE9IChyZXMgPSBoYXNoX2FkZChoYXNoLCAmYnVmWzBdKSkpIHsKICAgICAgICAgICAgICAgICAgICBnb3RvIEVORF9oYXNoX21ha2U7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKGMgPT0gRU9GKSB7CiAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgfQogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICpwKysgPSAoY2hhcikgYzsKICAgICAgICB9CiAgICB9CiAgICAvLyDntYLkuoYKICAgIHJlcyA9IEVDX05vcm1hbDsKICBFTkRfaGFzaF9tYWtlOgogICAgaWYgKGJ1ZikgewogICAgICAgIGZyZWUoYnVmKTsKICAgICAgICBidWYgPSBOVUxMOwogICAgfQogICAgaWYgKGZwKSB7CiAgICAgICAgZmNsb3NlKGZwKTsKICAgICAgICBmcCA9IE5VTEw7CiAgICB9CgogICAgcmV0dXJuIHJlczsKfQoKRVJSX0NPREUgaGFzaF9hZGQoSEFTSF9EQVRBICogaGFzaCwgY2hhciAqc3RyKQp7CiAgICBpbnQgaW5kZXg7ICAgICAgICAgICAgICAgICAgLy8g6L+95Yqg5YWICiAgICBpbnQgbmV4dF9zdGVwOyAgICAgICAgICAgICAgLy8g6KGd56qB5pmC6L+95Yqg5YWI5o6i57Si44K544OG44OD44OXCiAgICBpbnQgbGltaXQ7ICAgICAgICAgICAgICAgICAgLy8g6L+95Yqg5YWI44GM6KaL44Gk44GL44KJ44Gq44GE5aC05ZCI44G444Gu5YKZ44GICgogICAgLy8gaGFzaOWApOWPluW+lwogICAgaW5kZXggPSBoYXNoZnVuY19oKHN0ciwgaGFzaCk7CiAgICBoYXNoLT5yZWZfc2VhcmNoX2NvdW50W2luZGV4XSsrOyAgICAvLyDmjqLntKLlj4Lnhafjgqvjgqbjg7Pjgr8KICAgIC8vIOihneeqgQogICAgaWYgKGhhc2gtPnRhYmxlW2luZGV4XSkgewogICAgICAgIC8vIOWQjOS4gOaWh+Wtl+WIlwogICAgICAgIGlmICgwID09IHN0cmNtcF9pZ25vcmUoaGFzaC0+dGFibGVbaW5kZXhdLCBzdHIpICYmIGhhc2gtPm1vZGUgPT0gQU1EX01VU0kpIHsKICAgICAgICAgICAgcmV0dXJuIEVDX05vcm1hbDsgICAvLyDov73liqDjgZfjgarjgYQKICAgICAgICB9CiAgICAgICAgLy8g6KGd56qB5pmC44Gu6L+95Yqg5YWI5o6i57SiCiAgICAgICAgbmV4dF9zdGVwID0gaGFzaGZ1bmNfcChzdHIsIGhhc2gpOwogICAgICAgIGZvciAobGltaXQgPSAwOyBsaW1pdCA8IGhhc2gtPnRibF9zaXplOyBsaW1pdCsrKSB7CiAgICAgICAgICAgIGluZGV4ID0gKGluZGV4ICsgbmV4dF9zdGVwKSAlIGhhc2gtPnRibF9zaXplOwogICAgICAgICAgICBoYXNoLT5yZWZfc2VhcmNoX2NvdW50W2luZGV4XSsrOyAgICAvLyDmjqLntKLlj4Lnhafjgqvjgqbjg7Pjgr8KICAgICAgICAgICAgaWYgKE5VTEwgPT0gaGFzaC0+dGFibGVbaW5kZXhdKSB7CiAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgIC8vIOWQjOS4gOaWh+Wtl+WIlwogICAgICAgICAgICAgICAgaWYgKDAgPT0gc3RyY21wX2lnbm9yZShoYXNoLT50YWJsZVtpbmRleF0sIHN0cikgJiYgaGFzaC0+bW9kZSA9PSBBTURfTVVTSSkgewogICAgICAgICAgICAgICAgICAgIHJldHVybiBFQ19Ob3JtYWw7ICAgLy8g6L+95Yqg44GX44Gq44GECiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgLy8g6L+95Yqg5YWI44KS44G/44Gk44GR44KJ44KM44Gq44GL44Gj44Gf44KJ44CB44Ko44Op44O8CiAgICAgICAgaWYgKGxpbWl0ID49IGhhc2gtPnRibF9zaXplKSB7CiAgICAgICAgICAgIHJldHVybiBFQ19DYW50QWRkSGFzaDsKICAgICAgICB9CiAgICB9CiAgICAvLyDov73liqAKICAgIGlmIChOVUxMID09IChoYXNoLT50YWJsZVtpbmRleF0gPSAoY2hhciAqKSBtYWxsb2Moc2l6ZW9mKGNoYXIpICogc3RybGVuKHN0cikgKyAxKSkpIHsKICAgICAgICByZXR1cm4gRUNfTWVtQWxsb2M7CiAgICB9CiAgICBzdHJjcHkoaGFzaC0+dGFibGVbaW5kZXhdLCBzdHIpOwoKICAgIC8vIGVuZAogICAgcmV0dXJuIEVDX05vcm1hbDsKfQoKdm9pZCBoYXNoX3Nob3coSEFTSF9EQVRBICogaGFzaCwgY2hhciAqc3JjX2ZpbGVuYW1lKQp7CiAgICBpbnQgaTsKICAgIGNoYXIgYlsyNTZdOwogICAgaW50IGtldGFfY2VsbDsgICAgICAgICAgICAgIC8vIOOCu+ODq+eVquWPt+ahgeaVsAogICAgaW50IGtldGFfcmVmOyAgICAgICAgICAgICAgIC8vIOWPgueFp+WbnuaVsOahgeaVsAogICAgaW50IG07CgogICAgLy8g5qGB5pWw6KiI566XCiAgICBrZXRhX2NlbGwgPSBzcHJpbnRmKGIsICIlZCIsIGhhc2gtPnRibF9zaXplKTsKICAgIGZvciAoaSA9IG0gPSAwOyBpIDwgaGFzaC0+dGJsX3NpemU7IGkrKykgewogICAgICAgIGlmIChtIDwgaGFzaC0+cmVmX3NlYXJjaF9jb3VudFtpXSkgewogICAgICAgICAgICBtID0gaGFzaC0+cmVmX3NlYXJjaF9jb3VudFtpXTsKICAgICAgICB9CiAgICB9CiAgICBrZXRhX3JlZiA9IHNwcmludGYoYiwgIiVkIiwgbSk7CgogICAgLy8g5Ye65YqbCiAgICBmcHJpbnRmKHN0ZG91dCwgIuODu+WFpeWKm+ODleOCoeOCpOODqyAgICAgOiAlc1xuIiwgc3JjX2ZpbGVuYW1lKTsKICAgIGZwcmludGYoc3Rkb3V0LCAi44O75pyA5aSn5paH5a2X6ZW3ICAgICAgIDogJWRcbiIsIGhhc2gtPmxlbl9tYXgpOwogICAgZnByaW50ZihzdGRvdXQsICLjg7vmloflrZfliJfmlbAgICAgICAgICA6ICVk5YCLXG4iLCBoYXNoLT5kYXRhX24pOwogICAgZnByaW50ZihzdGRvdXQsICLjg7tIYXNo44OG44O844OW44Or5pWwICAgOiAlZOWAi1xuIiwgaGFzaC0+dGJsX3NpemUpOwogICAgZnByaW50ZihzdGRvdXQsICLjg7tIYXNo6L+95Yqg44Oi44O844OJICAgOiDlkIzkuIDmloflrZfliJfjgpLjgIElc1xuIiwgZ2V0U3RyX0FERF9NT0RFKGhhc2gtPm1vZGUpKTsKICAgIGZwcmludGYoc3Rkb3V0LCAi44O75b2T57WQ5p6c5Ye65Yqb44Oi44O844OJIDog56m644Gu44OG44O844OW44Or6KaB57Sg44KS5Ye65YqbJXNcbiIsIGhhc2gtPmZsYWdfcmVzX291dCA/ICLjgZnjgosiIDogIuOBl+OBquOBhCIpOwogICAgZm9yIChpID0gMDsgaSA8IGhhc2gtPnRibF9zaXplOyBpKyspIHsKICAgICAgICBpZiAoaGFzaC0+ZmxhZ19yZXNfb3V0IHx8IGhhc2gtPnRhYmxlW2ldKSB7CiAgICAgICAgICAgIGZwcmludGYoc3Rkb3V0LCAiWyUwKmRdIOWPgueFp+WbnuaVsCA9ICUwKmQsIOagvOe0jeaWh+WtlyA9IFslc11cbiIsIGtldGFfY2VsbCwgaSwga2V0YV9yZWYsIGhhc2gtPnJlZl9zZWFyY2hfY291bnRbaV0KICAgICAgICAgICAgICAgICAgICAsIGhhc2gtPnRhYmxlW2ldID8gaGFzaC0+dGFibGVbaV0gOiAiIik7CiAgICAgICAgfQogICAgfQp9CgovKgogKiAgICAgIGhhc2ggZnVuY3Rpb25zCiAqLwoKaW50IGhhc2hmdW5jX2goY2hhciAqcywgSEFTSF9EQVRBICogaGFzaCkKewogICAgaW50IHIgPSAwOwogICAgd2hpbGUgKCpzKSB7CiAgICAgICAgKnMgPSB0b2xvd2VyKCpzKTsKICAgICAgICByID0gciAqIGhhc2gtPnRibF9zaXplICsgKnM7CiAgICAgICAgciAlPSBoYXNoLT50Ymxfc2l6ZTsKICAgICAgICArK3M7CiAgICB9CiAgICByZXR1cm4gcjsKfQoKaW50IGhhc2hmdW5jX3AoY2hhciAqcywgSEFTSF9EQVRBICogaGFzaCkKewogICAgaW50IHIgPSAwOwogICAgaW50IG0gPSAwOwoKICAgIHdoaWxlICgqcykgewogICAgICAgICpzID0gdG9sb3dlcigqcyk7CiAgICAgICAgciAqPSBoYXNoLT50Ymxfc2l6ZTsKICAgICAgICBtID0gbSAqIGhhc2gtPnRibF9zaXplICsgKnM7CiAgICAgICAgciArPSBtIC8gaGFzaC0+dGJsX3NpemU7CiAgICAgICAgbSAlPSBoYXNoLT50Ymxfc2l6ZTsKICAgICAgICByICU9IGhhc2gtPnRibF9zaXplOwogICAgICAgICsrczsKICAgIH0KICAgIHJldHVybiByID09IDAgPyAxIDogcjsKfQoKLy8gRW5kIG9mIGNzXzE2MV8xNjUuYwo=