ircu2/ircd/ircd_lexer.l

382 lines
8.6 KiB
Plaintext

/*
* ircd_lexer.l: A lexical scanner for ircd config files.
* This is part of ircu, an Internet Relay Chat server.
* The contents of this file are Copyright(C) 2001 by Andrew Miller, the
* ircd-hybrid team and the ircu team.
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
* $Id: ircd_lexer.l 1851 2007-11-30 22:10:04Z klmitch $
*/
%option nounput
%option noinput
%{
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "config.h"
#include "fileio.h"
#include "ircd.h"
#include "ircd_alloc.h"
#include "ircd_string.h"
#include "s_conf.h"
#include "s_debug.h"
#include "y.tab.h"
extern int lineno;
extern char* linefile;
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(RECVQ),
TOKEN(NAME),
TOKEN(HOST),
TOKEN(FROM),
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),
TOKEN(FORWARDS),
TOKEN(WEBIRC),
TOKEN(IDENT),
TOKEN(USERIDENT),
TOKEN(IGNOREIDENT),
TOKEN(STRIPSSLFP),
TOKEN(MAXCHANS),
TOKEN(COUNTRY),
TOKEN(CONTINENT),
TOKEN(VERSION),
TOKEN(SPOOFHOST),
TOKEN(AUTOAPPLY),
TOKEN(SNOMASK),
TOKEN(EXCEPT),
TOKEN(SHUN),
TOKEN(KLINE),
TOKEN(GLINE),
TOKEN(ZLINE),
TOKEN(RDNS),
TOKEN(IPCHECK),
TOKEN(TARGETLIMIT),
TOKEN(LISTDELAY),
TOKEN(NOIDENTTILDE),
TOKEN(ISMASK),
TOKEN(REDIRECT),
TOKEN(HIDEHOSTCOMPONANTS),
TOKEN(HIDEHOSTCOMPONENTS),
TOKEN(AUTOJOINCHANNEL),
TOKEN(AUTOJOINNOTICE),
TOKEN(AUTHEXEMPT),
TOKEN(MARK),
TOKEN(RESTRICT_JOIN),
TOKEN(RESTRICT_PRIVMSG),
TOKEN(RESTRICT_UMODE),
TOKEN(MATCHUSERNAME),
TOKEN(FAKELAGMINIMUM),
TOKEN(FAKELAGFACTOR),
TOKEN(DEFAULTTEXT),
TOKEN(SSLFP),
TOKEN(SSLCIPHERS),
TOKEN(INCLUDE),
TOKEN(SWHOIS),
TOKEN(ENABLEOPTIONS),
TOKEN(TRUSTACCOUNT),
#undef TOKEN
{ "ssl", SSLTOK },
{ "administrator", ADMIN },
{ "apass_opmode", TPRIV_APASS_OPMODE },
{ "auto", AUTOCONNECT },
{ "b", BYTES },
{ "badchan", TPRIV_BADCHAN },
{ "chan_limit", TPRIV_CHAN_LIMIT },
{ "check", TPRIV_CHECK },
{ "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 },
{ "freeform", TPRIV_FREEFORM },
{ "gb", GBYTES },
{ "gigabytes", GBYTES },
{ "hide_channels", TPRIV_HIDE_CHANNELS },
{ "hide_idle", TPRIV_HIDE_IDLE },
{ "hide_oper", TPRIV_HIDE_OPER },
{ "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 },
{ "local_shun", TPRIV_LOCAL_SHUN },
{ "local_zline", TPRIV_LOCAL_ZLINE },
{ "mb", MBYTES },
{ "megabytes", MBYTES },
{ "mode_lchan", TPRIV_MODE_LCHAN },
{ "operator", OPER },
{ "opmode", TPRIV_OPMODE },
{ "password", PASS },
{ "propagate", TPRIV_PROPAGATE },
{ "realname", REAL },
{ "rehash", TPRIV_REHASH },
{ "remote", TPRIV_REMOTE },
{ "remoterehash", TPRIV_REMOTEREHASH },
{ "remove", TPRIV_REMOVE },
{ "restart", TPRIV_RESTART },
{ "see_chan", TPRIV_SEE_CHAN },
{ "see_opers", TPRIV_SEE_OPERS },
{ "service", TPRIV_SERVICE },
{ "set", TPRIV_SET },
{ "show_all_invis", TPRIV_SHOW_ALL_INVIS },
{ "show_invis", TPRIV_SHOW_INVIS },
{ "tb", TBYTES },
{ "terabytes", TBYTES },
{ "tempshun", TPRIV_TEMPSHUN },
{ "unlimit_query", TPRIV_UNLIMIT_QUERY },
{ "walk_lchan", TPRIV_WALK_LCHAN },
{ "wide_gline", TPRIV_WIDE_GLINE },
{ "wide_shun", TPRIV_WIDE_SHUN },
{ "wide_zline", TPRIV_WIDE_ZLINE },
{ "whois_notice", TPRIV_WHOIS_NOTICE },
{ "whox", TPRIV_WHOX },
{ "xtraop", TPRIV_XTRAOP },
{ 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;
}
struct include_state {
int lineno;
char* linefile;
FBFILE* lexer_input;
};
static FBFILE *lexer_input;
#define MAX_INCLUDE_DEPTH 10
struct include_state include_stack[MAX_INCLUDE_DEPTH];
int include_stack_ptr = 0;
#undef YY_NO_UNPUT
#define YY_NO_UNPUT
#undef YY_INPUT
#define YY_INPUT(buf, res, size) res = (fbgets(buf, size, lexer_input) ? strlen(buf) : 0)
int
init_lexer(void)
{
include_stack_ptr = 0;
lexer_input = fbopen(configfile, "r");
if (lexer_input == NULL)
{
#ifdef YY_FATAL_ERROR
YY_FATAL_ERROR("Could not open the configuration file.");
#else
fprintf(stderr, "Could not open the configuration file.");
#endif
return 0;
}
#ifdef YY_NEW_FILE
YY_NEW_FILE;
#endif
lineno = 1;
linefile = strdup(configfile);
return 1;
}
void deinit_lexer(void)
{
if (lexer_input != NULL)
{
fbclose(lexer_input);
if (linefile != NULL)
free(linefile);
linefile = NULL;
lexer_input = NULL;
}
}
int
init_lexer_file(char* file)
{
static char error_buffer[1024];
if (include_stack_ptr >= MAX_INCLUDE_DEPTH)
{
snprintf((char *)&error_buffer, 1024, "Cannot include %s: Includes nested too deeply", file);
yyerror(error_buffer);
return 0;
}
include_stack[include_stack_ptr].lineno = lineno;
include_stack[include_stack_ptr].linefile = linefile;
include_stack[include_stack_ptr++].lexer_input = lexer_input;
lexer_input = fbopen(file, "r");
if (lexer_input == NULL)
{
snprintf((char *)&error_buffer, 1024, "Cannot include %s: %s", file, strerror(errno));
yyerror(error_buffer);
lexer_input = include_stack[--include_stack_ptr].lexer_input;
return 0;
}
#ifdef YY_NEW_FILE
YY_NEW_FILE;
#endif
lineno = 1;
linefile = strdup(file);
return 1;
}
int next_lexer_file(void)
{
if (--include_stack_ptr < 0)
return 1;
if (lexer_input != NULL)
fbclose(lexer_input);
lexer_input = NULL;
if (linefile != NULL)
free(linefile);
linefile = NULL;
lineno = include_stack[include_stack_ptr].lineno;
linefile = include_stack[include_stack_ptr].linefile;
lexer_input = include_stack[include_stack_ptr].lexer_input;
return 0;
}
int
yywrap(void)
{
return next_lexer_file();
}
%}
WHITE [ \t\r]+
SHCOMMENT #[^\n]*
NUMBER [0-9]+
QSTRING \"[^"\n]+[\"\n]
%%
{QSTRING} {yytext[yyleng-1] = 0; DupString(yylval.text, yytext+1); return QSTRING;}
{NUMBER} {yylval.num = strtoul(yytext, NULL, 10); return NUMBER;}
{WHITE} ;
{SHCOMMENT} ;
[a-zA-Z_][a-zA-Z_0-9]* { int res = find_token(yytext); if (res) return res; else REJECT; }
\n lineno++;
. return yytext[0];