head 1.13; access; symbols L2_0_9_13:1.13 FSL_1_7_0:1.13 L2_0_9_12:1.13 LMTP2NNTP_1_4_1:1.13 LMTP2NNTP_1_4_0:1.13 FSL_1_6_1:1.13 L2_0_9_11:1.13 FSL_1_6_0:1.12 FSL_1_6b2:1.12 L2_0_9_10:1.12 FSL_1_6b1:1.12 L2_0_9_9:1.12 LMTP2NNTP_1_3_0:1.11 LMTP2NNTP_1_3b2:1.11 LMTP2NNTP_1_3b1:1.11 LMTP2NNTP_1_3a3:1.11 FSL_1_5_0:1.11 LMTP2NNTP_1_3a2:1.11 FSL_1_5a3:1.11 LMTP2NNTP_1_3a1:1.11 FSL_1_5a2:1.11 L2_0_9_8:1.11 FSL_1_5a1:1.11 L2_0_9_7:1.11 L2_0_9_6:1.11 FSL_1_4_0:1.11 FSL_1_4b1:1.11 L2_0_9_5:1.11 FSL_1_4a1:1.11 FSL_1_3_0:1.11 FSL_1_3b1:1.11 L2_0_9_4:1.11 FSL_1_2_1:1.11 L2_0_9_3:1.11 FSL_1_2_0:1.11 L2_0_9_2:1.11 FSL_1_1_0:1.11 FSL_1_1b1:1.11 WORKOFF:1.11.0.2 WORKOFF_BP:1.11 FSL_1_0_8:1.11 LMTP2NNTP_1_2_0:1.11 LMTP2NNTP_1_2b4:1.11 LMTP2NNTP_1_2b3:1.11 LMTP2NNTP_1_2b2:1.11 LMTP2NNTP_1_2b1:1.10 LMTP2NNTP_1_2a8:1.10 LMTP2NNTP_1_2a7:1.10 FSL_1_0_7:1.10 FSL_1_0_6:1.8 FSL_1_0_5:1.8 FSL_1_0_4:1.8 L2_0_9_1:1.8 FSL_1_0_3:1.8 LMTP2NNTP_1_2a6:1.8 FSL_1_0_2:1.8 FSL_1_0_1:1.8 FSL_1_0_0:1.8 FSL_0_9_0:1.8 L2_0_9_0:1.8 FSL_0_1_12:1.7 FSL_0_1_11:1.7 FSL_0_1_10:1.7 FSL_0_1_9:1.7 FSL_0_1_8:1.7 FSL_0_1_7:1.7 FSL_0_1_6:1.7 FSL_0_1_5:1.7 FSL_0_1_1:1.6 LMTP2NNTP_1_2a5:1.6 LMTP2NNTP_1_2a4:1.6 LMTP2NNTP_1_2a3:1.6 LMTP2NNTP_1_2a1:1.4; locks; strict; comment @ * @; 1.13 date 2005.10.03.08.08.11; author rse; state Exp; branches; next 1.12; 1.12 date 2005.01.24.15.03.18; author rse; state Exp; branches; next 1.11; 1.11 date 2003.02.11.07.51.27; author rse; state Exp; branches; next 1.10; 1.10 date 2003.01.06.11.41.52; author rse; state Exp; branches; next 1.9; 1.9 date 2003.01.06.11.19.45; author rse; state Exp; branches; next 1.8; 1.8 date 2002.07.30.19.08.25; author rse; state Exp; branches; next 1.7; 1.7 date 2002.07.25.09.13.13; author rse; state Exp; branches; next 1.6; 1.6 date 2002.01.02.17.07.38; author rse; state Exp; branches; next 1.5; 1.5 date 2001.12.14.12.42.07; author rse; state Exp; branches; next 1.4; 1.4 date 2001.11.08.21.58.00; author rse; state Exp; branches; next 1.3; 1.3 date 2001.11.08.09.28.35; author rse; state Exp; branches; next 1.2; 1.2 date 2001.11.07.17.01.05; author rse; state Exp; branches; next 1.1; 1.1 date 2001.11.07.16.17.09; author rse; state Exp; branches; next ; desc @@ 1.13 log @Adjust copyright messages for new year 2005. @ text @%{ /* ** OSSP l2 - Flexible Logging ** Copyright (c) 2001-2005 Cable & Wireless ** Copyright (c) 2001-2005 The OSSP Project ** Copyright (c) 2001-2005 Ralf S. Engelschall ** ** This file is part of OSSP l2, a flexible logging library which ** can be found at http://www.ossp.org/pkg/lib/l2/. ** ** Permission to use, copy, modify, and distribute this software for ** any purpose with or without fee is hereby granted, provided that ** the above copyright notice and this permission notice appear in all ** copies. ** ** THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED ** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF ** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ** IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR ** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF ** USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, ** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ** OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ** SUCH DAMAGE. ** ** l2_spec_parse.y: GNU Bison (Yacc-style) parser specification ** ** ATTENTION: This requires GNU Bison 1.875 or newer! */ #include "l2.h" /* for l2_xxx() API */ #include "l2_spec.h" /* for l2_spec_ctx_t */ /* make sure yyparse() accepts a context pointer and passes through its inlined scanner context to yylex() */ #define CTX ((l2_spec_ctx_t *)ctx) #define YYPARSE_PARAM ctx #define YYLEX_PARAM CTX->yyscan /* provide an explicit prototype for the yylex() function but use "void *" instead of correct type because at this point in the generation process we have the types still not available */ extern int yylex(/*YYSTYPE*/ void *lvalp, /*YYLTYPE*/ void *llocp, l2_spec_ctx_t *ctx); /* generate verbose error messages and remember them inside the context */ #undef yyerror #define yyerror(msg) \ l2_spec_error(CTX, L2_ERR_SYN, &yylloc, msg) /* scanner state transition */ extern void l2_spec_scan_push(l2_spec_ctx_t *, const char *state); extern void l2_spec_scan_pop(l2_spec_ctx_t *); %} /* parser options */ %error-verbose %pure_parser %locations %defines /* the YYSTYPE: parser token value */ %union { char *cpValue; l2_channel_t *chChannel; unsigned int nLevels; } /* assign YYSTYPE elements to parser rules */ %type stream %type streams %type channel %type channel_cons %type channel_level %type channel_level_mask /* list of scanner tokens */ %token T_ID %token T_PARAM %token T_STRING %token T_OP_ARROW /* operator association */ %right T_OP_ARROW /* grammar start rule (technically redundant but explicit to be sure) */ %start tree %% /* channel tree */ tree : stream { CTX->ch = $1; } ; /* stream of channels */ stream : /* empty */ { l2_channel_t *ch; if ((CTX->rv = l2_channel_create(&ch, CTX->env, "null")) != L2_OK) { l2_spec_error(CTX, CTX->rv, &yylloc, "failed to create channel 'null'"); YYERROR; } $$ = ch; } | channel { $$ = $1; } | channel T_OP_ARROW stream { $$ = $1; if ((CTX->rv = l2_channel_link($1, L2_LINK_CHILD, $3, NULL)) != L2_OK) { l2_spec_error(CTX, CTX->rv, &yylloc, "unable to link parent with child"); YYERROR; } } | channel T_OP_ARROW '{' streams '}' { $$ = $1; if ((CTX->rv = l2_channel_link($1, L2_LINK_CHILD, $4, NULL)) != L2_OK) { l2_spec_error(CTX, CTX->rv, &yylloc, "unable to link parent with child list"); YYERROR; } } ; /* list of sibling streams */ streams : stream { $$ = $1; } | stream ';' streams { $$ = $1; if ((CTX->rv = l2_channel_link($1, L2_LINK_SIBLING, $3, NULL)) != L2_OK) { l2_spec_error(CTX, CTX->rv, &yylloc, "unable to link childs together"); YYERROR; } } ; /* channel */ channel : channel_level '/' channel_level ':' channel_cons { $$ = $5; if ((CTX->rv = l2_channel_levels($5, $1, $3)) != L2_OK) { l2_spec_error(CTX, CTX->rv, &yylloc, "failed to set channel write and flush levels"); YYERROR; } } | channel_level ':' channel_cons { $$ = $3; if ((CTX->rv = l2_channel_levels($3, $1, L2_LEVEL_NONE)) != L2_OK) { l2_spec_error(CTX, CTX->rv, &yylloc, "failed to set channel write levels"); YYERROR; } } | channel_cons { $$ = $1; } ; /* channel level */ channel_level : T_ID { unsigned int levelmask; if ((CTX->rv = l2_util_s2l($1, strlen($1), ',', &levelmask)) != L2_OK) { l2_spec_error(CTX, CTX->rv, &yylloc, "invalid level '%s'", $1); free($1); YYERROR; } free($1); $$ = L2_LEVEL_UPTO(levelmask); } | '(' channel_level_mask ')' { $$ = $2; } ; /* channel level mask */ channel_level_mask : T_ID { unsigned int levelmask; if ((CTX->rv = l2_util_s2l($1, strlen($1), ',', &levelmask)) != L2_OK) { l2_spec_error(CTX, CTX->rv, &yylloc, "invalid level '%s'", $1); free($1); YYERROR; } free($1); $$ = levelmask; } | T_ID '|' channel_level_mask { unsigned int levelmask; if ((CTX->rv = l2_util_s2l($1, strlen($1), ',', &levelmask)) != L2_OK) { l2_spec_error(CTX, CTX->rv, &yylloc, "invalid level '%s'", $1); free($1); YYERROR; } free($1); $$ = levelmask | $3; } ; /* channel constructor */ channel_cons : T_ID { l2_channel_t *ch; if ((CTX->rv = l2_channel_create(&ch, CTX->env, $1)) != L2_OK) { l2_spec_error(CTX, CTX->rv, &yylloc, "failed to create channel '%s'", $1); free($1); YYERROR; } free($1); $$ = ch; /* provide channel to channel_param rule below because it does not know where on the token stack our $$ is because it is a sub-rule of the recursive channel_param_list rule and hence cannot use "$-n". */ CTX->chTmp = ch; } channel_params { $$ = $2; /* pass-through result */ CTX->chTmp = NULL; } ; /* channel parameters */ channel_params : /* empty */ | '(' ')' | '(' channel_param_list ')' ; /* channel parameter list */ channel_param_list : channel_param | channel_param ',' channel_param_list ; /* channel parameter */ channel_param : T_ID '=' { l2_spec_scan_push(CTX, "SS_PARAM"); } T_PARAM { l2_spec_scan_pop(CTX); } { if ((CTX->rv = l2_channel_configure(CTX->chTmp, "%s=\"%s\"", $1, $4)) != L2_OK) { l2_spec_error(CTX, CTX->rv, &yylloc, "failed to configure channel with '%s=\"%s\"'", $1, $4); free($1); free($4); YYERROR; } free($1); free($4); } ; %% @ 1.12 log @Adjust copyright messages for new year 2005. @ text @d4 3 a6 3 ** Copyright (c) 2001-2004 Cable & Wireless ** Copyright (c) 2001-2004 The OSSP Project ** Copyright (c) 2001-2004 Ralf S. Engelschall @ 1.11 log @fix all dmalloc-detected memory leaks @ text @d4 3 a6 3 ** Copyright (c) 2001-2003 Cable & Wireless Deutschland GmbH ** Copyright (c) 2001-2003 The OSSP Project (http://www.ossp.org/) ** Copyright (c) 2001-2003 Ralf S. Engelschall @ 1.10 log @- remove trailing whitespaces - adjust copyright messages - consistently use "OSSP l2" - consistently talk about "Flexible Logging" - use standard OSSP ASCII-art @ text @d172 1 d175 1 d189 1 d192 1 d199 1 d202 1 d213 1 d216 1 d248 2 d252 2 @ 1.9 log @upgrade to the latest Flex & Bison & Autoconf combo @ text @d3 4 a6 3 ** OSSP l2 - Logging Library ** Copyright (c) 2001-2002 The OSSP Project (http://www.ossp.org/) ** Copyright (c) 2001-2002 Cable & Wireless Deutschland (http://www.cw.com/de/) d8 1 a8 1 ** This file is part of OSSP L2, a flexible logging library which d43 2 a44 2 /* provide an explicit prototype for the yylex() function but use "void *" instead of correct type because at this point in the d46 1 a46 1 extern int yylex(/*YYSTYPE*/ void *lvalp, d89 1 a89 1 /* grammar start rule d97 1 a97 1 : stream { d100 1 a100 1 ; d112 2 a113 2 | channel { $$ = $1; d115 2 a116 2 | channel T_OP_ARROW stream { $$ = $1; d122 2 a123 2 | channel T_OP_ARROW '{' streams '}' { $$ = $1; d133 2 a134 2 : stream { $$ = $1; d136 2 a137 2 | stream ';' streams { $$ = $1; d147 2 a148 2 : channel_level '/' channel_level ':' channel_cons { $$ = $5; d154 2 a155 2 | channel_level ':' channel_cons { $$ = $3; d161 1 a161 1 | channel_cons { d168 1 a168 1 : T_ID { d176 2 a177 2 | '(' channel_level_mask ')' { $$ = $2; d182 2 a183 2 channel_level_mask : T_ID { d191 1 a191 1 | T_ID '|' channel_level_mask { d197 1 a197 1 $$ = levelmask | $3; d202 2 a203 2 channel_cons : T_ID { d214 1 a214 1 CTX->chTmp = ch; d216 1 a216 1 channel_params { d223 1 a223 1 channel_params d230 1 a230 1 channel_param_list d234 1 a234 1 d236 2 a237 2 channel_param : T_ID '=' { l2_spec_scan_push(CTX, "SS_PARAM"); } T_PARAM { l2_spec_scan_pop(CTX); } { d244 1 a244 1 @ 1.8 log @polish for release @ text @d30 1 a30 1 ** ATTENTION: This requires GNU Bison 1.30 or newer! a51 1 #define YYERROR_VERBOSE d59 1 @ 1.7 log @allow empty stream (means a 'null' channel) @ text @d3 1 a3 1 ** L2 - OSSP Logging Library d8 1 a8 1 ** can be found at http://www.ossp.org/pkg/l2/. @ 1.6 log @bump copyright year @ text @d103 9 a111 1 : channel { @ 1.5 log @Whoohooo! Add support for location tracking. This way the reported errors contain line, column, context and found/expected information. Now the specification parser is full featured... @ text @d4 2 a5 2 ** Copyright (c) 2001 The OSSP Project (http://www.ossp.org/) ** Copyright (c) 2001 Cable & Wireless Deutschland (http://www.cw.com/de/) @ 1.4 log @Enhance the specification parser to be more smart in parsing parameter values in order to remove the burden on the user to provide massive syntactic sugar. One now can name=value or name="value" or even name=va"lu"e, i.e., do not require quotation marks. But if they are present they can be used to introduce spaces or special characters with \xXX notation. @ text @d51 1 a51 2 do { l2_env_errorinfo(CTX->env, L2_ERR_ARG, "%s", msg); \ CTX->rv = L2_ERR_ARG; } while (0) d109 1 a109 1 l2_env_errorinfo(CTX->env, CTX->rv, "unable to link parent with child"); d116 1 a116 1 l2_env_errorinfo(CTX->env, CTX->rv, "unable to link parent with child list"); d130 1 a130 1 l2_env_errorinfo(CTX->env, CTX->rv, "unable to link childs together"); d141 1 a141 1 l2_env_errorinfo(CTX->env, CTX->rv, "failed to set channel write and flush levels"); d148 1 a148 1 l2_env_errorinfo(CTX->env, CTX->rv, "failed to set channel write levels"); d162 1 a162 1 l2_env_errorinfo(CTX->env, CTX->rv, "invalid level '%s'", $1); d177 1 a177 1 l2_env_errorinfo(CTX->env, CTX->rv, "invalid level '%s'", $1); d185 1 a185 1 l2_env_errorinfo(CTX->env, CTX->rv, "invalid level '%s'", $1); d197 1 a197 1 l2_env_errorinfo(CTX->env, CTX->rv, "failed to create channel '%s'", $1); d216 1 d222 1 a222 2 : /* empty */ | channel_param d230 1 a230 1 l2_env_errorinfo(CTX->env, CTX->rv, "failed to configure channel with '%s=\"%s\"'", $1, $4); @ 1.3 log @code cleanups and documentation @ text @d54 4 d82 1 d229 3 a231 3 : T_ID '=' T_STRING { if ((CTX->rv = l2_channel_configure(CTX->chTmp, "%s=\"%s\"", $1, $3)) != L2_OK) { l2_env_errorinfo(CTX->env, CTX->rv, "failed to configure channel with '%s=\"%s\"'", $1, $3); @ 1.2 log @more cleanups @ text @d56 1 a56 1 /* parser options */ d61 1 a61 1 /* the YYSTYPE: parser token value */ d68 1 a68 1 /* assign YYSTYPE elements to parser rules */ d72 3 a74 3 %type channel_spec %type channel_mask %type channel_levels d76 1 a76 1 /* list of scanner tokens */ d81 1 a81 1 /* operator association */ d84 2 a85 1 /* grammar start rule */ d90 131 a220 113 /* channel tree */ tree : stream { CTX->ch = $1; } ; /* stream of channels */ stream : channel { $$ = $1; } | channel T_OP_ARROW stream { $$ = $1; if ((CTX->rv = l2_channel_link($1, L2_LINK_CHILD, $3, NULL)) != L2_OK) { l2_env_errorinfo(CTX->env, CTX->rv, "unable to link parent with child"); YYERROR; } } | channel T_OP_ARROW '{' streams '}' { $$ = $1; if ((CTX->rv = l2_channel_link($1, L2_LINK_CHILD, $4, NULL)) != L2_OK) { l2_env_errorinfo(CTX->env, CTX->rv, "unable to link parent with child list"); YYERROR; } } ; /* list of sibling streams */ streams : stream { $$ = $1; } | stream ';' streams { $$ = $1; l2_channel_link($1, L2_LINK_SIBLING, $3, NULL); } ; /* single channel */ channel : channel_mask '/' channel_mask ':' channel_spec { $$ = $5; l2_channel_levels($5, $1, $3); } | channel_mask ':' channel_spec { $$ = $3; l2_channel_levels($3, $1, L2_LEVEL_NONE); } | channel_spec { $$ = $1; } ; /* channel write or flush mask */ channel_mask : T_ID { unsigned int levelmask; if ((CTX->rv = l2_util_s2l($1, strlen($1), ',', &levelmask)) != L2_OK) { l2_env_errorinfo(CTX->env, CTX->rv, "invalid level '%s'", $1); YYERROR; } $$ = L2_LEVEL_UPTO(levelmask); } | '(' channel_levels ')' { $$ = $2; } ; /* list of channels in a mask */ channel_levels : T_ID { unsigned int levelmask; if ((CTX->rv = l2_util_s2l($1, strlen($1), ',', &levelmask)) != L2_OK) { l2_env_errorinfo(CTX->env, CTX->rv, "invalid level '%s'", $1); YYERROR; } $$ = levelmask; } | T_ID '|' channel_levels { unsigned int levelmask; if ((CTX->rv = l2_util_s2l($1, strlen($1), ',', &levelmask)) != L2_OK) { l2_env_errorinfo(CTX->env, CTX->rv, "invalid level '%s'", $1); YYERROR; } $$ = levelmask | $3; } ; /* specifcation of a single channel */ channel_spec : T_ID { l2_channel_t *ch; if ((CTX->rv = l2_channel_create(&ch, CTX->env, $1)) != L2_OK) { l2_env_errorinfo(CTX->env, CTX->rv, "failed to create channel '%s'", $1); YYERROR; } $$ = ch; /* provide channel to channel_param rule below because it does not know where on the token stack our $$ is because it is a sub-rule of the recursive channel_param_list rule and hence cannot use "$-n". */ CTX->chTmp = ch; } channel_params { $$ = $2; /* pass result */ CTX->chTmp = NULL; } ; /* channel parameters */ channel_params : /* empty */ | '(' channel_param_list ')' ; channel_param_list : /* empty */ | channel_param | channel_param ',' channel_param_list ; d222 9 a230 8 channel_param : T_ID '=' T_STRING { if ((CTX->rv = l2_channel_configure(CTX->chTmp, "%s=\"%s\"", $1, $3)) != L2_OK) { l2_env_errorinfo(CTX->env, CTX->rv, "failed to configure channel with '%s=\"%s\"'", $1, $3); YYERROR; } } ; @ 1.1 log @HEADS UP, guys: Here comes the first cut for the long-awaited channel tree specification parser and channel tree builder. This certainly makes L2 finally _THE_ killer library in the logging field. Woohooo... and the crowd goes wild! It allows one to build an arbitrary complex logging channel tree out of a single textual specification. An example follows: noop -> { prefix(prefix="[%d-%m-%Y/%H:%M:%S] %L test[%P]: ", timezone="local") -> filter(regex="hecking", negate="0") -> buffer(size="800") -> file(path="l2_test.log",append="1",perm="420"); error: syslog(ident="L2-Test", facility="user", remotehost="en1", logpid="1", target="remote"); panic: smtp(rcpt="rse@@engelschall.com", host="en1", port="25" } This allows one to log nice timestamp-prefixed messages containing the word "hecking" to a buffered file. Additionally if the message has a level higher or equal to "error" it also logs it remotely via UDP to the syslogd on en1. And additionally if the message is a panic message, it is also sent out as an Email via SMTP to the MTA on en1. Ever thought a C library has to be dull and simple? ;) PS: This stuff certainly needs more polishing and cleanup and also a few things I'll enhance in the future (for instance to remove the restriction that parameter values have to be in quotation marks, etc.). @ text @d33 1 a33 2 #include "l2.h" /* for l2_xxx() */ #include "l2_p.h" /* for l2_channel_t and l2_env_t internals */ d42 3 a44 1 /* provide an explicit prototype for the yylex() function */ d51 2 a52 4 do { \ l2_env_errorinfo(CTX->env, L2_ERR_ARG, "%s", msg); \ CTX->rv = L2_ERR_ARG; \ } while (0) a53 2 #define YYDEBUG 1 d56 1 d61 1 d68 12 a79 6 %type stream %type streams %type channel %type channel_spec %type channel_mask %type channel_levels d81 2 a82 2 %token T_ID %token T_STRING d84 2 a85 2 %token T_OP_ARROW %left T_OP_ARROW d89 2 a90 1 root : stream d94 1 d103 1 a103 3 l2_env_errorinfo(CTX->env, CTX->rv, "unable to link parent '%s' with child '%s'", $1->handler.name, $3->handler.name); d111 1 a111 3 l2_env_errorinfo(CTX->env, CTX->rv, "unable to link parent '%s' with child list", $1->handler.name); d117 1 d124 1 d133 1 d144 3 a146 1 { $$ = $2; } d149 1 d170 1 d188 1 a188 1 $$ = $2; d193 1 @