1 /*
2 ** OSSP l2 - Flexible Logging
3 ** Copyright (c) 2001-2005 Cable & Wireless <http://www.cw.com/>
4 ** Copyright (c) 2001-2005 The OSSP Project <http://www.ossp.org/>
5 ** Copyright (c) 2001-2005 Ralf S. Engelschall <rse@engelschall.com>
6 **
7 ** This file is part of OSSP l2, a flexible logging library which
8 ** can be found at http://www.ossp.org/pkg/lib/l2/.
9 **
10 ** Permission to use, copy, modify, and distribute this software for
11 ** any purpose with or without fee is hereby granted, provided that
12 ** the above copyright notice and this permission notice appear in all
13 ** copies.
14 **
15 ** THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
16 ** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
17 ** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 ** IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
19 ** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
22 ** USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 ** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 ** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 ** OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 ** SUCH DAMAGE.
27 **
28 ** l2_spec.c: channel tree specification support
29 */
30
31 #include "l2.h"
32 #include "l2_p.h"
33 #include "l2_spec.h"
34
35 /* prototypes for Flex-generated scanner */
36 extern int l2_spec_lex_init(void *);
37 extern int l2_spec_lex_destroy(void *);
38 extern void l2_spec_set_extra(void *, void *);
39
40 /* prototypes for Bison-generated parser */
41 extern int l2_spec_parse(void *);
42
43 /* build a channel tree according to a textual specification */
l2_spec(l2_channel_t ** ch,l2_env_t * env,const char * spec,...)44 l2_result_t l2_spec(l2_channel_t **ch, l2_env_t *env, const char *spec, ...)
45 {
46 va_list ap;
47 l2_result_t rv;
48
49 /* pass-through to va_list-based variant */
50 va_start(ap, spec);
51 rv = l2_vspec(ch, env, spec, &ap);
52 va_end(ap);
53
54 return rv;
55 }
56
57 /* build a channel tree according to a textual specification (va_list variant) */
l2_vspec(l2_channel_t ** ch,l2_env_t * env,const char * spec,va_list * ap)58 l2_result_t l2_vspec(l2_channel_t **ch, l2_env_t *env, const char *spec, va_list *ap)
59 {
60 l2_spec_ctx_t ctx;
61 void *yyscan;
62 char *specstr;
63
64 /* on-the-fly create or take over specification string */
65 if ((specstr = l2_util_vasprintf(spec, ap)) == NULL)
66 return L2_ERR_ARG;
67
68 /* initialize scanner */
69 l2_spec_lex_init(&yyscan);
70 l2_spec_set_extra(&ctx, yyscan);
71
72 /* establish our own context which is passed
73 through the parser and scanner */
74 ctx.yyscan = yyscan;
75 ctx.inputptr = specstr;
76 ctx.inputbuf = specstr;
77 ctx.inputlen = strlen(specstr);
78 ctx.env = env;
79 ctx.ch = NULL;
80 ctx.chTmp = NULL;
81 ctx.rv = L2_OK;
82
83 /* start the parser loop */
84 if (l2_spec_parse(&ctx))
85 ctx.rv = (ctx.rv == L2_OK ? L2_ERR_INT : ctx.rv);
86
87 /* destroy scanner */
88 l2_spec_lex_destroy(yyscan);
89
90 /* destroy specification string */
91 free(specstr);
92
93 /* provide root/top-level channel as result */
94 *ch = ctx.ch;
95
96 return ctx.rv;
97 }
98
99 /* remember a specification parsing error (used internally) */
l2_spec_error(l2_spec_ctx_t * ctx,l2_result_t rv,YYLTYPE * loc,const char * fmt,...)100 void l2_spec_error(l2_spec_ctx_t *ctx, l2_result_t rv, YYLTYPE *loc, const char *fmt, ...)
101 {
102 va_list ap;
103 const char *cpF, *cpL;
104 const char *cpP, *cpE;
105 int line, column;
106 char *cpBuf;
107 char *cp;
108 int n;
109
110 /* determine first and last positions of token */
111 cpF = ctx->inputbuf+loc->first;
112 cpL = ctx->inputbuf+loc->last;
113
114 /* determine epilog and prolog of token */
115 cpP = cpF-4;
116 if (cpP < ctx->inputbuf)
117 cpP = ctx->inputbuf;
118 cpE = cpL+4;
119 if (cpE > ctx->inputbuf+ctx->inputlen)
120 cpE = ctx->inputbuf+ctx->inputlen;
121
122 /* calculate line and column of token */
123 line = 1;
124 column = 1;
125 for (cp = (char *)ctx->inputbuf; cp < (ctx->inputbuf+ctx->inputlen) && cp != cpF; cp++) {
126 column++;
127 if (*cp == '\n') {
128 column = 1;
129 line++;
130 }
131 }
132
133 /* extract token context with mark token borders */
134 if ((cpBuf = malloc((cpE-cpP)+2+1)) == NULL)
135 return;
136 cp = cpBuf;
137 n = cpF-cpP;
138 memcpy(cp, cpP, n); cp += n;
139 *cp++ = '<';
140 n = cpL-cpF;
141 memcpy(cp, cpF, n); cp += n;
142 *cp++ = '>';
143 n = cpE-cpL;
144 memcpy(cp, cpL, n); cp += n;
145 *cp++ = '\0';
146
147 /* remember error */
148 va_start(ap, fmt);
149 if ((cp = l2_util_vasprintf(fmt, &ap)) != NULL) {
150 l2_env_errorinfo(ctx->env, rv, "line %d, column %d: `%s'; %s",
151 line, column, cpBuf, cp);
152 free(cp);
153 }
154 else
155 l2_env_errorinfo(ctx->env, rv, "line %d, column %d: `%s'; N.A.",
156 line, column, cpBuf);
157 va_end(ap);
158 ctx->rv = rv;
159
160 /* cleanup */
161 free(cpBuf);
162
163 return;
164 }
165
166