%x incl
%x module
%x lua

%{

#define NO_GMIME
#include "config.h"
#include "cfg_file.h"
#include "cfg_yacc.h"
#ifdef WITH_LUA
#include "lua.h"
#else 
#define add_luabuf(x) yyerror ("lua support diabled")
#endif

#define MAX_INCLUDE_DEPTH 10
YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH];
int line_stack[MAX_INCLUDE_DEPTH];
int include_stack_ptr = 0;
extern struct config_file *cfg;

%}

%option noyywrap
%option yylineno

%%
[ \t]*#.*						/* ignore comments */;
.include						BEGIN(incl);
.module							BEGIN(module);
.lua							BEGIN(lua);
composites						return COMPOSITES;
tempdir							return TEMPDIR;
pidfile							return PIDFILE;
workers							return WORKERS;
error_time                      return ERROR_TIME;
dead_time                       return DEAD_TIME;
maxerrors                       return MAXERRORS;
reconnect_timeout				return RECONNECT_TIMEOUT;
connect_timeout					return CONNECT_TIMEOUT;
protocol						return PROTOCOL;
memcached						return MEMCACHED;
bind_socket						return BINDSOCK;
servers							return SERVERS;
require							return REQUIRE;
header_filters					return HEADER_FILTERS;
mime_filters					return MIME_FILTERS;
message_filters					return MESSAGE_FILTERS;
url_filters						return URL_FILTERS;
factors							return FACTORS;
metric							return METRIC;
name							return NAME;
required_score					return REQUIRED_SCORE;
function						return FUNCTION;
control							return CONTROL;
password						return PASSWORD;
lmtp							return LMTP;
enabled							return ENABLED;
delivery						return DELIVERY;
agent							return AGENT;

statfile						return STATFILE;
alias							return ALIAS;
pattern							return PATTERN;
weight							return WEIGHT;
size							return SIZE;
tokenizer						return TOKENIZER;
classifier						return CLASSIFIER;
section							return SECTION;

logging							return LOGGING;

log_type						return LOG_TYPE;
console							return LOG_TYPE_CONSOLE;
syslog							return LOG_TYPE_SYSLOG;
file							return LOG_TYPE_FILE;

log_level						return LOG_LEVEL;
DEBUG							return LOG_LEVEL_DEBUG;
INFO							return LOG_LEVEL_INFO;
WARNING							return LOG_LEVEL_WARNING;
ERROR							return LOG_LEVEL_ERROR;
log_facility					return LOG_FACILITY;
log_file						return LOG_FILENAME;

statfile_pool_size				return STATFILE_POOL_SIZE;

\{								return OBRACE;
\}								return EBRACE;
;								return SEMICOLON;
,								return COMMA;
=								return EQSIGN;
yes|YES|no|NO|[yY]|[nN]			yylval.flag=parse_flag(yytext); return FLAG;
\n								/* ignore EOL */;
[ \t]+							/* ignore whitespace */;
\".+[^\\]\"						yylval.string=strdup(yytext + 1); yylval.string[strlen(yylval.string) - 1] = '\0'; unescape_quotes(yylval.string); return QUOTEDSTRING;
\"								return QUOTE;
\$[a-zA-Z_][a-zA-Z0-9_]+		yylval.string=strdup(yytext + 1); return VARIABLE;
[0-9]+							yylval.number=strtol(yytext, NULL, 10); return NUMBER;
-?[0-9]+\.?[0-9]*				yylval.fract=strtod(yytext, NULL); return FRACT;
[0-9]+[kKmMgG]?					yylval.limit=parse_limit(yytext); return SIZELIMIT;
[0-9]+[sS]|[0-9]+[mM][sS]		yylval.seconds=parse_seconds(yytext); return SECONDS;
[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}	yylval.string=strdup(yytext); return IPADDR;
[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\/[0-9]{1,2}	yylval.string=strdup(yytext); return IPNETWORK;
[a-zA-Z0-9.-]+:[0-9]{1,5}		yylval.string=strdup(yytext); return HOSTPORT;
[a-zA-Z<][a-zA-Z@+>_-]*         yylval.string=strdup(yytext); return STRING;
\/[^/\n]+\/						yylval.string=strdup(yytext); return REGEXP;
[a-zA-Z0-9].[a-zA-Z0-9\/.-]+	yylval.string=strdup(yytext); return DOMAINNAME;
<incl>[ \t]*      /* eat the whitespace */
<incl>[^ \t\n]+   { /* got the include file name */
		/* got the include file name */
		if ( include_stack_ptr >= MAX_INCLUDE_DEPTH ) {
			yyerror ("yylex: includes nested too deeply" );
			return -1;
		}

		line_stack[include_stack_ptr] = yylineno;
		include_stack[include_stack_ptr++] = YY_CURRENT_BUFFER;

		yylineno = 1;
		yyin = fopen (yytext, "r");

		if (!yyin) {
			yyerror ("yylex: cannot open include file");
			return -1;
		}

		yy_switch_to_buffer (yy_create_buffer (yyin, YY_BUF_SIZE));

		BEGIN(INITIAL);
}

<<EOF>> {
		if ( --include_stack_ptr < 0 ) {
			include_stack_ptr = 0;
			yylineno = 1;
			post_load_config (cfg);
			yyterminate ();
		}
		else {
			yy_delete_buffer (YY_CURRENT_BUFFER);
			yy_switch_to_buffer (include_stack[include_stack_ptr] );
			yylineno = line_stack[include_stack_ptr];
		}
}

<module>\n								/* ignore EOL */;
<module>[ \t]+							/* ignore whitespace */;
<module>[ \t]*#.*						/* ignore comments */;
<module>\'[a-zA-Z0-9_-]+\'	yylval.string=strdup(yytext + 1); yylval.string[strlen(yylval.string) - 1] = '\0'; return MODULE_OPT; 
<module>\{	return OBRACE;
<module>\}  BEGIN(INITIAL); return EBRACE;
<module>\;	return SEMICOLON;
<module>=	return EQSIGN;
<module>[a-zA-Z0-9_%-]+	yylval.string=strdup(yytext); return PARAM;
<module>\$[a-zA-Z_][a-zA-Z0-9_]+		yylval.string=strdup(yytext + 1); return VARIABLE;
<module>\".+[^\\]\"	yylval.string=strdup(yytext + 1); yylval.string[strlen(yylval.string) - 1] = '\0'; unescape_quotes(yylval.string); return QUOTEDSTRING;

<lua>\n									/* ignore EOL */;
<lua>[ \t]+								/* ignore whitespace */;
<lua>[ \t]*#.*							/* ignore comments */;
<lua>^.endlua$							BEGIN(INITIAL);
<lua>.*									add_luabuf(yytext); return LUACODE;

%%
/* 
 * vi:ts=4 
 */