#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct lst {
void *data;
struct lst *next;
};
struct lst *lst_cons(struct lst *elem, struct lst *lst);
struct lst *lst_append(struct lst *a, struct lst *b);
struct lst *lst_reverse(struct lst *lst);
void *alloc(size_t n);
int add(const char *s, struct lst *translation);
struct lst *translate(const char *s);
// --- main -------------------------------------------------------------------
void *alloc(size_t n)
{
void *r;
fputs("malloc() failed\n", stderr
); }
return r;
}
void print(struct lst *tp, FILE *iop)
{
while (tp) {
fputs(tp
->next
? ", " : "\n", iop
); tp = tp->next;
}
}
struct lst *new_translation(const char *s)
{
struct lst *tp = alloc(sizeof *tp);
return tp;
}
struct lst *tokenise(char *s, int n, FILE *iop)
{
const char *delim = " \t\r\n";
struct lst *lst = 0;
while (fgets(s
, n
, iop
)) { for (char *sp
= strtok(s
, delim
); sp
; sp
= strtok(0, delim
)) lst = lst_cons(new_translation(sp), lst);
if (lst)
return lst_reverse(lst);
}
return 0;
}
int main(int argc, char *argv[])
{
struct lst *lst;
char buf[8192];
FILE *iop;
if (argc
!= 2 || !(iop
= fopen(argv
[1], "r"))) { fprintf(stderr
, "usage: %s dictionary\n", argv[0] && argv[0][0] ? argv[0] : "translate");
return EXIT_FAILURE;
}
while ((lst = tokenise(buf, sizeof buf, iop))) {
if (!lst->next)
fprintf(stderr
, "%s: missing translation\n", (char *) lst->data);
else if (add(lst->data, lst->next))
fprintf(stderr
, "%s: invalid word\n", (char *) lst->data);
}
while (scanf("%8191s", buf
) == 1) print(translate(buf), stdout);
return 0;
}
// -- trie --------------------------------------------------------------------
struct letter {
struct lst *translation;
struct letter *link[26];
};
static int chartoindex(char c) // Assumes a sensible charset.
{
return isalpha((unsigned char) c
) ? tolower((unsigned char) c
) - 'a' : -1; }
static struct letter trie;
static struct letter *new_letter(void)
{
struct letter *lp = alloc(sizeof *lp);
for (int i = 0; i < sizeof lp->link / sizeof lp->link[0]; i++)
lp->link[i] = 0;
lp->translation = 0;
return lp;
}
int add(const char *s, struct lst *translation)
{
struct letter *tp = ≜
int i;
while (*s) {
if ((i = chartoindex(*s++)) < 0)
return -1;
if (!tp->link[i])
tp->link[i] = new_letter();
tp = tp->link[i];
}
tp->translation = lst_append(translation, tp->translation);
return 0;
}
struct lst *translate(const char *s)
{
struct letter *tp;
int i;
for (tp = ≜ *s && tp; tp = tp->link[i])
if ((i = chartoindex(*s++)) < 0)
return 0;
return tp ? tp->translation : 0;
}
// --- list -------------------------------------------------------------------
struct lst *lst_cons(struct lst *elem, struct lst *lst)
{
return elem->next = lst, elem;
}
struct lst *lst_append(struct lst *a, struct lst *b)
{
struct lst *r;
if (!a)
return b;
for (r = a; a->next; a = a->next)
;
a->next = b;
return r;
}
struct lst *lst_reverse(struct lst *lst)
{
struct lst *r, *next;
for (r = 0; lst; lst = next) {
next = lst->next;
r = lst_cons(lst, r);
}
return r;
}
I2luY2x1ZGUgPGN0eXBlLmg+CiNpbmNsdWRlIDxzdGRpby5oPgojaW5jbHVkZSA8c3RkbGliLmg+CiNpbmNsdWRlIDxzdHJpbmcuaD4KCnN0cnVjdCBsc3QgewoJdm9pZCAqZGF0YTsKCXN0cnVjdCBsc3QgKm5leHQ7Cn07CgpzdHJ1Y3QgbHN0ICpsc3RfY29ucyhzdHJ1Y3QgbHN0ICplbGVtLCBzdHJ1Y3QgbHN0ICpsc3QpOwoKc3RydWN0IGxzdCAqbHN0X2FwcGVuZChzdHJ1Y3QgbHN0ICphLCBzdHJ1Y3QgbHN0ICpiKTsKCnN0cnVjdCBsc3QgKmxzdF9yZXZlcnNlKHN0cnVjdCBsc3QgKmxzdCk7Cgp2b2lkICphbGxvYyhzaXplX3Qgbik7CgppbnQgYWRkKGNvbnN0IGNoYXIgKnMsIHN0cnVjdCBsc3QgKnRyYW5zbGF0aW9uKTsKCnN0cnVjdCBsc3QgKnRyYW5zbGF0ZShjb25zdCBjaGFyICpzKTsKCi8vIC0tLSBtYWluIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCnZvaWQgKmFsbG9jKHNpemVfdCBuKQp7Cgl2b2lkICpyOwoKCWlmICghKHIgPSBtYWxsb2MobikpKSB7CgkJZnB1dHMoIm1hbGxvYygpIGZhaWxlZFxuIiwgc3RkZXJyKTsKCQlleGl0KEVYSVRfRkFJTFVSRSk7Cgl9CglyZXR1cm4gcjsKfQoKdm9pZCBwcmludChzdHJ1Y3QgbHN0ICp0cCwgRklMRSAqaW9wKQp7Cgl3aGlsZSAodHApIHsKCQlmcHV0cyh0cC0+ZGF0YSwgaW9wKTsKCQlmcHV0cyh0cC0+bmV4dCA/ICIsICIgOiAiXG4iLCBpb3ApOwoJCXRwID0gdHAtPm5leHQ7Cgl9Cn0KCnN0cnVjdCBsc3QgKm5ld190cmFuc2xhdGlvbihjb25zdCBjaGFyICpzKQp7CglzdHJ1Y3QgbHN0ICp0cCA9IGFsbG9jKHNpemVvZiAqdHApOwoKCXN0cmNweSh0cC0+ZGF0YSA9IGFsbG9jKHN0cmxlbihzKSArIDEpLCBzKTsKCXJldHVybiB0cDsKfQoKc3RydWN0IGxzdCAqdG9rZW5pc2UoY2hhciAqcywgaW50IG4sIEZJTEUgKmlvcCkKewoJY29uc3QgY2hhciAqZGVsaW0gPSAiIFx0XHJcbiI7CglzdHJ1Y3QgbHN0ICpsc3QgPSAwOwoKCXdoaWxlIChmZ2V0cyhzLCBuLCBpb3ApKSB7CgkJZm9yIChjaGFyICpzcCA9IHN0cnRvayhzLCBkZWxpbSk7IHNwOyBzcCA9IHN0cnRvaygwLCBkZWxpbSkpCgkJCWxzdCA9IGxzdF9jb25zKG5ld190cmFuc2xhdGlvbihzcCksIGxzdCk7CgkJaWYgKGxzdCkKCQkJcmV0dXJuIGxzdF9yZXZlcnNlKGxzdCk7Cgl9CglyZXR1cm4gMDsKfQoKaW50IG1haW4oaW50IGFyZ2MsIGNoYXIgKmFyZ3ZbXSkKewoJc3RydWN0IGxzdCAqbHN0OwoJY2hhciBidWZbODE5Ml07CglGSUxFICppb3A7CgoJaWYgKGFyZ2MgIT0gMiB8fCAhKGlvcCA9IGZvcGVuKGFyZ3ZbMV0sICJyIikpKSB7CgkJZnByaW50ZihzdGRlcnIsICJ1c2FnZTogJXMgZGljdGlvbmFyeVxuIiwKCQkJYXJndlswXSAmJiBhcmd2WzBdWzBdID8gYXJndlswXSA6ICJ0cmFuc2xhdGUiKTsKCQlyZXR1cm4gRVhJVF9GQUlMVVJFOwoJfQoJd2hpbGUgKChsc3QgPSB0b2tlbmlzZShidWYsIHNpemVvZiBidWYsIGlvcCkpKSB7CgkJaWYgKCFsc3QtPm5leHQpCgkJCWZwcmludGYoc3RkZXJyLCAiJXM6IG1pc3NpbmcgdHJhbnNsYXRpb25cbiIsCgkJCQkoY2hhciAqKSBsc3QtPmRhdGEpOwoJCWVsc2UgaWYgKGFkZChsc3QtPmRhdGEsIGxzdC0+bmV4dCkpCgkJCWZwcmludGYoc3RkZXJyLCAiJXM6IGludmFsaWQgd29yZFxuIiwKCQkJCShjaGFyICopIGxzdC0+ZGF0YSk7CgkJZnJlZShsc3QpOwoJfQoJZmNsb3NlKGlvcCk7Cgl3aGlsZSAoc2NhbmYoIiU4MTkxcyIsIGJ1ZikgPT0gMSkKCQlwcmludCh0cmFuc2xhdGUoYnVmKSwgc3Rkb3V0KTsKCXJldHVybiAwOwp9CgovLyAtLSB0cmllIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgpzdHJ1Y3QgbGV0dGVyIHsKCXN0cnVjdCBsc3QgKnRyYW5zbGF0aW9uOwoJc3RydWN0IGxldHRlciAqbGlua1syNl07Cn07CgpzdGF0aWMgaW50IGNoYXJ0b2luZGV4KGNoYXIgYykJLy8gQXNzdW1lcyBhIHNlbnNpYmxlIGNoYXJzZXQuCnsKCXJldHVybiBpc2FscGhhKCh1bnNpZ25lZCBjaGFyKSBjKSA/CgkJdG9sb3dlcigodW5zaWduZWQgY2hhcikgYykgLSAnYScgOiAtMTsKfQoKc3RhdGljIHN0cnVjdCBsZXR0ZXIgdHJpZTsKCnN0YXRpYyBzdHJ1Y3QgbGV0dGVyICpuZXdfbGV0dGVyKHZvaWQpCnsKCXN0cnVjdCBsZXR0ZXIgKmxwID0gYWxsb2Moc2l6ZW9mICpscCk7CgoJZm9yIChpbnQgaSA9IDA7IGkgPCBzaXplb2YgbHAtPmxpbmsgLyBzaXplb2YgbHAtPmxpbmtbMF07IGkrKykKCQlscC0+bGlua1tpXSA9IDA7CglscC0+dHJhbnNsYXRpb24gPSAwOwoJcmV0dXJuIGxwOwp9CgppbnQgYWRkKGNvbnN0IGNoYXIgKnMsIHN0cnVjdCBsc3QgKnRyYW5zbGF0aW9uKQp7CglzdHJ1Y3QgbGV0dGVyICp0cCA9ICZ0cmllOwoJaW50IGk7CgoJd2hpbGUgKCpzKSB7CgkJaWYgKChpID0gY2hhcnRvaW5kZXgoKnMrKykpIDwgMCkKCQkJcmV0dXJuIC0xOwoJCWlmICghdHAtPmxpbmtbaV0pCgkJCXRwLT5saW5rW2ldID0gbmV3X2xldHRlcigpOwoJCXRwID0gdHAtPmxpbmtbaV07Cgl9Cgl0cC0+dHJhbnNsYXRpb24gPSBsc3RfYXBwZW5kKHRyYW5zbGF0aW9uLCB0cC0+dHJhbnNsYXRpb24pOwoJcmV0dXJuIDA7Cn0KCnN0cnVjdCBsc3QgKnRyYW5zbGF0ZShjb25zdCBjaGFyICpzKQp7CglzdHJ1Y3QgbGV0dGVyICp0cDsKCWludCBpOwoKCWZvciAodHAgPSAmdHJpZTsgKnMgJiYgdHA7IHRwID0gdHAtPmxpbmtbaV0pCgkJaWYgKChpID0gY2hhcnRvaW5kZXgoKnMrKykpIDwgMCkKCQkJcmV0dXJuIDA7CglyZXR1cm4gdHAgPyB0cC0+dHJhbnNsYXRpb24gOiAwOwp9CgovLyAtLS0gbGlzdCAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgpzdHJ1Y3QgbHN0ICpsc3RfY29ucyhzdHJ1Y3QgbHN0ICplbGVtLCBzdHJ1Y3QgbHN0ICpsc3QpCnsKCXJldHVybiBlbGVtLT5uZXh0ID0gbHN0LCBlbGVtOwp9CgpzdHJ1Y3QgbHN0ICpsc3RfYXBwZW5kKHN0cnVjdCBsc3QgKmEsIHN0cnVjdCBsc3QgKmIpCnsKCXN0cnVjdCBsc3QgKnI7CgoJaWYgKCFhKQoJCXJldHVybiBiOwoJZm9yIChyID0gYTsgYS0+bmV4dDsgYSA9IGEtPm5leHQpCgkJOwoJYS0+bmV4dCA9IGI7CglyZXR1cm4gcjsKfQoKc3RydWN0IGxzdCAqbHN0X3JldmVyc2Uoc3RydWN0IGxzdCAqbHN0KQp7CglzdHJ1Y3QgbHN0ICpyLCAqbmV4dDsKCglmb3IgKHIgPSAwOyBsc3Q7IGxzdCA9IG5leHQpIHsKCQluZXh0ID0gbHN0LT5uZXh0OwoJCXIgPSBsc3RfY29ucyhsc3QsIHIpOwoJfQoJcmV0dXJuIHI7Cn0K