2
* Copyright (c) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
3
* NOVELL (All rights reserved)
4
* Copyright (c) 2010 - 2012
7
* This program is free software; you can redistribute it and/or
8
* modify it under the terms of version 2 of the GNU General Public
9
* License published by the Free Software Foundation.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, contact Canonical, Ltd.
20
/* Definitions section */
23
/* eliminates need to link with libfl */
33
#include <sys/types.h>
37
#define _(s) gettext(s)
40
#include "parser_include.h"
41
#include "parser_yacc.h"
48
#define PDEBUG(fmt, args...) printf("Lexer (state %d): " fmt, YY_START, ## args)
50
#define PDEBUG(fmt, args...) /* Do nothing */
52
#define NPDEBUG(fmt, args...) /* Do nothing */
54
#define DUMP_PREPROCESS do { if (preprocess_only) ECHO; } while (0)
58
struct ignored_suffix_t {
64
struct ignored_suffix_t ignored_suffixes[] = {
65
/* Debian packging files, which are in flux during install
66
should be silently ignored. */
67
{ ".dpkg-new", 9, 1 },
68
{ ".dpkg-old", 9, 1 },
69
{ ".dpkg-dist", 10, 1 },
70
{ ".dpkg-bak", 9, 1 },
71
/* RPM packaging files have traditionally not been silently
75
/* Backup files should be mentioned */
80
void include_filename(char *filename, int search)
82
FILE *include_file = NULL;
84
char *fullpath = NULL;
88
fprintf(yyout, "\n\n##included <%s>\n", filename);
89
include_file = search_path(filename, &fullpath);
92
fprintf(yyout, "\n\n##included \"%s\"\n", filename);
93
fullpath = strdup(filename);
94
include_file = fopen(fullpath, "r");
98
yyerror(_("Could not open '%s'"),
99
fullpath ? fullpath: filename);
101
if (fstat(fileno(include_file), &my_stat))
102
yyerror(_("fstat failed for '%s'"), fullpath);
104
if (S_ISREG(my_stat.st_mode)) {
106
update_mru_tstamp(include_file);
107
PDEBUG("Opened include \"%s\"\n", fullpath);
108
push_include_stack(fullpath);
109
yypush_buffer_state(yy_create_buffer( yyin, YY_BUF_SIZE ));
112
if (S_ISDIR(my_stat.st_mode)) {
114
char *dirent_path = NULL;
115
struct dirent *dirent;
117
PDEBUG("Opened include directory \"%s\"\n", fullpath);
118
if (!(dir = opendir(fullpath)))
119
yyerror(_("opendir failed '%s'"), fullpath);
120
fclose(include_file);
123
while ((dirent = readdir(dir)) != NULL) {
125
struct ignored_suffix_t *suffix;
126
/* skip dotfiles silently. */
127
if (dirent->d_name[0] == '.')
132
if (asprintf(&dirent_path, "%s/%s", fullpath, dirent->d_name) < 0)
133
yyerror("Out of memory");
135
name_len = strlen(dirent->d_name);
136
/* skip blacklisted suffixes */
137
for (suffix = ignored_suffixes; suffix->text; suffix++) {
139
if ( (found = strstr(dirent->d_name, suffix->text)) &&
140
found - dirent->d_name + suffix->len == name_len ) {
143
PERROR("Ignoring: '%s'\n", dirent_path);
147
if (!name_len) continue;
149
if (stat(dirent_path, &my_stat))
150
yyerror(_("stat failed for '%s'"), dirent_path);
151
if (S_ISREG(my_stat.st_mode)) {
152
if (!(yyin = fopen(dirent_path,"r")))
153
yyerror(_("Could not open '%s' in '%s'"), dirent_path, filename);
154
PDEBUG("Opened include \"%s\" in \"%s\"\n", dirent_path, filename);
155
update_mru_tstamp(yyin);
156
push_include_stack(dirent_path);
157
yypush_buffer_state(yy_create_buffer(yyin, YY_BUF_SIZE));
178
MODE_CHARS ([RrWwaLlMmkXx])|(([Pp]|[Cc])[Xx])|(([Pp]|[Cc])?([IiUu])[Xx])
184
ID {ID_CHARS}|(,{ID_CHARS})
186
POST_VAR_ID_CHARS [^ \t\n"!,]{-}[=\+]
187
POST_VAR_ID {POST_VAR_ID_CHARS}|(,{POST_VAR_ID_CHARS})
188
LIST_VALUE_ID_CHARS [^ \t\n"!,]{-}[()]
189
LIST_VALUE_ID {LIST_VALUE_ID_CHARS}+
190
ID_CHARS_NOEQ [^ \t\n"!,]{-}[=]
191
ID_NOEQ {ID_CHARS_NOEQ}|(,{ID_CHARS_NOEQ})
193
ALLOWED_QUOTED_ID [^\0"]|\\\"
194
QUOTED_ID \"{ALLOWED_QUOTED_ID}*\"
196
IP {NUMBER}\.{NUMBER}\.{NUMBER}\.{NUMBER}
200
KEYWORD [[:alpha:]_]+
201
VARIABLE_NAME [[:alpha:]][[:alnum:]_]*
203
SET_VARIABLE {SET_VAR_PREFIX}(\{{VARIABLE_NAME}\}|{VARIABLE_NAME})
204
BOOL_VARIABLE $(\{{VARIABLE_NAME}\}|{VARIABLE_NAME})
206
PATHNAME (\/|{SET_VARIABLE}{POST_VAR_ID}){ID}*
207
QPATHNAME \"(\/|{SET_VAR_PREFIX})([^\0"]|\\\")*\"
225
%x CHANGE_PROFILE_MODE
231
/* Copied directly into yylex function */
233
int t = parser_token;
240
{WS}+ { /* Eat whitespace */ }
241
\<([^\> \t\n]+)\> { /* <filename> */
242
char *filename = strdup(yytext);
243
filename[strlen(filename) - 1] = '\0';
244
include_filename(filename + 1, 1);
249
\"([^\" \t\n]+)\" { /* "filename" */
250
char *filename = strdup(yytext);
251
filename[strlen(filename) - 1] = '\0';
252
include_filename(filename + 1, 0);
257
[^\<\>\"{WS}]+ { /* filename */
258
include_filename(yytext, 0);
266
yypop_buffer_state();
267
if ( !YY_CURRENT_BUFFER ) yyterminate();
270
<INITIAL,MOUNT_MODE>{
271
{VARIABLE_NAME}/{WS}*= {
272
/* we match to the = in the lexer so that
273
* can switch scanner state. By the time
274
* the parser see the = it may be to late
275
* as bison may have requested the next
276
* token from the scanner
278
PDEBUG("conditional %s=\n", yytext);
279
yylval.id = processid(yytext, yyleng);
280
yy_push_state(EXTCOND_MODE);
286
({IDS}|{QUOTED_ID}) {
287
/* Ugh, this is a gross hack. I used to use
288
* {IDS} to match all TOK_IDs, but that would
289
* also match TOK_MODE + TOK_END_OF_RULE
290
* without any spaces in between (because it's
291
* a longer match). So now, when I want to
292
* match any random string, I go into a
295
yylval.id = processid(yytext, yyleng);
296
PDEBUG("Found sub name: \"%s\"\n", yylval.id);
303
/* Something we didn't expect */
304
yyerror(_("Found unexpected character: '%s'"), yytext);
309
({IDS}|{QUOTED_ID}) {
310
/* Ugh, this is a gross hack. I used to use
311
* {IDS} to match all TOK_IDs, but that would
312
* also match TOK_MODE + TOK_END_OF_RULE
313
* without any spaces in between (because it's
314
* a longer match). So now, when I want to
315
* match any random string, I go into a
318
yylval.id = processid(yytext, yyleng);
319
PDEBUG("Found sub value: \"%s\"\n", yylval.id);
326
/* Something we didn't expect */
327
yyerror(_("Found unexpected character: '%s'"), yytext);
334
PDEBUG("listval: )\n");
336
return TOK_CLOSEPAREN;
339
{WS}+ { DUMP_PREPROCESS; /* Eat whitespace */ }
343
PDEBUG("listval: , \n");
344
/* East comma, its an optional separator */
347
({LIST_VALUE_ID}|{QUOTED_ID}) {
349
yylval.id = processid(yytext, yyleng);
350
PDEBUG("listval: \"%s\"\n", yylval.id);
356
/* Something we didn't expect */
357
yyerror(_("Found unexpected character: '%s'"), yytext);
362
{WS}+ { DUMP_PREPROCESS; /* Eat whitespace */ }
364
{EQUALS}{WS}*/[^(\n]{-}{WS} {
377
PDEBUG("extcond listv\n");
378
/* Don't push state here as this is a transition
379
* start condition and we want to return to the start
380
* condition that invoked <EXTCOND_MODE> when
381
* LIST_VAL_ID is done
383
BEGIN(LIST_VAL_MODE);
384
return TOK_OPENPAREN;
389
/* Something we didn't expect */
390
yyerror(_("Found unexpected character: '%s' %d"), yytext, *yytext);
396
{WS}+ { DUMP_PREPROCESS; /* Eat whitespace */ }
398
({IDS}|{QUOTED_ID}) {
400
yylval.var_val = processid(yytext, yyleng);
401
PDEBUG("Found assignment value: \"%s\"\n", yylval.var_val);
407
yylval.id = strdup(yytext);
408
yyerror(_("Variable declarations do not accept trailing commas"));
411
\\\n { DUMP_PREPROCESS; current_lineno++ ; }
420
/* Something we didn't expect */
421
yyerror(_("Found unexpected character: '%s'"), yytext);
426
{WS}+ { DUMP_PREPROCESS; /* Eat whitespace */ }
430
yylval.id = strdup(yytext);
436
return TOK_END_OF_RULE;
440
/* Something we didn't expect */
441
yylval.id = strdup(yytext);
442
yyerror(_("(network_mode) Found unexpected character: '%s'"), yylval.id);
451
<CHANGE_PROFILE_MODE>{
454
PDEBUG("Matched a change profile arrow\n");
458
({IDS}|{QUOTED_ID}) {
459
/* Ugh, this is a gross hack. I used to use
460
* {IDS} to match all TOK_IDs, but that would
461
* also match TOK_MODE + TOK_END_OF_RULE
462
* without any spaces in between (because it's
463
* a longer match). So now, when I want to
464
* match any random string, I go into a
467
yylval.id = processid(yytext, yyleng);
468
PDEBUG("Found change profile name: \"%s\"\n", yylval.id);
473
{WS}+ { DUMP_PREPROCESS; /* Ignoring whitespace */ }
476
/* Something we didn't expect */
477
yyerror(_("Found unexpected character: '%s'"), yytext);
482
{WS}+ { DUMP_PREPROCESS; /* Eat whitespace */ }
485
-?{NUMBER}[[:alpha:]]* {
487
yylval.var_val = strdup(yytext);
493
yylval.id = strdup(yytext);
494
if (strcmp(yytext, "infinity") == 0)
499
{LT_EQUAL} { DUMP_PREPROCESS; return TOK_LE; }
504
return TOK_END_OF_RULE;
521
{WS}+ { DUMP_PREPROCESS; /* Ignoring whitespace */ }
525
PDEBUG("Matched arrow\n");
529
({IDS_NOEQ}|{PATHNAME}|{QUOTED_ID}) {
531
yylval.id = processid(yytext, yyleng);
532
PDEBUG("Found ID: \"%s\"\n", yylval.id);
539
return TOK_END_OF_RULE;
544
/* Something we didn't expect */
545
yyerror(_("Found unexpected character: '%s'"), yytext);
555
#include/.*\r?\n { /* include */
556
PDEBUG("Matched #include\n");
557
yy_push_state(INCLUDE);
560
#.*\r?\n { /* normal comment */
562
PDEBUG("comment(%d): %s\n", current_lineno, yytext);
566
{END_OF_RULE} { DUMP_PREPROCESS; return TOK_END_OF_RULE; }
570
PDEBUG("Matched hat ^\n");
571
yy_push_state(SUB_ID);
576
PDEBUG("Matched a arrow\n");
581
PDEBUG("Matched equals for assignment\n");
582
yy_push_state(ASSIGN_MODE);
587
PDEBUG("Matched additive value assignment\n");
588
yy_push_state(ASSIGN_MODE);
589
return TOK_ADD_ASSIGN;
593
yylval.set_var = strdup(yytext);
594
PDEBUG("Found set variable %s\n", yylval.set_var);
600
yylval.bool_var = strdup(yytext);
601
PDEBUG("Found boolean variable %s\n", yylval.bool_var);
607
PDEBUG("Open Brace\n");
612
PDEBUG("Close Brace\n");
616
({PATHNAME}|{QPATHNAME}) {
618
yylval.id = processid(yytext, yyleng);
619
PDEBUG("Found id: \"%s\"\n", yylval.id);
623
({MODES})/([[:space:],]) {
625
yylval.mode = strdup(yytext);
626
PDEBUG("Found modes: %s\n", yylval.mode);
632
yy_push_state(SUB_ID);
638
yy_push_state(SUB_ID);
644
PDEBUG("Found a colon\n");
650
PDEBUG("listval (\n");
651
yy_push_state(LIST_VAL_MODE);
652
return TOK_OPENPAREN;
657
int token = get_keyword_token(yytext);
663
yylval.id = processunquoted(yytext, yyleng);
664
PDEBUG("Found (var) id: \"%s\"\n", yylval.id);
668
yy_push_state(RLIMIT_MODE);
671
yy_push_state(NETWORK_MODE);
673
case TOK_CHANGE_PROFILE:
674
yy_push_state(CHANGE_PROFILE_MODE);
680
PDEBUG("Entering mount\n");
681
yy_push_state(MOUNT_MODE);
683
default: /* nothing */
689
{WS}+ { DUMP_PREPROCESS; /* Ignoring whitespace */ }
691
\r?\n { DUMP_PREPROCESS; current_lineno++ ; }
696
/* Something we didn't expect */
697
yyerror(_("Found unexpected character: '%s'"), yytext);