1: %{
2: /*
3: * Copyright (c) 2002-2017 Martin Hedenfalk <martin@bzero.se>
4: *
5: * Permission to use, copy, modify, and/or distribute this software for any
6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
8: *
9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16: */
17:
18: #include <assert.h>
19: #include <ctype.h>
20: #include <errno.h>
21:
22: #ifdef HAVE_CONFIG_H
23: # include <config.h>
24: #endif
25:
26: #ifndef HAVE_UNISTD_H
27: # define YY_NO_UNISTD_H
28: #else
29: # include <unistd.h> /* isatty() */
30: #endif
31:
32: #ifdef HAVE_STRING_H
33: # include <string.h>
34: #endif
35:
36: /* Defines isatty() for non UNIX systems */
37: #include "confuse.h"
38:
39: #if defined(ENABLE_NLS) && defined(HAVE_GETTEXT)
40: # include <libintl.h>
41: # define _(str) dgettext(PACKAGE, str)
42: #else
43: # define _(str) str
44: #endif
45: #define N_(str) str
46:
47: /*
48: * Prevent compilation of static input() function in generated code
49: * This function is never used but GCC 4.3 will warn about it.
50: */
51: #define YY_NO_INPUT
52:
53: typedef char * YYSTYPE;
54: extern YYSTYPE cfg_yylval;
55:
56: #define YY_DECL int cfg_yylex ( cfg_t *cfg )
57:
58: /* temporary buffer for the quoted strings scanner
59: */
60: #define CFG_QSTRING_BUFSIZ 32
61: char *cfg_qstring = NULL;
62: static size_t qstring_index = 0;
63: static size_t qstring_len = 0;
64: static void qputc(char ch);
65: static void qput(cfg_t *cfg, char skip);
66: static void qbeg(int state);
67: static int qend(cfg_t *cfg, int trim, int ret);
68: static int qstr(cfg_t *cfg, char skip, int ret);
69:
70: #define MAX_INCLUDE_DEPTH 10
71: struct {
72: FILE *fp;
73: char *filename;
74: unsigned int line;
75: } cfg_include_stack[MAX_INCLUDE_DEPTH];
76: int cfg_include_stack_ptr = 0;
77:
78: void cfg_scan_fp_begin(FILE *fp);
79: void cfg_scan_fp_end(void);
80:
81: %}
82:
83: %option noyywrap
84:
85: /* start conditions
86: */
87: %x comment
88: %x dq_str
89: %x sq_str
90:
91: %%
92:
93: [ \t]+ /* eat up whitespace */
94:
95: \n cfg->line++; /* keep track of line number */
96:
97: /*
98: * handle one-line comments
99: *
100: * Note: Comments with lots of leading #### or //// are fully
101: * consumed and are not included in CFGT_COMMENT yylval
102: */
103: "#"{1,}.* return qstr(cfg, '#', CFGT_COMMENT);
104: "/"{2,}.* return qstr(cfg, '/', CFGT_COMMENT);
105:
106: /* special keywords/symbols
107: */
108: "{" { cfg_yylval = yytext; return '{'; }
109: "}" { cfg_yylval = yytext; return '}'; }
110: "(" { cfg_yylval = yytext; return '('; }
111: ")" { cfg_yylval = yytext; return ')'; }
112: "=" { cfg_yylval = yytext; return '='; }
113: "+=" { cfg_yylval = yytext; return '+'; }
114: "," { cfg_yylval = yytext; return ','; }
115:
116: /* handle multi-line C-style comments
117: */
118: "/*" qbeg(comment);
119: <comment>[^*\n]* qput(NULL, 0); /* anything that's not a '*' */
120: <comment>"*"+[^*/\n]* qput(NULL, 0); /* '*'s not followed by '/'s */
121: <comment>\n qput(cfg, 0);
122: <comment>[ \t]*"*"+"/" return qend(cfg, 1, CFGT_COMMENT);
123:
124: /* handle C-style strings
125: */
126: "\"" {
127: qstring_index = 0;
128: BEGIN(dq_str);
129: }
130: <dq_str>\" { /* saw closing quote - all done */
131: BEGIN(INITIAL);
132: qputc('\0');
133: cfg_yylval = cfg_qstring;
134: return CFGT_STR;
135: }
136: <dq_str>$\{[^}]*\} { /* environment variable substitution */
137: char *var;
138: char *e;
139: yytext[strlen(yytext) - 1] = 0;
140: e = strchr(yytext+2, ':');
141: if(e && e[1] == '-')
142: *e = 0;
143: else
144: e = 0;
145: var = getenv(yytext+2);
146: if(!var && e)
147: var = e+2;
148: while(var && *var)
149: qputc(*var++);
150: }
151: <dq_str>\n {
152: qputc('\n');
153: cfg->line++;
154: }
155: <dq_str>\\\n { /* allow continuing on next line */
156: /* no-op */
157: cfg->line++;
158: }
159: <dq_str>\\[0-7]{1,3} { /* octal escape sequence */
160: unsigned int result;
161: sscanf(yytext + 1, "%o", &result);
162: if(result > 0xFF) {
163: cfg_error(cfg, _("invalid octal number '%s'"), yytext);
164: return 0;
165: }
166: qputc(result);
167: }
168: <dq_str>\\[0-9]+ {
169: cfg_error(cfg, _("bad escape sequence '%s'"), yytext);
170: return 0;
171: }
172: <dq_str>"\\x"[0-9A-Fa-f]{1,2} { /* hexadecimal escape sequence */
173: unsigned int result;
174: sscanf(yytext + 2, "%x", &result);
175: qputc(result);
176: }
177: <dq_str>\\n {
178: qputc('\n');
179: }
180: <dq_str>\\r {
181: qputc('\r');
182: }
183: <dq_str>\\b {
184: qputc('\b');
185: }
186: <dq_str>\\f {
187: qputc('\f');
188: }
189: <dq_str>\\a {
190: qputc('\007');
191: }
192: <dq_str>\\e {
193: qputc('\033');
194: }
195: <dq_str>\\t {
196: qputc('\t');
197: }
198: <dq_str>\\v {
199: qputc('\v');
200: }
201: <dq_str>\\. {
202: qputc(yytext[1]);
203: }
204: <dq_str>[^\\\"\n] {
205: qputc(yytext[0]);
206: }
207:
208: /* single-quoted string ('...') */
209: "\'" {
210: qstring_index = 0;
211: BEGIN(sq_str);
212: }
213: <sq_str>\' { /* saw closing quote - all done */
214: BEGIN(INITIAL);
215: qputc('\0');
216: cfg_yylval = cfg_qstring;
217: return CFGT_STR;
218: }
219: <sq_str>\n {
220: qputc('\n');
221: cfg->line++;
222: }
223: <sq_str>\\\n { /* allow continuing on next line */
224: /* no-op */
225: cfg->line++;
226: }
227: <sq_str>\\[\\\'] {
228: qputc(yytext[1]);
229: }
230: <sq_str>\\[^\\\'] {
231: qputc(yytext[0]);
232: qputc(yytext[1]);
233: }
234: <sq_str>[^\\\'\n]+ {
235: char *cp = yytext;
236: while (*cp != '\0')
237: qputc(*cp++);
238: }
239: <sq_str><<EOF>> {
240: cfg_error(cfg, _("unterminated string constant"));
241: return 0;
242: }
243:
244: <<EOF>> {
245: if (cfg_include_stack_ptr > 0)
246: {
247: --cfg_include_stack_ptr;
248: /* fp opened by cfg_lexer_include()? */
249: if (cfg_include_stack[cfg_include_stack_ptr].fp != cfg_yyin) {
250: ++cfg_include_stack_ptr;
251: return EOF;
252: }
253: free(cfg->filename);
254: cfg->filename = cfg_include_stack[cfg_include_stack_ptr].filename;
255: cfg->line = cfg_include_stack[cfg_include_stack_ptr].line;
256: fclose(cfg_yyin);
257: cfg_scan_fp_end();
258: }
259: else
260: {
261: return EOF;
262: }
263: }
264:
265: $\{[^}]*\} {
266: char *var;
267: char *e;
268:
269: yytext[strlen(yytext) - 1] = 0;
270: e = strchr(yytext+2, ':');
271: if (e && e[1] == '-')
272: *e = 0;
273: else
274: e = 0;
275: var = getenv(yytext+2);
276: if (!var && e)
277: var = e+2;
278: if (!var)
279: var = "";
280: cfg_yylval = var;
281:
282: return CFGT_STR;
283: }
284:
285: /* an unquoted string
286: * a slash can't be followed by another slash (c++
287: * comment) or an asterisk (C multi-line comment)
288: */
289: (\/[^ #\"\'\t\n\r={}()+,\/*]|[^ #\"\'\t\n\r={}()+,\*])+ {
290: cfg_yylval = yytext;
291: return CFGT_STR;
292: }
293:
294: . /* eat any non-matching characters */
295:
296: %%
297:
298: void cfg_dummy_function(void)
299: {
300: /* please compiler :-)
301: * otherwise "defined but not used" warning
302: */
303: yyunput(0, 0);
304: }
305:
306: int cfg_lexer_include(cfg_t *cfg, const char *filename)
307: {
308: FILE *fp;
309: char *xfilename;
310:
311: if (cfg_include_stack_ptr >= MAX_INCLUDE_DEPTH)
312: {
313: cfg_error(cfg, _("includes nested too deeply"));
314: return CFG_PARSE_ERROR;
315: }
316:
317: cfg_include_stack[cfg_include_stack_ptr].filename = cfg->filename;
318: cfg_include_stack[cfg_include_stack_ptr].line = cfg->line;
319:
320: if (cfg->path)
321: {
322: xfilename = cfg_searchpath(cfg->path, filename);
323: if (!xfilename)
324: {
325: cfg_error(cfg, _("%s: Not found in search path"), filename);
326: return CFG_PARSE_ERROR;
327: }
328: }
329: else
330: {
331: xfilename = cfg_tilde_expand(filename);
332: if (!xfilename)
333: {
334: cfg_error(cfg, _("%s: Failed tilde expand"), filename);
335: return CFG_PARSE_ERROR;
336: }
337: }
338:
339: fp = fopen(xfilename, "r");
340: if (!fp)
341: {
342: cfg_error(cfg, "%s: %s", xfilename, strerror(errno));
343: free(xfilename);
344: return CFG_PARSE_ERROR;
345: }
346:
347: cfg_include_stack[cfg_include_stack_ptr].fp = fp;
348: cfg_include_stack_ptr++;
349: cfg->filename = xfilename;
350: cfg->line = 1;
351: cfg_scan_fp_begin(fp);
352:
353: return CFG_SUCCESS;
354: }
355:
356: /* write a character to the quoted string buffer, and reallocate as
357: * necessary
358: */
359: static void qputc(char ch)
360: {
361: if (qstring_index >= qstring_len) {
362: qstring_len += CFG_QSTRING_BUFSIZ;
363: cfg_qstring = (char *)realloc(cfg_qstring, qstring_len + 1);
364: assert(cfg_qstring);
365: memset(cfg_qstring + qstring_index, 0, CFG_QSTRING_BUFSIZ + 1);
366: }
367: cfg_qstring[qstring_index++] = ch;
368: }
369:
370: static void qput(cfg_t *cfg, char skip)
371: {
372: char *cp;
373:
374: if (cfg)
375: cfg->line++;
376:
377: cp = yytext;
378:
379: while (skip && *cp == skip)
380: cp++;
381:
382: while (*cp)
383: qputc(*cp++);
384: }
385:
386: static void qbeg(int state)
387: {
388: BEGIN(state);
389: qstring_index = 0;
390: if (cfg_qstring)
391: memset(cfg_qstring, 0, qstring_len);
392: }
393:
394: static char *trim_whitespace(char *str, unsigned int len)
395: {
396: if (!str || !str[0])
397: return str;
398:
399: while (len > 1) {
400: if ((str[len] == 0 || isspace(str[len])) && isspace(str[len - 1]))
401: len--;
402: else
403: break;
404: }
405: str[len] = 0;
406:
407: while (isspace(*str))
408: str++;
409:
410: return str;
411: }
412:
413: static int qend(cfg_t *cfg, int trim, int ret)
414: {
415: char *ptr = cfg_qstring;
416:
417: BEGIN(INITIAL);
418: if (cfg)
419: cfg->line++;
420:
421: if (trim)
422: ptr = trim_whitespace(cfg_qstring, qstring_index);
423: else
424: qputc('\0');
425:
426: cfg_yylval = ptr;
427:
428: return ret;
429: }
430:
431: static int qstr(cfg_t *cfg, char skip, int ret)
432: {
433: qbeg(comment);
434: qput(cfg, skip);
435:
436: return qend(cfg, 1, ret);
437: }
438:
439: void cfg_scan_fp_begin(FILE *fp)
440: {
441: cfg_yypush_buffer_state(cfg_yy_create_buffer(fp, YY_BUF_SIZE));
442: }
443:
444: void cfg_scan_fp_end(void)
445: {
446: if (cfg_qstring)
447: free(cfg_qstring);
448: cfg_qstring = NULL;
449: qstring_index = qstring_len = 0;
450: cfg_yypop_buffer_state();
451: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>