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