Index: ossp-pkg/l2/.cvsignore RCS File: /v/ossp/cvs/ossp-pkg/l2/.cvsignore,v rcsdiff -q -kk '-r1.10' '-r1.11' -u '/v/ossp/cvs/ossp-pkg/l2/.cvsignore,v' 2>/dev/null --- .cvsignore 2001/09/15 16:03:37 1.10 +++ .cvsignore 2001/11/07 16:17:09 1.11 @@ -20,3 +20,6 @@ l2_ut_pcre.gen l2_ut_pcre.tab l2.h +l2_spec_parse.c +l2_spec_parse.h +l2_spec_scan.c Index: ossp-pkg/l2/Makefile.in RCS File: /v/ossp/cvs/ossp-pkg/l2/Makefile.in,v rcsdiff -q -kk '-r1.29' '-r1.30' -u '/v/ossp/cvs/ossp-pkg/l2/Makefile.in,v' 2>/dev/null --- Makefile.in 2001/11/05 20:39:35 1.29 +++ Makefile.in 2001/11/07 16:17:09 1.30 @@ -53,6 +53,8 @@ RMDIR = rmdir POD2MAN = pod2man TRUE = true +BISON = bison +FLEX = flex SHTOOL = ./shtool LIBTOOL = ./libtool @@ -83,6 +85,9 @@ l2_ut_level.lo \ l2_ut_fmtcb.lo \ l2_ut_sa.lo \ + l2_spec.lo \ + l2_spec_scan.lo \ + l2_spec_parse.lo \ l2_version.lo # list of source files @@ -159,6 +164,14 @@ ./l2_ut_pcre.gen >l2_ut_pcre.tab -$(RM) l2_ut_pcre.gen +# build specification parser/scanner +l2_spec.c: l2_spec.h l2_spec_parse.h +l2_spec_scan.lo: l2_spec_scan.c l2_spec_parse.h +l2_spec_scan.c: l2_spec_scan.l + $(FLEX) -f -Pl2_spec_ -s -8 -B -ol2_spec_scan.c l2_spec_scan.l +l2_spec_parse.c l2_spec_parse.h: l2_spec_parse.y + $(BISON) -d -k -pl2_spec_ -ol2_spec_parse.c l2_spec_parse.y + # build test suite programs l2_test: l2_test.o libl2.la $(LIBTOOL) --mode=link --quiet $(CC) $(LDFLAGS) -o l2_test l2_test.o libl2.la $(LIBS) @@ -240,6 +253,8 @@ -$(RMDIR) .libs >/dev/null 2>&1 || $(TRUE) $(RM) $(TARGET_LIBS) $(RM) $(TARGET_TESTS) + $(RM) l2_spec_scan.c # FIXME: remove later + $(RM) l2_spec_parse.c l2_spec_parse.h # FIXME: remove later # remove everything which can be regenerated # by "./configure && make all" @@ -264,6 +279,8 @@ $(RM) l2_config.h.in $(RM) l2.3 $(RM) l2++.3 + $(RM) l2_spec_scan.c + $(RM) l2_spec_parse.c l2_spec_parse.h # roll a distribution tarball dist: distclean Index: ossp-pkg/l2/TODO RCS File: /v/ossp/cvs/ossp-pkg/l2/TODO,v rcsdiff -q -kk '-r1.38' '-r1.39' -u '/v/ossp/cvs/ossp-pkg/l2/TODO,v' 2>/dev/null --- TODO 2001/11/07 09:28:45 1.38 +++ TODO 2001/11/07 16:17:09 1.39 @@ -2,6 +2,11 @@ OSSP L2 ======= +Spec-Parsing: +- location tracking +- target=remote has to be currently after host=xxx because of + single-configuration procedure + Channel-Only Revamping: - syscall override ala OSSP SA in l2_env_t - l2_objects.fig update @@ -376,41 +381,3 @@ error:syslog } -Grammar -======= - -hierarchy : stream - | '{' stream_list '}' - ; - -stream_list : hierarchy - | hierarchy ';' stream_list - ; - -stream : channel - | channel "->" hierarchy - ; - -channel : channel_mask ':' channel_spec - | channel_spec - ; - -channel_mask : T_ID_LEVEL - | '(' channel_levels ')' - ; - -channel_levels : T_ID_LEVEL - | T_ID_LEVEL '|' channel_mask_list - ; - -channel_spec : T_ID_CHANNEL - | T_ID_CHANNEL '(' channel_params ')' - ; - -channel_params : channel_param - | channel_param ',' channel_params - ; - -channel_param : T_ID_PARAM '=' T_STRING - ; - Index: ossp-pkg/l2/l2.h.in RCS File: /v/ossp/cvs/ossp-pkg/l2/l2.h.in,v rcsdiff -q -kk '-r1.20' '-r1.21' -u '/v/ossp/cvs/ossp-pkg/l2/l2.h.in,v' 2>/dev/null --- l2.h.in 2001/11/07 13:05:20 1.20 +++ l2.h.in 2001/11/07 16:17:09 1.21 @@ -227,6 +227,9 @@ l2_result_t l2_channel_type (l2_channel_t *ch, l2_chtype_t *type); l2_result_t l2_channel_env (l2_channel_t *ch, l2_env_t **env); +/* channel tree specification operations */ +l2_result_t l2_spec (l2_channel_t **ch, l2_env_t *env, const char *spec); + /* utility operations */ l2_result_t l2_util_setparams (l2_env_t *env, l2_param_t p[], const char *fmt, va_list ap); l2_result_t l2_util_l2s (char *string, size_t maxlen, int sep, unsigned int levelmask); Index: ossp-pkg/l2/l2_spec.c RCS File: /v/ossp/cvs/ossp-pkg/l2/l2_spec.c,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/l2/l2_spec.c,v' | diff -u /dev/null - -L'ossp-pkg/l2/l2_spec.c' 2>/dev/null --- ossp-pkg/l2/l2_spec.c +++ - 2024-04-23 12:01:33.737393204 +0200 @@ -0,0 +1,56 @@ + +#include + +#include "l2.h" +#include "l2_p.h" +#include "l2_spec.h" +#include "l2_spec_parse.h" + +extern int l2_spec_lex_init(void *); +extern int l2_spec_lex_destroy(void *); +extern void l2_spec_set_extra(void *, void *); +extern int l2_spec_debug; + +void dump(int level, l2_channel_t *ch) +{ + l2_channel_t *chD; + + fprintf(stderr, "%*s%s (0x%lx)\n", level*4, "", ch->handler.name, ch); + chD = NULL; + while ((l2_channel_downstream(ch, &chD)) == L2_OK) + dump(level+1, chD); + return; +} + +l2_result_t l2_spec(l2_channel_t **ch, l2_env_t *env, const char *spec) +{ + l2_spec_ctx_t ctx; + void *yyscan; + + l2_spec_lex_init(&yyscan); + l2_spec_set_extra(&ctx, yyscan); + + ctx.yyscan = yyscan; + ctx.inputptr = spec; + ctx.inputbuf = spec; + ctx.inputlen = strlen(spec); + ctx.env = env; + ctx.ch = NULL; + ctx.chTmp = NULL; + ctx.rv = L2_OK; + +#if 0 + l2_spec_debug = 1; +#endif + if (l2_spec_parse(&ctx)) + ctx.rv = (ctx.rv == L2_OK ? L2_ERR_INT : ctx.rv); + + *ch = ctx.ch; + + dump(0, ctx.ch); + + l2_spec_lex_destroy(yyscan); + + return ctx.rv; +} + Index: ossp-pkg/l2/l2_spec.h RCS File: /v/ossp/cvs/ossp-pkg/l2/l2_spec.h,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/l2/l2_spec.h,v' | diff -u /dev/null - -L'ossp-pkg/l2/l2_spec.h' 2>/dev/null --- ossp-pkg/l2/l2_spec.h +++ - 2024-04-23 12:01:33.740092120 +0200 @@ -0,0 +1,19 @@ +#ifndef __L2_SPEC_H__ +#define __L2_SPEC_H__ + +#include "l2.h" + +typedef struct { + const char *inputptr; + const char *inputbuf; + size_t inputlen; + l2_env_t *env; + l2_channel_t *ch; + l2_channel_t *chTmp; + l2_result_t rv; + void *yyscan; +} l2_spec_ctx_t; + +extern int l2_spec_parse(void *); + +#endif /* __L2_SPEC_H__ */ Index: ossp-pkg/l2/l2_spec_parse.y RCS File: /v/ossp/cvs/ossp-pkg/l2/l2_spec_parse.y,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/l2/l2_spec_parse.y,v' | diff -u /dev/null - -L'ossp-pkg/l2/l2_spec_parse.y' 2>/dev/null --- ossp-pkg/l2/l2_spec_parse.y +++ - 2024-04-23 12:01:33.742692744 +0200 @@ -0,0 +1,202 @@ +%{ +/* +** L2 - OSSP Logging Library +** Copyright (c) 2001 The OSSP Project (http://www.ossp.org/) +** Copyright (c) 2001 Cable & Wireless Deutschland (http://www.cw.com/de/) +** +** This file is part of OSSP L2, a flexible logging library which +** can be found at http://www.ossp.org/pkg/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.30 or newer! +*/ + +#include "l2.h" /* for l2_xxx() */ +#include "l2_p.h" /* for l2_channel_t and l2_env_t internals */ +#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 */ +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) \ + do { \ + l2_env_errorinfo(CTX->env, L2_ERR_ARG, "%s", msg); \ + CTX->rv = L2_ERR_ARG; \ + } while (0) +#define YYERROR_VERBOSE + +#define YYDEBUG 1 +%} + +%pure_parser +%locations +%defines + +%union { + char *cpValue; + l2_channel_t *chChannel; + unsigned int nLevels; +} + +%type stream +%type streams +%type channel +%type channel_spec +%type channel_mask +%type channel_levels + +%token T_ID +%token T_STRING + +%token T_OP_ARROW +%left T_OP_ARROW + +%% + +root : stream + { CTX->ch = $1; } + ; + +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 '%s' with child '%s'", + $1->handler.name, $3->handler.name); + 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 '%s' with child list", + $1->handler.name); + YYERROR; + } + } + ; + +streams : stream + { $$ = $1; } + | stream ';' streams + { $$ = $1; l2_channel_link($1, L2_LINK_SIBLING, $3, NULL); } + ; + +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_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; } + ; + +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; + } + ; + +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; + CTX->chTmp = NULL; + } + ; + +channel_params : /* empty */ + | '(' channel_param_list ')' + ; + +channel_param_list : /* empty */ + | channel_param + | channel_param ',' channel_param_list + ; + +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; + } + } + ; + +%% + Index: ossp-pkg/l2/l2_spec_scan.l RCS File: /v/ossp/cvs/ossp-pkg/l2/l2_spec_scan.l,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/l2/l2_spec_scan.l,v' | diff -u /dev/null - -L'ossp-pkg/l2/l2_spec_scan.l' 2>/dev/null --- ossp-pkg/l2/l2_spec_scan.l +++ - 2024-04-23 12:01:33.745567458 +0200 @@ -0,0 +1,152 @@ +%{ +/* +** L2 - OSSP Logging Library +** Copyright (c) 2001 The OSSP Project (http://www.ossp.org/) +** Copyright (c) 2001 Cable & Wireless Deutschland (http://www.cw.com/de/) +** +** This file is part of OSSP L2, a flexible logging library which +** can be found at http://www.ossp.org/pkg/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_scan.l: GNU Flex (Lex-style) scanner specification +** +** ATTENTION: This requires GNU Flex 2.5.6-dev-2001.11.01 or newer! +*/ + +#include "l2.h" /* for l2_xxx() */ +#include "l2_spec.h" /* for l2_spec_ctx_t */ +#include "l2_spec_parse.h" /* for T_XXXX */ + +/* how to find our own context */ +#define CTX ((l2_spec_ctx_t *)yyget_extra(yy_globals)) + +/* provide own input handling */ +#define YY_NO_UNPUT 1 +#undef YY_INPUT +#define YY_INPUT(buf,result,max_size) (result = yyinput(CTX, buf, max_size)) +static int yyinput(l2_spec_ctx_t *ctx, char *buf, int max_size); +%} + +%pointer +/* %option stack */ +%option reentrant-bison +%option never-interactive +%option noyywrap + +%x str + +%% + + char caStr[2048]; + char *cpStr = NULL; + + /* + * Whitespaces + */ +[ \t\n]+ { + /* NOOP */ +} + + /* + * C-style strings ("...") + */ +\" { + cpStr = caStr; + BEGIN(str); +} +\" { + BEGIN(INITIAL); + *cpStr = '\0'; + yylval->cpValue = strdup(caStr); + return T_STRING; +} +\n { + l2_env_errorinfo(CTX->env, L2_ERR_ARG, "%s", "Unterminated string"); + CTX->rv = L2_ERR_ARG; +} +\\[0-7]{1,3} { + int result; + (void)sscanf(yytext+1, "%o", &result); + if (result > 0xff) { + l2_env_errorinfo(CTX->env, L2_ERR_ARG, "%s", "Escape sequence out of bound"); + CTX->rv = L2_ERR_ARG; + } + else + *cpStr++ = result; +} +\\[0-9]+ { + l2_env_errorinfo(CTX->env, L2_ERR_ARG, "%s", "Bad escape sequence"); + CTX->rv = L2_ERR_ARG; +} +\\n { *cpStr++ = '\n'; } +\\r { *cpStr++ = '\r'; } +\\t { *cpStr++ = '\t'; } +\\b { *cpStr++ = '\b'; } +\\f { *cpStr++ = '\f'; } +\\(.|\n) { + *cpStr++ = yytext[1]; +} +[^\\\n\"]+ { + char *cp = yytext; + while (*cp != '\0') + *cpStr++ = *cp++; +} +. { + *cpStr++ = yytext[1]; +} + + /* + * Operators + */ +"->" { + return T_OP_ARROW; +} + + /* + * Identifiers + */ +[a-zA-Z][a-zA-Z0-9_-]* { + yylval->cpValue = strdup(yytext); + return T_ID; +} + + /* + * Anything else is returned as is... + */ +.|\n { + return yytext[0]; +} + +%% + +static int yyinput(l2_spec_ctx_t *ctx, char *buf, int max_size) +{ + int n; + + n = (ctx->inputbuf + ctx->inputlen - ctx->inputptr); + if (n > max_size) + n = max_size; + if (n <= 0) + return YY_NULL; + memcpy(buf, ctx->inputptr, n); + ctx->inputptr += n; + return n; +} + Index: ossp-pkg/l2/l2_test.c RCS File: /v/ossp/cvs/ossp-pkg/l2/l2_test.c,v rcsdiff -q -kk '-r1.43' '-r1.44' -u '/v/ossp/cvs/ossp-pkg/l2/l2_test.c,v' 2>/dev/null --- l2_test.c 2001/11/07 13:05:20 1.43 +++ l2_test.c 2001/11/07 16:17:09 1.44 @@ -60,12 +60,16 @@ int main(int argc, char *argv[]) { l2_channel_t *ch; +#if 1 + char *spec; +#else l2_channel_t *chFilter; l2_channel_t *chPrefix; l2_channel_t *chBuffer; l2_channel_t *chFile; l2_channel_t *chSyslog; l2_channel_t *chSmtp; +#endif l2_result_t rv; l2_env_t *env; @@ -77,6 +81,19 @@ if ((rv = l2_env_formatter(env, 'S', l2_util_fmt_dump, NULL)) != L2_OK) die(env, rv, "failed to configure formatter for %%S"); +#if 1 + spec = "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\") ;" + " syslog(ident=\"L2-Test\", facility=\"user\", " + " remotehost=\"en1\", logpid=\"1\", target=\"remote\")" + "}"; + fprintf(stderr, "configuring: %s\n", spec); + if ((rv = l2_spec(&ch, env, spec)) != L2_OK) + die(env, rv, "failed to parse specification"); +#else /* create noop channel */ if ((rv = l2_channel_create(&ch, env, "noop")) != L2_OK) die(env, rv, "failed to create noop channel"); @@ -128,6 +145,7 @@ die(env, rv, "failed to link file-related channels together as a child sequence"); if ((rv = l2_channel_link(ch, L2_LINK_CHILD, chSyslog, NULL)) != L2_OK) die(env, rv, "failed to link syslog-related channels together as a child sequence"); +#endif /* open channel tree */ if ((rv = l2_channel_open(ch)) != L2_OK)