%{ /* * Copyright (c) 2002-2017 Martin Hedenfalk * * Permission to use, copy, modify, and/or 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. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #ifdef HAVE_CONFIG_H # include #endif #ifndef HAVE_UNISTD_H # define YY_NO_UNISTD_H #else # include /* isatty() */ #endif #ifdef HAVE_STRING_H # include #endif /* Defines isatty() for non UNIX systems */ #include "confuse.h" #if defined(ENABLE_NLS) && defined(HAVE_GETTEXT) # include # define _(str) dgettext(PACKAGE, str) #else # define _(str) str #endif #define N_(str) str /* * Prevent compilation of static input() function in generated code * This function is never used but GCC 4.3 will warn about it. */ #define YY_NO_INPUT typedef char * YYSTYPE; extern YYSTYPE cfg_yylval; #define YY_DECL int cfg_yylex ( cfg_t *cfg ) /* temporary buffer for the quoted strings scanner */ #define CFG_QSTRING_BUFSIZ 32 char *cfg_qstring = NULL; static size_t qstring_index = 0; static size_t qstring_len = 0; static void qputc(char ch); static void qput(cfg_t *cfg, char skip); static void qbeg(int state); static int qend(cfg_t *cfg, int trim, int ret); static int qstr(cfg_t *cfg, char skip, int ret); #define MAX_INCLUDE_DEPTH 10 struct { FILE *fp; char *filename; unsigned int line; } cfg_include_stack[MAX_INCLUDE_DEPTH]; int cfg_include_stack_ptr = 0; void cfg_scan_fp_begin(FILE *fp); void cfg_scan_fp_end(void); %} %option noyywrap /* start conditions */ %x comment %x dq_str %x sq_str %% [ \t]+ /* eat up whitespace */ \n cfg->line++; /* keep track of line number */ /* * handle one-line comments * * Note: Comments with lots of leading #### or //// are fully * consumed and are not included in CFGT_COMMENT yylval */ "#"{1,}.* return qstr(cfg, '#', CFGT_COMMENT); "/"{2,}.* return qstr(cfg, '/', CFGT_COMMENT); /* special keywords/symbols */ "{" { cfg_yylval = yytext; return '{'; } "}" { cfg_yylval = yytext; return '}'; } "(" { cfg_yylval = yytext; return '('; } ")" { cfg_yylval = yytext; return ')'; } "=" { cfg_yylval = yytext; return '='; } "+=" { cfg_yylval = yytext; return '+'; } "," { cfg_yylval = yytext; return ','; } /* handle multi-line C-style comments */ "/*" qbeg(comment); [^*\n]* qput(NULL, 0); /* anything that's not a '*' */ "*"+[^*/\n]* qput(NULL, 0); /* '*'s not followed by '/'s */ \n qput(cfg, 0); [ \t]*"*"+"/" return qend(cfg, 1, CFGT_COMMENT); /* handle C-style strings */ "\"" { qstring_index = 0; BEGIN(dq_str); } \" { /* saw closing quote - all done */ BEGIN(INITIAL); qputc('\0'); cfg_yylval = cfg_qstring; return CFGT_STR; } $\{[^}]*\} { /* environment variable substitution */ char *var; char *e; yytext[strlen(yytext) - 1] = 0; e = strchr(yytext+2, ':'); if(e && e[1] == '-') *e = 0; else e = 0; var = getenv(yytext+2); if(!var && e) var = e+2; while(var && *var) qputc(*var++); } \n { qputc('\n'); cfg->line++; } \\\n { /* allow continuing on next line */ /* no-op */ cfg->line++; } \\[0-7]{1,3} { /* octal escape sequence */ unsigned int result; sscanf(yytext + 1, "%o", &result); if(result > 0xFF) { cfg_error(cfg, _("invalid octal number '%s'"), yytext); return 0; } qputc(result); } \\[0-9]+ { cfg_error(cfg, _("bad escape sequence '%s'"), yytext); return 0; } "\\x"[0-9A-Fa-f]{1,2} { /* hexadecimal escape sequence */ unsigned int result; sscanf(yytext + 2, "%x", &result); qputc(result); } \\n { qputc('\n'); } \\r { qputc('\r'); } \\b { qputc('\b'); } \\f { qputc('\f'); } \\a { qputc('\007'); } \\e { qputc('\033'); } \\t { qputc('\t'); } \\v { qputc('\v'); } \\. { qputc(yytext[1]); } [^\\\"\n] { qputc(yytext[0]); } /* single-quoted string ('...') */ "\'" { qstring_index = 0; BEGIN(sq_str); } \' { /* saw closing quote - all done */ BEGIN(INITIAL); qputc('\0'); cfg_yylval = cfg_qstring; return CFGT_STR; } \n { qputc('\n'); cfg->line++; } \\\n { /* allow continuing on next line */ /* no-op */ cfg->line++; } \\[\\\'] { qputc(yytext[1]); } \\[^\\\'] { qputc(yytext[0]); qputc(yytext[1]); } [^\\\'\n]+ { char *cp = yytext; while (*cp != '\0') qputc(*cp++); } <> { cfg_error(cfg, _("unterminated string constant")); return 0; } <> { if (cfg_include_stack_ptr > 0) { --cfg_include_stack_ptr; /* fp opened by cfg_lexer_include()? */ if (cfg_include_stack[cfg_include_stack_ptr].fp != cfg_yyin) { ++cfg_include_stack_ptr; return EOF; } free(cfg->filename); cfg->filename = cfg_include_stack[cfg_include_stack_ptr].filename; cfg->line = cfg_include_stack[cfg_include_stack_ptr].line; fclose(cfg_yyin); cfg_scan_fp_end(); } else { return EOF; } } $\{[^}]*\} { char *var; char *e; yytext[strlen(yytext) - 1] = 0; e = strchr(yytext+2, ':'); if (e && e[1] == '-') *e = 0; else e = 0; var = getenv(yytext+2); if (!var && e) var = e+2; if (!var) var = ""; cfg_yylval = var; return CFGT_STR; } /* an unquoted string * a slash can't be followed by another slash (c++ * comment) or an asterisk (C multi-line comment) */ (\/[^ #\"\'\t\n\r={}()+,\/*]|[^ #\"\'\t\n\r={}()+,\*])+ { cfg_yylval = yytext; return CFGT_STR; } . /* eat any non-matching characters */ %% void cfg_dummy_function(void) { /* please compiler :-) * otherwise "defined but not used" warning */ yyunput(0, 0); } int cfg_lexer_include(cfg_t *cfg, const char *filename) { FILE *fp; char *xfilename; if (cfg_include_stack_ptr >= MAX_INCLUDE_DEPTH) { cfg_error(cfg, _("includes nested too deeply")); return CFG_PARSE_ERROR; } cfg_include_stack[cfg_include_stack_ptr].filename = cfg->filename; cfg_include_stack[cfg_include_stack_ptr].line = cfg->line; if (cfg->path) { xfilename = cfg_searchpath(cfg->path, filename); if (!xfilename) { cfg_error(cfg, _("%s: Not found in search path"), filename); return CFG_PARSE_ERROR; } } else { xfilename = cfg_tilde_expand(filename); if (!xfilename) { cfg_error(cfg, _("%s: Failed tilde expand"), filename); return CFG_PARSE_ERROR; } } fp = fopen(xfilename, "r"); if (!fp) { cfg_error(cfg, "%s: %s", xfilename, strerror(errno)); free(xfilename); return CFG_PARSE_ERROR; } cfg_include_stack[cfg_include_stack_ptr].fp = fp; cfg_include_stack_ptr++; cfg->filename = xfilename; cfg->line = 1; cfg_scan_fp_begin(fp); return CFG_SUCCESS; } /* write a character to the quoted string buffer, and reallocate as * necessary */ static void qputc(char ch) { if (qstring_index >= qstring_len) { qstring_len += CFG_QSTRING_BUFSIZ; cfg_qstring = (char *)realloc(cfg_qstring, qstring_len + 1); assert(cfg_qstring); memset(cfg_qstring + qstring_index, 0, CFG_QSTRING_BUFSIZ + 1); } cfg_qstring[qstring_index++] = ch; } static void qput(cfg_t *cfg, char skip) { char *cp; if (cfg) cfg->line++; cp = yytext; while (skip && *cp == skip) cp++; while (*cp) qputc(*cp++); } static void qbeg(int state) { BEGIN(state); qstring_index = 0; if (cfg_qstring) memset(cfg_qstring, 0, qstring_len); } static char *trim_whitespace(char *str, unsigned int len) { if (!str || !str[0]) return str; while (len > 1) { if ((str[len] == 0 || isspace(str[len])) && isspace(str[len - 1])) len--; else break; } str[len] = 0; while (isspace(*str)) str++; return str; } static int qend(cfg_t *cfg, int trim, int ret) { char *ptr = cfg_qstring; BEGIN(INITIAL); if (cfg) cfg->line++; if (trim) ptr = trim_whitespace(cfg_qstring, qstring_index); else qputc('\0'); cfg_yylval = ptr; return ret; } static int qstr(cfg_t *cfg, char skip, int ret) { qbeg(comment); qput(cfg, skip); return qend(cfg, 1, ret); } void cfg_scan_fp_begin(FILE *fp) { cfg_yypush_buffer_state(cfg_yy_create_buffer(fp, YY_BUF_SIZE)); } void cfg_scan_fp_end(void) { if (cfg_qstring) free(cfg_qstring); cfg_qstring = NULL; qstring_index = qstring_len = 0; cfg_yypop_buffer_state(); }