Annotation of embedaddon/confuse/src/lexer.l, revision 1.1.1.2
1.1 misho 1: %{
2: /*
1.1.1.2 ! misho 3: * Copyright (c) 2002-2017 Martin Hedenfalk <martin@bzero.se>
1.1 misho 4: *
1.1.1.2 ! misho 5: * Permission to use, copy, modify, and/or distribute this software for any
1.1 misho 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:
1.1.1.2 ! misho 18: #include <assert.h>
! 19: #include <ctype.h>
! 20: #include <errno.h>
! 21:
1.1 misho 22: #ifdef HAVE_CONFIG_H
23: # include <config.h>
24: #endif
25:
1.1.1.2 ! misho 26: #ifndef HAVE_UNISTD_H
! 27: # define YY_NO_UNISTD_H
! 28: #else
! 29: # include <unistd.h> /* isatty() */
! 30: #endif
1.1 misho 31:
32: #ifdef HAVE_STRING_H
33: # include <string.h>
34: #endif
35:
1.1.1.2 ! misho 36: /* Defines isatty() for non UNIX systems */
! 37: #include "confuse.h"
1.1 misho 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: */
1.1.1.2 ! misho 60: #define CFG_QSTRING_BUFSIZ 32
1.1 misho 61: char *cfg_qstring = NULL;
1.1.1.2 ! misho 62: static size_t qstring_index = 0;
! 63: static size_t qstring_len = 0;
1.1 misho 64: static void qputc(char ch);
1.1.1.2 ! misho 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);
1.1 misho 69:
70: #define MAX_INCLUDE_DEPTH 10
71: struct {
1.1.1.2 ! misho 72: FILE *fp;
1.1 misho 73: char *filename;
74: unsigned int line;
75: } cfg_include_stack[MAX_INCLUDE_DEPTH];
76: int cfg_include_stack_ptr = 0;
77:
1.1.1.2 ! misho 78: void cfg_scan_fp_begin(FILE *fp);
! 79: void cfg_scan_fp_end(void);
1.1 misho 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:
1.1.1.2 ! misho 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);
1.1 misho 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: */
1.1.1.2 ! misho 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);
1.1 misho 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;
1.1.1.2 ! misho 135: }
1.1 misho 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: }
1.1.1.2 ! misho 204: <dq_str>[^\\\"\n] {
! 205: qputc(yytext[0]);
1.1 misho 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;
1.1.1.2 ! misho 236: while (*cp != '\0')
1.1 misho 237: qputc(*cp++);
238: }
239: <sq_str><<EOF>> {
240: cfg_error(cfg, _("unterminated string constant"));
241: return 0;
242: }
243:
244: <<EOF>> {
1.1.1.2 ! misho 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: }
1.1 misho 263: }
264:
265: $\{[^}]*\} {
266: char *var;
267: char *e;
1.1.1.2 ! misho 268:
1.1 misho 269: yytext[strlen(yytext) - 1] = 0;
270: e = strchr(yytext+2, ':');
1.1.1.2 ! misho 271: if (e && e[1] == '-')
1.1 misho 272: *e = 0;
273: else
274: e = 0;
275: var = getenv(yytext+2);
1.1.1.2 ! misho 276: if (!var && e)
1.1 misho 277: var = e+2;
1.1.1.2 ! misho 278: if (!var)
1.1 misho 279: var = "";
280: cfg_yylval = var;
1.1.1.2 ! misho 281:
1.1 misho 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: {
1.1.1.2 ! misho 308: FILE *fp;
1.1 misho 309: char *xfilename;
310:
1.1.1.2 ! misho 311: if (cfg_include_stack_ptr >= MAX_INCLUDE_DEPTH)
! 312: {
1.1 misho 313: cfg_error(cfg, _("includes nested too deeply"));
1.1.1.2 ! misho 314: return CFG_PARSE_ERROR;
1.1 misho 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:
1.1.1.2 ! misho 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: }
1.1 misho 338:
1.1.1.2 ! misho 339: fp = fopen(xfilename, "r");
! 340: if (!fp)
! 341: {
1.1 misho 342: cfg_error(cfg, "%s: %s", xfilename, strerror(errno));
343: free(xfilename);
1.1.1.2 ! misho 344: return CFG_PARSE_ERROR;
1.1 misho 345: }
346:
1.1.1.2 ! misho 347: cfg_include_stack[cfg_include_stack_ptr].fp = fp;
! 348: cfg_include_stack_ptr++;
1.1 misho 349: cfg->filename = xfilename;
350: cfg->line = 1;
1.1.1.2 ! misho 351: cfg_scan_fp_begin(fp);
1.1 misho 352:
1.1.1.2 ! misho 353: return CFG_SUCCESS;
1.1 misho 354: }
355:
356: /* write a character to the quoted string buffer, and reallocate as
357: * necessary
358: */
359: static void qputc(char ch)
360: {
1.1.1.2 ! misho 361: if (qstring_index >= qstring_len) {
1.1 misho 362: qstring_len += CFG_QSTRING_BUFSIZ;
1.1.1.2 ! misho 363: cfg_qstring = (char *)realloc(cfg_qstring, qstring_len + 1);
1.1 misho 364: assert(cfg_qstring);
1.1.1.2 ! misho 365: memset(cfg_qstring + qstring_index, 0, CFG_QSTRING_BUFSIZ + 1);
1.1 misho 366: }
367: cfg_qstring[qstring_index++] = ch;
368: }
369:
1.1.1.2 ! misho 370: static void qput(cfg_t *cfg, char skip)
1.1 misho 371: {
1.1.1.2 ! misho 372: char *cp;
1.1 misho 373:
1.1.1.2 ! misho 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++);
1.1 misho 384: }
385:
1.1.1.2 ! misho 386: static void qbeg(int state)
1.1 misho 387: {
1.1.1.2 ! misho 388: BEGIN(state);
! 389: qstring_index = 0;
! 390: if (cfg_qstring)
! 391: memset(cfg_qstring, 0, qstring_len);
1.1 misho 392: }
393:
1.1.1.2 ! misho 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: }
1.1 misho 438:
439: void cfg_scan_fp_begin(FILE *fp)
440: {
1.1.1.2 ! misho 441: cfg_yypush_buffer_state(cfg_yy_create_buffer(fp, YY_BUF_SIZE));
1.1 misho 442: }
443:
444: void cfg_scan_fp_end(void)
445: {
1.1.1.2 ! misho 446: if (cfg_qstring)
! 447: free(cfg_qstring);
! 448: cfg_qstring = NULL;
1.1 misho 449: qstring_index = qstring_len = 0;
1.1.1.2 ! misho 450: cfg_yypop_buffer_state();
1.1 misho 451: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>