#include "regex.h"
#define connect_e(src_node, dst_node, i) \
{ \
src_node->edges[i] = dst_node; \
src_node->noname[i] = true; \
}
#define connect(src_node, dst_node, c, i) \
{ \
connect_e(src_node, dst_node, i); \
src_node->labels[(int)c] = i; \
src_node->noname[i] = false; \
}
#define check_char(c) (isprint(c) && !iscntrl(c))
typedef struct _ReturnValue {
NFA head;
NFA tail;
int str_index;
} ReturnValue;
static NFA new_node(void);
static ReturnValue new_connect_node(NFA head, char c);
static ReturnValue compile_class(const char *str, int begin);
static ReturnValue nfa_compile(const char *str, int begin);
static void nfa_to_graphviz(NFA head, const char *dot_file, const char *image_file);
static int count_id = 1;
static NFA new_node(void)
/* ノードを確保し値を初期化して返す
labelsの使わない添字には-1を入れておく */
{
NFA node
= malloc(sizeof(struct _NFA
)); node->edges[0] = node->edges[1] = NULL;
node->noname[0] = node->noname[1] = false;
memset(node
->labels
, -1, LABELS_SIZE
* sizeof(node
->labels
[0])); node->id = count_id++;
return node;
}
static ReturnValue new_connect_node(NFA head, char c)
/* head --[c]--> newnode */
{
NFA tail = new_node();
connect(head, tail, c, 0);
ReturnValue rv = {.head = head, .tail = tail};
return rv;
}
static NFA reverse_labels(NFA node)
{
for (int i = 0; i < LABELS_SIZE; i++) {
node->labels[i] = (node->labels[i] == -1 ? 0 : -1);
if (!check_char(i)) {
node->labels[i] = -1;
}
}
return node;
}
static ReturnValue compile_class(const char *str, int begin)
{
NFA head = new_node();
NFA tail = new_node();
bool reverse_flag = false;
if (str[begin] == '^') {
begin++;
reverse_flag = true;
}
for (int i = begin; str[i]; i++) {
switch (str[i]) {
case ']':
{
if (reverse_flag) {
head = reverse_labels(head);
}
ReturnValue rv = {.head = head, .tail = tail, .str_index = i};
return rv;
}
case '-':
{
char c1 = str[i-1];
char c2 = str[i+1];
for (; c1 <= c2; c1++)
connect(head, tail, c1, 0);
i++;
break;
}
default:
if (str[i+1] != '-') {
connect(head, tail, str[i], 0);
}
break;
}
}
fputs("クラスの終わりがない\n", stderr
); }
static ReturnValue compile_or(NFA head_node, NFA tail_node, const char *str, int i)
{
NFA head = new_node(), tail = new_node();
connect_e(head, head_node, 0);
connect_e(tail_node, tail, 0);
ReturnValue rv = nfa_compile(str, i + 1);
connect_e(head, rv.head, 1);
connect_e(rv.tail, tail, 0);
ReturnValue rv2 = {.head = head, .tail = tail, .str_index = rv.str_index};
return rv2;
}
static ReturnValue compile_repeat(NFA head_node, NFA tail_node, NFA cur_node)
{
NFA node, head = new_node(), tail = new_node();
bool flag = false;
if (head_node == cur_node) {
flag = true;
node = new_node();
} else {
for (node = head_node; node->edges[0] != cur_node; node = node->edges[0]);
}
connect_e(head, cur_node, 0);
connect_e(head, tail, 1);
connect_e(tail_node, tail, 0);
connect_e(tail_node, cur_node, 1);
node->edges[0] = head;
if (flag) head_node = head;
ReturnValue rv = {.head = head_node, .tail = tail};
return rv;
}
static ReturnValue nfa_compile(const char *str, int begin)
{
NFA head_node = new_node();
NFA tail_node = head_node;
NFA cur_node = head_node;
int i;
for (i = begin; str[i]; i++) {
switch (str[i]) {
case '[':
{
ReturnValue rv = compile_class(str, i + 1);
connect_e(tail_node, rv.head, 0);
cur_node = rv.head;
tail_node = rv.tail;
i = rv.str_index;
break;
}
case '(':
{
ReturnValue rv = nfa_compile(str, i + 1);
connect_e(tail_node, rv.head, 0);
cur_node = rv.head;
tail_node = rv.tail;
i = rv.str_index;
break;
}
case ')':
{
ReturnValue rv = {.head = head_node, .tail = tail_node, .str_index = i};
return rv;
}
case '|':
{
ReturnValue rv = compile_or(head_node, tail_node, str, i);
head_node = rv.head;
tail_node = rv.tail;
cur_node = rv.head;
i = rv.str_index;
break;
}
case '*':
{
ReturnValue rv = compile_repeat(head_node, tail_node, cur_node);
head_node = rv.head;
tail_node = rv.tail;
break;
}
default:
{
ReturnValue rv = new_connect_node(tail_node, str[i]);
cur_node = rv.head;
tail_node = rv.tail;
break;
}
}
}
ReturnValue rv = {.head = head_node, .tail = tail_node, .str_index = i - 1};
return rv;
}
static void nfa_to_graphviz(NFA head, const char *dot_file, const char *image_file)
{
FILE
*fp
= fopen(dot_file
, "w"); if (fp == NULL) {
fputs("ファイルを読み込めない\n", stderr
); }
int id_array[100000];
memset(id_array
, 0, sizeof(id_array
));
bool do_node(NFA node, int index)
{
if (node->edges[index]) {
if (node->noname[index]) {
fprintf(fp
, "%d -> %d [label = \"%s\"];\n", node->id, node->edges[index]->id, "ε");
} else {
for (int i = 0; i < LABELS_SIZE; i++) {
if ((node->labels[i] != -1) && (index == node->labels[i])) {
if (i == '"' || i == '\\') {
fprintf(fp
, "%d -> %d [label = \"\\%c\"];\n", node->id, node->edges[index]->id, i);
} else {
fprintf(fp
, "%d -> %d [label = \"%c\"];\n", node->id, node->edges[index]->id, i);
}
}
}
}
return true;
}
return false;
}
void recur(NFA node)
{
if (id_array[node->id]) {
return;
} else {
id_array[node->id] = 1;
}
if (do_node(node, 0)) recur(node->edges[0]);
if (do_node(node, 1)) recur(node->edges[1]);
}
fputs("digraph test {\n", fp
); fputs("graph [rankdir = LR];\n", fp
); recur(head);
if (image_file != NULL) {
char buf[512];
sprintf(buf
, "dot -Tgif %s -o %s", dot_file
, image_file
); }
}
NFA regex_compile(const char *regstr)
{
ReturnValue rv = nfa_compile(regstr, 0);
return rv.head;
}
static char g_word[256];
static int g_word_index;
#define branch(edge, str) \
{ \
char *p = regex_recur(edge, str); \
if (p) return p; \
}
static char* regex_recur(NFA node, const char *str)
{
if (node->edges[0] == NULL && node->edges[1] == NULL) {
if (g_word_index == 0) return NULL;
g_word[g_word_index] = '\0';
return g_word;
}
for (int i = 0; i <= 1; i++) {
if (node->edges[i] && node->noname[i] && node->id > node->edges[i]->id) {
branch(node->edges[i], str);
}
}
for (int i = 0; i <= 1; i++) {
if (node->edges[i] && node->noname[i]) {
branch(node->edges[i], str);
}
}
int index = node->labels[(int)*str];
if (index != -1) {
g_word[g_word_index++] = *str;
branch(node->edges[index], str + 1);
}
return NULL;
}
char* regex_search(NFA node, const char *str)
{
for (int i = 0; str[i]; i++) {
g_word_index = 0;
branch(node, str + i);
}
return NULL;
}
int main(int argc, char *argv[])
{
if (argc == 1) return 1;
NFA head = regex_compile(argv[1]);
nfa_to_graphviz(head, "test.dot", "test.gif");
char line[256];
while (fgets(line
, sizeof(line
), stdin
)) { char *p = regex_search(head, line);
}
}
I2luY2x1ZGUgInJlZ2V4LmgiCgojZGVmaW5lIGNvbm5lY3RfZShzcmNfbm9kZSwgZHN0X25vZGUsIGkpICAgIFwKICB7CQkJCQkJXAogICAgc3JjX25vZGUtPmVkZ2VzW2ldID0gZHN0X25vZGU7CQlcCiAgICBzcmNfbm9kZS0+bm9uYW1lW2ldID0gdHJ1ZTsJCQlcCiAgfQoKI2RlZmluZSBjb25uZWN0KHNyY19ub2RlLCBkc3Rfbm9kZSwgYywgaSkJXAogIHsJCQkJCQlcCiAgICBjb25uZWN0X2Uoc3JjX25vZGUsIGRzdF9ub2RlLCBpKTsJCVwKICAgIHNyY19ub2RlLT5sYWJlbHNbKGludCljXSA9IGk7CQlcCiAgICBzcmNfbm9kZS0+bm9uYW1lW2ldID0gZmFsc2U7CQlcCiAgfQoKI2RlZmluZSBjaGVja19jaGFyKGMpIChpc3ByaW50KGMpICYmICFpc2NudHJsKGMpKQoKdHlwZWRlZiBzdHJ1Y3QgX1JldHVyblZhbHVlIHsKICBORkEgaGVhZDsKICBORkEgdGFpbDsKICBpbnQgc3RyX2luZGV4Owp9IFJldHVyblZhbHVlOwoKc3RhdGljIE5GQSBuZXdfbm9kZSh2b2lkKTsKc3RhdGljIFJldHVyblZhbHVlIG5ld19jb25uZWN0X25vZGUoTkZBIGhlYWQsIGNoYXIgYyk7CnN0YXRpYyBSZXR1cm5WYWx1ZSBjb21waWxlX2NsYXNzKGNvbnN0IGNoYXIgKnN0ciwgaW50IGJlZ2luKTsKc3RhdGljIFJldHVyblZhbHVlIG5mYV9jb21waWxlKGNvbnN0IGNoYXIgKnN0ciwgaW50IGJlZ2luKTsKc3RhdGljIHZvaWQgbmZhX3RvX2dyYXBodml6KE5GQSBoZWFkLCBjb25zdCBjaGFyICpkb3RfZmlsZSwgY29uc3QgY2hhciAqaW1hZ2VfZmlsZSk7CgpzdGF0aWMgaW50IGNvdW50X2lkID0gMTsKCnN0YXRpYyBORkEgbmV3X25vZGUodm9pZCkKLyog44OO44O844OJ44KS56K65L+d44GX5YCk44KS5Yid5pyf5YyW44GX44Gm6L+U44GZCiAgIGxhYmVsc+OBruS9v+OCj+OBquOBhOa3u+Wtl+OBq+OBry0x44KS5YWl44KM44Gm44GK44GPICovCnsKICBORkEgbm9kZSA9IG1hbGxvYyhzaXplb2Yoc3RydWN0IF9ORkEpKTsKICBub2RlLT5lZGdlc1swXSA9IG5vZGUtPmVkZ2VzWzFdID0gTlVMTDsKICBub2RlLT5ub25hbWVbMF0gPSBub2RlLT5ub25hbWVbMV0gPSBmYWxzZTsKICBtZW1zZXQobm9kZS0+bGFiZWxzLCAtMSwgTEFCRUxTX1NJWkUgKiBzaXplb2Yobm9kZS0+bGFiZWxzWzBdKSk7CiAgbm9kZS0+aWQgPSBjb3VudF9pZCsrOwogIHJldHVybiBub2RlOwp9CgpzdGF0aWMgUmV0dXJuVmFsdWUgbmV3X2Nvbm5lY3Rfbm9kZShORkEgaGVhZCwgY2hhciBjKQovKiBoZWFkIC0tW2NdLS0+IG5ld25vZGUgKi8KewogIE5GQSB0YWlsID0gbmV3X25vZGUoKTsKICBjb25uZWN0KGhlYWQsIHRhaWwsIGMsIDApOwogIFJldHVyblZhbHVlIHJ2ID0gey5oZWFkID0gaGVhZCwgLnRhaWwgPSB0YWlsfTsKICByZXR1cm4gcnY7Cn0KCnN0YXRpYyBORkEgcmV2ZXJzZV9sYWJlbHMoTkZBIG5vZGUpCnsKICBmb3IgKGludCBpID0gMDsgaSA8IExBQkVMU19TSVpFOyBpKyspIHsKICAgIG5vZGUtPmxhYmVsc1tpXSA9IChub2RlLT5sYWJlbHNbaV0gPT0gLTEgPyAwIDogLTEpOwogICAgaWYgKCFjaGVja19jaGFyKGkpKSB7CiAgICAgIG5vZGUtPmxhYmVsc1tpXSA9IC0xOwogICAgfQogIH0KICByZXR1cm4gbm9kZTsKfQoKc3RhdGljIFJldHVyblZhbHVlIGNvbXBpbGVfY2xhc3MoY29uc3QgY2hhciAqc3RyLCBpbnQgYmVnaW4pCnsKICBORkEgaGVhZCA9IG5ld19ub2RlKCk7CiAgTkZBIHRhaWwgPSBuZXdfbm9kZSgpOwoKICBib29sIHJldmVyc2VfZmxhZyA9IGZhbHNlOwoKICBpZiAoc3RyW2JlZ2luXSA9PSAnXicpIHsKICAgIGJlZ2luKys7CiAgICByZXZlcnNlX2ZsYWcgPSB0cnVlOwogIH0KCiAgZm9yIChpbnQgaSA9IGJlZ2luOyBzdHJbaV07IGkrKykgewogICAgc3dpdGNoIChzdHJbaV0pIHsKICAgIGNhc2UgJ10nOgogICAgICB7CglpZiAocmV2ZXJzZV9mbGFnKSB7CgkgIGhlYWQgPSByZXZlcnNlX2xhYmVscyhoZWFkKTsKCX0KCVJldHVyblZhbHVlIHJ2ID0gey5oZWFkID0gaGVhZCwgLnRhaWwgPSB0YWlsLCAuc3RyX2luZGV4ID0gaX07CglyZXR1cm4gcnY7CiAgICAgIH0KICAgIGNhc2UgJy0nOgogICAgICB7CgljaGFyIGMxID0gc3RyW2ktMV07CgljaGFyIGMyID0gc3RyW2krMV07Cglmb3IgKDsgYzEgPD0gYzI7IGMxKyspCgkgIGNvbm5lY3QoaGVhZCwgdGFpbCwgYzEsIDApOwoJaSsrOwoJYnJlYWs7CiAgICAgIH0KICAgIGRlZmF1bHQ6CiAgICAgIGlmIChzdHJbaSsxXSAhPSAnLScpIHsKCWNvbm5lY3QoaGVhZCwgdGFpbCwgc3RyW2ldLCAwKTsKICAgICAgfQogICAgICBicmVhazsKICAgIH0KICB9CgogIGZwdXRzKCLjgq/jg6njgrnjga7ntYLjgo/jgorjgYzjgarjgYRcbiIsIHN0ZGVycik7CiAgZXhpdChFWElUX0ZBSUxVUkUpOwp9CgpzdGF0aWMgUmV0dXJuVmFsdWUgY29tcGlsZV9vcihORkEgaGVhZF9ub2RlLCBORkEgdGFpbF9ub2RlLCBjb25zdCBjaGFyICpzdHIsIGludCBpKQp7CiAgTkZBIGhlYWQgPSBuZXdfbm9kZSgpLCB0YWlsID0gbmV3X25vZGUoKTsKICBjb25uZWN0X2UoaGVhZCwgaGVhZF9ub2RlLCAwKTsKICBjb25uZWN0X2UodGFpbF9ub2RlLCB0YWlsLCAwKTsKICBSZXR1cm5WYWx1ZSBydiA9IG5mYV9jb21waWxlKHN0ciwgaSArIDEpOwogIGNvbm5lY3RfZShoZWFkLCBydi5oZWFkLCAxKTsKICBjb25uZWN0X2UocnYudGFpbCwgdGFpbCwgMCk7CgogIFJldHVyblZhbHVlIHJ2MiA9IHsuaGVhZCA9IGhlYWQsIC50YWlsID0gdGFpbCwgLnN0cl9pbmRleCA9IHJ2LnN0cl9pbmRleH07CiAgcmV0dXJuIHJ2MjsKfQoKc3RhdGljIFJldHVyblZhbHVlIGNvbXBpbGVfcmVwZWF0KE5GQSBoZWFkX25vZGUsIE5GQSB0YWlsX25vZGUsIE5GQSBjdXJfbm9kZSkKewogIE5GQSBub2RlLCBoZWFkID0gbmV3X25vZGUoKSwgdGFpbCA9IG5ld19ub2RlKCk7CiAgYm9vbCBmbGFnID0gZmFsc2U7CgogIGlmIChoZWFkX25vZGUgPT0gY3VyX25vZGUpIHsKICAgIGZsYWcgPSB0cnVlOwogICAgbm9kZSA9IG5ld19ub2RlKCk7CiAgfSBlbHNlIHsKICAgIGZvciAobm9kZSA9IGhlYWRfbm9kZTsgbm9kZS0+ZWRnZXNbMF0gIT0gY3VyX25vZGU7IG5vZGUgPSBub2RlLT5lZGdlc1swXSk7CiAgfQoKICBjb25uZWN0X2UoaGVhZCwgY3VyX25vZGUsIDApOwogIGNvbm5lY3RfZShoZWFkLCB0YWlsLCAxKTsKICBjb25uZWN0X2UodGFpbF9ub2RlLCB0YWlsLCAwKTsKICBjb25uZWN0X2UodGFpbF9ub2RlLCBjdXJfbm9kZSwgMSk7CiAgbm9kZS0+ZWRnZXNbMF0gPSBoZWFkOwoKICBpZiAoZmxhZykgaGVhZF9ub2RlID0gaGVhZDsKICBSZXR1cm5WYWx1ZSBydiA9IHsuaGVhZCA9IGhlYWRfbm9kZSwgLnRhaWwgPSB0YWlsfTsKICByZXR1cm4gcnY7Cn0KCnN0YXRpYyBSZXR1cm5WYWx1ZSBuZmFfY29tcGlsZShjb25zdCBjaGFyICpzdHIsIGludCBiZWdpbikKewogIE5GQSBoZWFkX25vZGUgPSBuZXdfbm9kZSgpOwogIE5GQSB0YWlsX25vZGUgPSBoZWFkX25vZGU7CiAgTkZBIGN1cl9ub2RlID0gaGVhZF9ub2RlOwoKICBpbnQgaTsKICBmb3IgKGkgPSBiZWdpbjsgc3RyW2ldOyBpKyspIHsKICAgIHN3aXRjaCAoc3RyW2ldKSB7CiAgICBjYXNlICdbJzoKICAgICAgewogICAgICAJUmV0dXJuVmFsdWUgcnYgPSBjb21waWxlX2NsYXNzKHN0ciwgaSArIDEpOwoJY29ubmVjdF9lKHRhaWxfbm9kZSwgcnYuaGVhZCwgMCk7CgljdXJfbm9kZSA9IHJ2LmhlYWQ7CiAgICAgIAl0YWlsX25vZGUgPSBydi50YWlsOwoJaSA9IHJ2LnN0cl9pbmRleDsKICAgICAgCWJyZWFrOwogICAgICB9CiAgICBjYXNlICcoJzoKICAgICAgewoJUmV0dXJuVmFsdWUgcnYgPSBuZmFfY29tcGlsZShzdHIsIGkgKyAxKTsKCWNvbm5lY3RfZSh0YWlsX25vZGUsIHJ2LmhlYWQsIDApOwoJY3VyX25vZGUgPSBydi5oZWFkOwoJdGFpbF9ub2RlID0gcnYudGFpbDsKCWkgPSBydi5zdHJfaW5kZXg7CglicmVhazsKICAgICAgfQogICAgY2FzZSAnKSc6CiAgICAgIHsKCVJldHVyblZhbHVlIHJ2ID0gey5oZWFkID0gaGVhZF9ub2RlLCAudGFpbCA9IHRhaWxfbm9kZSwgLnN0cl9pbmRleCA9IGl9OwoJcmV0dXJuIHJ2OwogICAgICB9CiAgICBjYXNlICd8JzoKICAgICAgewoJUmV0dXJuVmFsdWUgcnYgPSBjb21waWxlX29yKGhlYWRfbm9kZSwgdGFpbF9ub2RlLCBzdHIsIGkpOwoJaGVhZF9ub2RlID0gcnYuaGVhZDsKCXRhaWxfbm9kZSA9IHJ2LnRhaWw7CgljdXJfbm9kZSA9IHJ2LmhlYWQ7CglpID0gcnYuc3RyX2luZGV4OwoJYnJlYWs7CiAgICAgIH0KICAgIGNhc2UgJyonOgogICAgICB7CglSZXR1cm5WYWx1ZSBydiA9IGNvbXBpbGVfcmVwZWF0KGhlYWRfbm9kZSwgdGFpbF9ub2RlLCBjdXJfbm9kZSk7CgloZWFkX25vZGUgPSBydi5oZWFkOwoJdGFpbF9ub2RlID0gcnYudGFpbDsKCWJyZWFrOwogICAgICB9CiAgICBkZWZhdWx0OgogICAgICB7CglSZXR1cm5WYWx1ZSBydiA9IG5ld19jb25uZWN0X25vZGUodGFpbF9ub2RlLCBzdHJbaV0pOwoJY3VyX25vZGUgPSBydi5oZWFkOwoJdGFpbF9ub2RlID0gcnYudGFpbDsKCWJyZWFrOwogICAgICB9CiAgICB9CiAgfQoKICBSZXR1cm5WYWx1ZSBydiA9IHsuaGVhZCA9IGhlYWRfbm9kZSwgLnRhaWwgPSB0YWlsX25vZGUsIC5zdHJfaW5kZXggPSBpIC0gMX07CiAgcmV0dXJuIHJ2Owp9CgpzdGF0aWMgdm9pZCBuZmFfdG9fZ3JhcGh2aXooTkZBIGhlYWQsIGNvbnN0IGNoYXIgKmRvdF9maWxlLCBjb25zdCBjaGFyICppbWFnZV9maWxlKQp7CiAgRklMRSAqZnAgPSBmb3Blbihkb3RfZmlsZSwgInciKTsKICBpZiAoZnAgPT0gTlVMTCkgewogICAgZnB1dHMoIuODleOCoeOCpOODq+OCkuiqreOBv+i+vOOCgeOBquOBhFxuIiwgc3RkZXJyKTsKICAgIGV4aXQoRVhJVF9GQUlMVVJFKTsKICB9CgogIGludCBpZF9hcnJheVsxMDAwMDBdOwogIG1lbXNldChpZF9hcnJheSwgMCwgc2l6ZW9mKGlkX2FycmF5KSk7CgogIGJvb2wgZG9fbm9kZShORkEgbm9kZSwgaW50IGluZGV4KQogIHsKICAgIGlmIChub2RlLT5lZGdlc1tpbmRleF0pIHsKICAgICAgaWYgKG5vZGUtPm5vbmFtZVtpbmRleF0pIHsKCWZwcmludGYoZnAsICIlZCAtPiAlZCBbbGFiZWwgPSBcIiVzXCJdO1xuIiwKCQlub2RlLT5pZCwgbm9kZS0+ZWRnZXNbaW5kZXhdLT5pZCwgIs61Iik7CiAgICAgIH0gZWxzZSB7Cglmb3IgKGludCBpID0gMDsgaSA8IExBQkVMU19TSVpFOyBpKyspIHsKCSAgaWYgKChub2RlLT5sYWJlbHNbaV0gIT0gLTEpICYmIChpbmRleCA9PSBub2RlLT5sYWJlbHNbaV0pKSB7CgkgICAgaWYgKGkgPT0gJyInIHx8IGkgPT0gJ1xcJykgewoJICAgICAgZnByaW50ZihmcCwgIiVkIC0+ICVkIFtsYWJlbCA9IFwiXFwlY1wiXTtcbiIsCgkJICAgICAgbm9kZS0+aWQsIG5vZGUtPmVkZ2VzW2luZGV4XS0+aWQsIGkpOwoJICAgIH0gZWxzZSB7CgkgICAgICBmcHJpbnRmKGZwLCAiJWQgLT4gJWQgW2xhYmVsID0gXCIlY1wiXTtcbiIsCgkJICAgICAgbm9kZS0+aWQsIG5vZGUtPmVkZ2VzW2luZGV4XS0+aWQsIGkpOwoJICAgIH0KCSAgfQoJfQogICAgICB9CiAgICAgIHJldHVybiB0cnVlOwogICAgfQogICAgcmV0dXJuIGZhbHNlOwogIH0KCiAgdm9pZCByZWN1cihORkEgbm9kZSkKICB7CiAgICBpZiAoaWRfYXJyYXlbbm9kZS0+aWRdKSB7CiAgICAgIHJldHVybjsKICAgIH0gZWxzZSB7CiAgICAgIGlkX2FycmF5W25vZGUtPmlkXSA9IDE7CiAgICB9CgogICAgaWYgKGRvX25vZGUobm9kZSwgMCkpIHJlY3VyKG5vZGUtPmVkZ2VzWzBdKTsKICAgIGlmIChkb19ub2RlKG5vZGUsIDEpKSByZWN1cihub2RlLT5lZGdlc1sxXSk7CiAgfQoKICBmcHV0cygiZGlncmFwaCB0ZXN0IHtcbiIsIGZwKTsKICBmcHV0cygiZ3JhcGggW3JhbmtkaXIgPSBMUl07XG4iLCBmcCk7CiAgcmVjdXIoaGVhZCk7CiAgZnB1dHMoIn1cbiIsIGZwKTsKCiAgZmNsb3NlKGZwKTsKCiAgaWYgKGltYWdlX2ZpbGUgIT0gTlVMTCkgewogICAgY2hhciBidWZbNTEyXTsKICAgIHNwcmludGYoYnVmLCAiZG90IC1UZ2lmICVzIC1vICVzIiwgZG90X2ZpbGUsIGltYWdlX2ZpbGUpOwogICAgc3lzdGVtKGJ1Zik7CiAgfQp9CgpORkEgcmVnZXhfY29tcGlsZShjb25zdCBjaGFyICpyZWdzdHIpCnsKICBSZXR1cm5WYWx1ZSBydiA9IG5mYV9jb21waWxlKHJlZ3N0ciwgMCk7CiAgcmV0dXJuIHJ2LmhlYWQ7Cn0KCgpzdGF0aWMgY2hhciBnX3dvcmRbMjU2XTsKc3RhdGljIGludCBnX3dvcmRfaW5kZXg7CgojZGVmaW5lIGJyYW5jaChlZGdlLCBzdHIpCQkJXAogIHsJCQkJCQlcCiAgICBjaGFyICpwID0gcmVnZXhfcmVjdXIoZWRnZSwgc3RyKTsJCVwKICAgIGlmIChwKSByZXR1cm4gcDsJCQkJXAogIH0KCnN0YXRpYyBjaGFyKiByZWdleF9yZWN1cihORkEgbm9kZSwgY29uc3QgY2hhciAqc3RyKQp7CiAgaWYgKG5vZGUtPmVkZ2VzWzBdID09IE5VTEwgJiYgbm9kZS0+ZWRnZXNbMV0gPT0gTlVMTCkgewogICAgaWYgKGdfd29yZF9pbmRleCA9PSAwKSByZXR1cm4gTlVMTDsKICAgIGdfd29yZFtnX3dvcmRfaW5kZXhdID0gJ1wwJzsKICAgIHJldHVybiBnX3dvcmQ7CiAgfQoKICBmb3IgKGludCBpID0gMDsgaSA8PSAxOyBpKyspIHsKICAgIGlmIChub2RlLT5lZGdlc1tpXSAmJiBub2RlLT5ub25hbWVbaV0gJiYgbm9kZS0+aWQgPiBub2RlLT5lZGdlc1tpXS0+aWQpIHsKICAgICAgYnJhbmNoKG5vZGUtPmVkZ2VzW2ldLCBzdHIpOwogICAgfQogIH0KCiAgZm9yIChpbnQgaSA9IDA7IGkgPD0gMTsgaSsrKSB7CiAgICBpZiAobm9kZS0+ZWRnZXNbaV0gJiYgbm9kZS0+bm9uYW1lW2ldKSB7CiAgICAgIGJyYW5jaChub2RlLT5lZGdlc1tpXSwgc3RyKTsKICAgIH0KICB9CgogIGludCBpbmRleCA9IG5vZGUtPmxhYmVsc1soaW50KSpzdHJdOwogIGlmIChpbmRleCAhPSAtMSkgewogICAgZ193b3JkW2dfd29yZF9pbmRleCsrXSA9ICpzdHI7CiAgICBicmFuY2gobm9kZS0+ZWRnZXNbaW5kZXhdLCBzdHIgKyAxKTsKICB9CgogIHJldHVybiBOVUxMOwp9CgpjaGFyKiByZWdleF9zZWFyY2goTkZBIG5vZGUsIGNvbnN0IGNoYXIgKnN0cikKewogIGZvciAoaW50IGkgPSAwOyBzdHJbaV07IGkrKykgewogICAgZ193b3JkX2luZGV4ID0gMDsKICAgIGJyYW5jaChub2RlLCBzdHIgKyBpKTsKICB9CiAgcmV0dXJuIE5VTEw7Cn0KCmludCBtYWluKGludCBhcmdjLCBjaGFyICphcmd2W10pCnsKICBpZiAoYXJnYyA9PSAxKSByZXR1cm4gMTsKCiAgTkZBIGhlYWQgPSByZWdleF9jb21waWxlKGFyZ3ZbMV0pOwogIG5mYV90b19ncmFwaHZpeihoZWFkLCAidGVzdC5kb3QiLCAidGVzdC5naWYiKTsKCiAgY2hhciBsaW5lWzI1Nl07CiAgd2hpbGUgKGZnZXRzKGxpbmUsIHNpemVvZihsaW5lKSwgc3RkaW4pKSB7CiAgICBjaGFyICpwID0gcmVnZXhfc2VhcmNoKGhlYWQsIGxpbmUpOwogICAgcHV0cyhwKTsKICB9Cn0K