// 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)) {
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+dGFibGUpIHsKICAgICAgICAgICAgZm9yIChpID0gMDsgaSA8IGhhc2gtPnRibF9zaXplOyBpKyspIHsKICAgICAgICAgICAgICAgIGlmIChoYXNoLT50YWJsZVtpXSkgewogICAgICAgICAgICAgICAgICAgIGZyZWUoaGFzaC0+dGFibGVbaV0pOwogICAgICAgICAgICAgICAgICAgIGhhc2gtPnRhYmxlW2ldID0gTlVMTDsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICBmcmVlKGhhc2gtPnRhYmxlKTsKICAgICAgICAgICAgaGFzaC0+dGFibGUgPSBOVUxMOwogICAgICAgIH0KICAgICAgICBpZiAoaGFzaC0+cmVmX3NlYXJjaF9jb3VudCkgewogICAgICAgICAgICBmcmVlKGhhc2gtPnJlZl9zZWFyY2hfY291bnQpOwogICAgICAgICAgICBoYXNoLT5yZWZfc2VhcmNoX2NvdW50ID0gTlVMTDsKICAgICAgICB9CiAgICAgICAgbWVtc2V0KGhhc2gsIDB4MDAsIHNpemVvZihIQVNIX0RBVEEpKTsKICAgIH0KfQoKRVJSX0NPREUgaGFzaF9tYWtlKEhBU0hfREFUQSAqIGhhc2gsIGNoYXIgKmZpbGVuYW1lKQp7CiAgICBGSUxFICpmcCA9IE5VTEw7CiAgICBjaGFyICpidWYgPSBOVUxMLCAqcDsKICAgIGludCBjOwogICAgRVJSX0NPREUgcmVzID0gRUNfTm9ybWFsOwoKICAgIC8vIOODkOODg+ODleOCoeeiuuS/nQogICAgaWYgKE5VTEwgPT0gKGJ1ZiA9IChjaGFyICopIG1hbGxvYyhzaXplb2YoY2hhcikgKiAoaGFzaC0+bGVuX21heCArIDIpKSkpIHsKICAgICAgICByZXMgPSBFQ19NZW1BbGxvYzsKICAgICAgICBnb3RvIEVORF9oYXNoX21ha2U7CiAgICB9CiAgICAvLyDoqq3jgb/ovrzjgb8g77yGIOODj+ODg+OCt+ODpeOBq+i/veWKoAogICAgZnAgPSBmb3BlbihmaWxlbmFtZSwgInIiKTsKICAgIHAgPSAmYnVmWzBdOwogICAgd2hpbGUgKGMgPSBmZ2V0YyhmcCkpIHsKICAgICAgICBpZiAoYyA9PSAnICcgfHwgYyA9PSAnXHQnIHx8IGMgPT0gJ1xyJyB8fCBjID09ICdcbicgfHwgYyA9PSBFT0YpIHsKICAgICAgICAgICAgKnAgPSAnXDAnOwogICAgICAgICAgICBwID0gJmJ1ZlswXTsKICAgICAgICAgICAgaWYgKHN0cmxlbihidWYpKSB7CiAgICAgICAgICAgICAgICBpZiAoRUNfTm9ybWFsICE9IChyZXMgPSBoYXNoX2FkZChoYXNoLCAmYnVmWzBdKSkpIHsKICAgICAgICAgICAgICAgICAgICBnb3RvIEVORF9oYXNoX21ha2U7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKGMgPT0gRU9GKSB7CiAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgfQogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICpwKysgPSAoY2hhcikgYzsKICAgICAgICB9CiAgICB9CiAgICAvLyDntYLkuoYKICAgIHJlcyA9IEVDX05vcm1hbDsKICBFTkRfaGFzaF9tYWtlOgogICAgaWYgKGJ1ZikgewogICAgICAgIGZyZWUoYnVmKTsKICAgICAgICBidWYgPSBOVUxMOwogICAgfQogICAgaWYgKGZwKSB7CiAgICAgICAgZmNsb3NlKGZwKTsKICAgICAgICBmcCA9IE5VTEw7CiAgICB9CgogICAgcmV0dXJuIHJlczsKfQoKRVJSX0NPREUgaGFzaF9hZGQoSEFTSF9EQVRBICogaGFzaCwgY2hhciAqc3RyKQp7CiAgICBpbnQgaW5kZXg7ICAgICAgICAgICAgICAgICAgLy8g6KiY6Yyy5YWICiAgICBpbnQgbmV4dF9zdGVwOyAgICAgICAgICAgICAgLy8g6KGd56qB5pmC5pu444GN6L6844G/5YWI5o6i57Si44K544OG44OD44OXCiAgICBpbnQgbGltaXQ7ICAgICAgICAgICAgICAgICAgLy8g6KiY6Yyy5YWI44GM6KaL44Gk44GL44KJ44Gq44GE5aC05ZCI44G444Gu5YKZ44GICgogICAgLy8gaGFzaOWApOWPluW+lwogICAgaW5kZXggPSBoYXNoZnVuY19oKHN0ciwgaGFzaCk7CiAgICBoYXNoLT5yZWZfc2VhcmNoX2NvdW50W2luZGV4XSsrOyAgICAvLyDmjqLntKLlj4Lnhafjgqvjgqbjg7Pjgr8KICAgIC8vIOihneeqgQogICAgaWYgKGhhc2gtPnRhYmxlW2luZGV4XSkgewogICAgICAgIC8vIOWQjOS4gOaWh+Wtl+WIlwogICAgICAgIGlmICgwID09IHN0cmNtcF9pZ25vcmUoaGFzaC0+dGFibGVbaW5kZXhdLCBzdHIpKSB7CiAgICAgICAgICAgIGlmIChoYXNoLT5tb2RlID09IEFNRF9NVVNJKSB7CiAgICAgICAgICAgICAgICByZXR1cm4gRUNfTm9ybWFsOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIC8vIOihneeqgeW+jCDlhaXjgozlhYjmjqLntKIKICAgICAgICBuZXh0X3N0ZXAgPSBoYXNoZnVuY19wKHN0ciwgaGFzaCk7CiAgICAgICAgZm9yIChsaW1pdCA9IDA7IGxpbWl0IDwgaGFzaC0+dGJsX3NpemU7IGxpbWl0KyspIHsKICAgICAgICAgICAgaW5kZXggPSAoaW5kZXggKyBuZXh0X3N0ZXApICUgaGFzaC0+dGJsX3NpemU7CiAgICAgICAgICAgIGhhc2gtPnJlZl9zZWFyY2hfY291bnRbaW5kZXhdKys7ICAgIC8vIOaOoue0ouWPgueFp+OCq+OCpuODs+OCvwogICAgICAgICAgICBpZiAoTlVMTCA9PSBoYXNoLT50YWJsZVtpbmRleF0pIHsKICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGlmIChsaW1pdCA+PSBoYXNoLT50Ymxfc2l6ZSkgewogICAgICAgICAgICByZXR1cm4gRUNfQ2FudEFkZEhhc2g7CiAgICAgICAgfQogICAgfQogICAgLy8g6L+95YqgCiAgICBpZiAoTlVMTCA9PSAoaGFzaC0+dGFibGVbaW5kZXhdID0gKGNoYXIgKikgbWFsbG9jKHNpemVvZihjaGFyKSAqIHN0cmxlbihzdHIpICsgMSkpKSB7CiAgICAgICAgcmV0dXJuIEVDX01lbUFsbG9jOwogICAgfQogICAgc3RyY3B5KGhhc2gtPnRhYmxlW2luZGV4XSwgc3RyKTsKCiAgICAvLyBlbmQKICAgIHJldHVybiBFQ19Ob3JtYWw7Cn0KCnZvaWQgaGFzaF9zaG93KEhBU0hfREFUQSAqIGhhc2gsIGNoYXIgKnNyY19maWxlbmFtZSkKewogICAgaW50IGk7CiAgICBjaGFyIGJbMjU2XTsKICAgIGludCBrZXRhX2NlbGw7ICAgICAgICAgICAgICAvLyDjgrvjg6vnlarlj7fmoYHmlbAKICAgIGludCBrZXRhX3JlZjsgICAgICAgICAgICAgICAvLyDlj4Lnhaflm57mlbDmoYHmlbAKICAgIGludCBtOwoKICAgIC8vIOahgeaVsOioiOeulwogICAga2V0YV9jZWxsID0gc3ByaW50ZihiLCAiJWQiLCBoYXNoLT50Ymxfc2l6ZSk7CiAgICBmb3IgKGkgPSBtID0gMDsgaSA8IGhhc2gtPnRibF9zaXplOyBpKyspIHsKICAgICAgICBpZiAobSA+IGhhc2gtPnJlZl9zZWFyY2hfY291bnRbaV0pIHsKICAgICAgICAgICAgbSA9IGhhc2gtPnJlZl9zZWFyY2hfY291bnRbaV07CiAgICAgICAgfQogICAgfQogICAga2V0YV9yZWYgPSBzcHJpbnRmKGIsICIlZCIsIG0pOwoKICAgIC8vIOWHuuWKmwogICAgZnByaW50ZihzdGRvdXQsICLjg7vlhaXlipvjg5XjgqHjgqTjg6sgICAgIDogJXNcbiIsIHNyY19maWxlbmFtZSk7CiAgICBmcHJpbnRmKHN0ZG91dCwgIuODu+acgOWkp+aWh+Wtl+WIl+mVtyAgICAgOiAlZFxuIiwgaGFzaC0+bGVuX21heCk7CiAgICBmcHJpbnRmKHN0ZG91dCwgIuODu+aWh+Wtl+WIl+aVsCAgICAgICAgIDogJWTlgItcbiIsIGhhc2gtPmRhdGFfbik7CiAgICBmcHJpbnRmKHN0ZG91dCwgIuODu0hhc2jjg4bjg7zjg5bjg6vmlbAgICA6ICVk5YCLXG4iLCBoYXNoLT50Ymxfc2l6ZSk7CiAgICBmcHJpbnRmKHN0ZG91dCwgIuODu0hhc2jov73liqDjg6Ljg7zjg4kgICA6IOWQjOS4gOaWh+Wtl+WIl+OCkuOAgSVzXG4iLCBnZXRTdHJfQUREX01PREUoaGFzaC0+bW9kZSkpOwogICAgZnByaW50ZihzdGRvdXQsICLjg7vlvZPntZDmnpzlh7rlipvjg6Ljg7zjg4kgOiDnqbrjga7jg4bjg7zjg5bjg6vopoHntKDjgpLlh7rlipslc1xuIiwgaGFzaC0+ZmxhZ19yZXNfb3V0ID8gIuOBmeOCiyIgOiAi44GX44Gq44GEIik7CiAgICBmb3IgKGkgPSAwOyBpIDwgaGFzaC0+dGJsX3NpemU7IGkrKykgewogICAgICAgIGlmIChoYXNoLT5mbGFnX3Jlc19vdXQgfHwgaGFzaC0+dGFibGVbaV0pIHsKICAgICAgICAgICAgZnByaW50ZihzdGRvdXQsICJbJTAqZF0g5Y+C54Wn5Zue5pWwID0gJTAqZCwg5qC857SN5paH5a2XID0gWyVzXVxuIiwga2V0YV9jZWxsLCBpLCBrZXRhX3JlZiwgaGFzaC0+cmVmX3NlYXJjaF9jb3VudFtpXQogICAgICAgICAgICAgICAgICAgICwgaGFzaC0+dGFibGVbaV0gPyBoYXNoLT50YWJsZVtpXSA6ICIiKTsKICAgICAgICB9CiAgICB9Cn0KCi8qCiAqICAgICAgaGFzaCBmdW5jdGlvbnMKICovCgppbnQgaGFzaGZ1bmNfaChjaGFyICpzLCBIQVNIX0RBVEEgKiBoYXNoKQp7CiAgICBpbnQgciA9IDA7CiAgICB3aGlsZSAoKnMpIHsKICAgICAgICAqcyA9IHRvbG93ZXIoKnMpOwogICAgICAgIGlmICgnYScgPD0gKnMgJiYgKnMgPD0gJ3onKSB7CiAgICAgICAgICAgIHIgPSByICogMjYgKyAoKnMgLSAnYScpOwogICAgICAgICAgICByICU9IGhhc2gtPnRibF9zaXplOwogICAgICAgIH0KICAgICAgICArK3M7CiAgICB9CiAgICByZXR1cm4gcjsKfQoKaW50IGhhc2hmdW5jX3AoY2hhciAqcywgSEFTSF9EQVRBICogaGFzaCkKewogICAgcmV0dXJuIDE7Cn0KCi8vIEVuZCBvZiBjc18xNjFfMTY1LmMK