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>