+static struct lexer_token {
+ const char *string;
+ int value;
+} tokens[] = {
+#define TOKEN(NAME) { #NAME, NAME }
+ TOKEN(ADMIN),
+ TOKEN(GENERAL),
+ TOKEN(LOCATION),
+ TOKEN(CONTACT),
+ TOKEN(CLASS),
+ TOKEN(PINGFREQ),
+ TOKEN(CONNECT),
+ TOKEN(CONNECTFREQ),
+ TOKEN(MAXLINKS),
+ TOKEN(MAXHOPS),
+ TOKEN(SENDQ),
+ TOKEN(NAME),
+ TOKEN(HOST),
+ TOKEN(IP),
+ TOKEN(USERNAME),
+ TOKEN(PASS),
+ TOKEN(SECONDS),
+ TOKEN(MINUTES),
+ TOKEN(HOURS),
+ TOKEN(DAYS),
+ TOKEN(WEEKS),
+ TOKEN(MONTHS),
+ TOKEN(YEARS),
+ TOKEN(DECADES),
+ TOKEN(BYTES),
+ TOKEN(KBYTES),
+ TOKEN(MBYTES),
+ TOKEN(GBYTES),
+ TOKEN(TBYTES),
+ TOKEN(PORT),
+ TOKEN(SERVER),
+ TOKEN(YES),
+ TOKEN(NO),
+ TOKEN(HUB),
+ TOKEN(LEAF),
+ TOKEN(UWORLD),
+ TOKEN(OPER),
+ TOKEN(LOCAL),
+ TOKEN(VHOST),
+ TOKEN(MASK),
+ TOKEN(HIDDEN),
+ TOKEN(MOTD),
+ TOKEN(NUMERIC),
+ TOKEN(NICK),
+ TOKEN(JUPE),
+ TOKEN(DESCRIPTION),
+ TOKEN(CLIENT),
+ TOKEN(REAL),
+ TOKEN(REASON),
+ TOKEN(RULE),
+ TOKEN(ALL),
+ TOKEN(CRULE),
+ TOKEN(KILL),
+ TOKEN(QUARANTINE),
+ TOKEN(IAUTH),
+ TOKEN(TIMEOUT),
+ TOKEN(FEATURES),
+ TOKEN(CHANNEL),
+ TOKEN(PSEUDO),
+ TOKEN(PREPEND),
+ TOKEN(USERMODE),
+ TOKEN(FAST),
+ TOKEN(AUTOCONNECT),
+ TOKEN(PROGRAM),
+ TOKEN(DNS),
+#undef TOKEN
+ { "administrator", ADMIN },
+ { "apass_opmode", TPRIV_APASS_OPMODE },
+ { "auto", AUTOCONNECT },
+ { "b", BYTES },
+ { "badchan", TPRIV_BADCHAN },
+ { "chan_limit", TPRIV_CHAN_LIMIT },
+ { "deop_lchan", TPRIV_DEOP_LCHAN },
+ { "die", TPRIV_DIE },
+ { "display", TPRIV_DISPLAY },
+ { "file", TFILE },
+ { "force_local_opmode", TPRIV_FORCE_LOCAL_OPMODE },
+ { "force_opmode", TPRIV_FORCE_OPMODE },
+ { "gb", GBYTES },
+ { "gigabytes", GBYTES },
+ { "gline", TPRIV_GLINE },
+ { "ipv4", TOK_IPV4 },
+ { "ipv6", TOK_IPV6 },
+ { "kb", KBYTES },
+ { "kilobytes", KBYTES },
+ { "list_chan", TPRIV_LIST_CHAN },
+ { "local_badchan", TPRIV_LOCAL_BADCHAN },
+ { "local_gline", TPRIV_LOCAL_GLINE },
+ { "local_jupe", TPRIV_LOCAL_JUPE },
+ { "local_kill", TPRIV_LOCAL_KILL },
+ { "local_opmode", TPRIV_LOCAL_OPMODE },
+ { "mb", MBYTES },
+ { "megabytes", MBYTES },
+ { "mode_lchan", TPRIV_MODE_LCHAN },
+ { "operator", OPER },
+ { "opmode", TPRIV_OPMODE },
+ { "password", PASS },
+ { "propagate", TPRIV_PROPAGATE },
+ { "realname", REAL },
+ { "rehash", TPRIV_REHASH },
+ { "restart", TPRIV_RESTART },
+ { "see_chan", TPRIV_SEE_CHAN },
+ { "see_opers", TPRIV_SEE_OPERS },
+ { "set", TPRIV_SET },
+ { "show_all_invis", TPRIV_SHOW_ALL_INVIS },
+ { "show_invis", TPRIV_SHOW_INVIS },
+ { "tb", TBYTES },
+ { "terabytes", TBYTES },
+ { "unlimit_query", TPRIV_UNLIMIT_QUERY },
+ { "walk_lchan", TPRIV_WALK_LCHAN },
+ { "wide_gline", TPRIV_WIDE_GLINE },
+ { "whox", TPRIV_WHOX },
+ { NULL, 0 }
+};
+static int ntokens;
+
+static int
+token_compare(const void *pa, const void *pb)
+{
+ const struct lexer_token *ta = pa;
+ const struct lexer_token *tb = pb;
+ unsigned int ii = 0;
+ int res;
+ while (ta->string[ii] && (ToLower(ta->string[ii]) == ToLower(tb->string[ii])))
+ ii++;
+ res = ToLower(tb->string[ii]) - ToLower(ta->string[ii]);
+ return res;
+}
+
+static void
+init_ntokens(void)
+{
+ for (ntokens = 0; tokens[ntokens].string; ++ntokens) ;
+ qsort(tokens, ntokens, sizeof(tokens[0]), token_compare);
+}
+
+static int
+find_token(char *token)
+{
+ struct lexer_token *tok;
+ if (!ntokens)
+ init_ntokens();
+ tok = bsearch(&token, tokens, ntokens, sizeof(tokens[0]), token_compare);
+ return tok ? tok->value : 0;
+}
+
+static FBFILE *lexer_input;
+
+#undef YY_INPUT
+#define YY_INPUT(buf, res, size) res = (fbgets(buf, size, lexer_input) ? strlen(buf) : 0)
+
+int