From: Jeremy Kerr Date: Fri, 13 Sep 2013 06:50:19 +0000 (+0800) Subject: discover/grub2: Handle var tokens in lexer X-Git-Tag: v1.0.0~466 X-Git-Url: https://git.ozlabs.org/?p=petitboot;a=commitdiff_plain;h=fb5a2b71f85614114663c86dbba62c5c491a11b9 discover/grub2: Handle var tokens in lexer Rather than post-processing to expand variables, use the lexer to identify variable tokens as a type of grub2_word. Signed-off-by: Jeremy Kerr --- diff --git a/discover/grub2/grub2.h b/discover/grub2/grub2.h index 07a1e6c..cbd69dc 100644 --- a/discover/grub2/grub2.h +++ b/discover/grub2/grub2.h @@ -1,16 +1,23 @@ #ifndef GRUB2_H #define GRUB2_H -#include #include #include struct grub2_script; struct grub2_word { - const char *text; - bool expand; - bool split; + enum { + GRUB2_WORD_TEXT, + GRUB2_WORD_VAR, + } type; + union { + char *text; + struct { + const char *name; + bool split; + } var; + }; struct grub2_word *next; struct list_item argv_list; }; @@ -61,7 +68,6 @@ struct grub2_statement_block { struct grub2_script { struct grub2_statements *statements; struct list environment; - regex_t var_re; }; struct grub2_parser { @@ -85,8 +91,11 @@ struct grub2_statement *create_statement_if(struct grub2_parser *parser, struct grub2_statement *create_statement_block(struct grub2_parser *parser, struct grub2_statements *stmts); -struct grub2_word *create_word(struct grub2_parser *parser, const char *text, - bool expand, bool split); +struct grub2_word *create_word_text(struct grub2_parser *parser, + const char *text); + +struct grub2_word *create_word_var(struct grub2_parser *parser, + const char *name, bool split); struct grub2_argv *create_argv(struct grub2_parser *parser); diff --git a/discover/grub2/lexer.l b/discover/grub2/lexer.l index 64eee27..ab26f4b 100644 --- a/discover/grub2/lexer.l +++ b/discover/grub2/lexer.l @@ -51,15 +51,19 @@ VARNAME ([[:alpha:]][_[:alnum:]]*|[0-9]|[\?@\*#]) /* anything that's not a metachar: return as a plain word */ {WORD} { - yylval->word = create_word(yyget_extra(yyscanner), yytext, - false, false); + yylval->word = create_word_text(yyget_extra(yyscanner), yytext); return TOKEN_WORD; } \${VARNAME} | \$\{{VARNAME}\} { - yylval->word = create_word(yyget_extra(yyscanner), yytext, - true, true); + if (yytext[1] == '{') { + yytext[yyleng-1] = '\0'; + yytext++; + } + yytext++; + yylval->word = create_word_var(yyget_extra(yyscanner), yytext, + true); return TOKEN_WORD; } @@ -71,8 +75,7 @@ VARNAME ([[:alpha:]][_[:alnum:]]*|[0-9]|[\?@\*#]) yy_pop_state(yyscanner); } [^']+ { - yylval->word = create_word(yyget_extra(yyscanner), yytext, - false, false); + yylval->word = create_word_text(yyget_extra(yyscanner), yytext); return TOKEN_WORD; } @@ -83,11 +86,22 @@ VARNAME ([[:alpha:]][_[:alnum:]]*|[0-9]|[\?@\*#]) \" { yy_pop_state(yyscanner); } -([^"]|\\\")+ { - yylval->word = create_word(yyget_extra(yyscanner), yytext, - true, false); +([^"\$]|\\\")+ { + yylval->word = create_word_text(yyget_extra(yyscanner), yytext); return TOKEN_WORD; } +\${VARNAME} | +\$\{{VARNAME}\} { + if (yytext[1] == '{') { + yytext[yyleng-1] = '\0'; + yytext++; + } + yytext++; + yylval->word = create_word_var(yyget_extra(yyscanner), yytext, + false); + return TOKEN_WORD; + } + /* blocks */ diff --git a/discover/grub2/parser-api.c b/discover/grub2/parser-api.c index 9ccf15e..765bd87 100644 --- a/discover/grub2/parser-api.c +++ b/discover/grub2/parser-api.c @@ -68,13 +68,23 @@ void statement_append(struct grub2_statements *stmts, list_add_tail(&stmts->list, &stmt->list); } -struct grub2_word *create_word(struct grub2_parser *parser, const char *text, - bool expand, bool split) +struct grub2_word *create_word_text(struct grub2_parser *parser, + const char *text) { struct grub2_word *word = talloc(parser, struct grub2_word); + word->type = GRUB2_WORD_TEXT; word->text = talloc_strdup(word, text); - word->expand = expand; - word->split = split; + word->next = NULL; + return word; +} + +struct grub2_word *create_word_var(struct grub2_parser *parser, + const char *name, bool split) +{ + struct grub2_word *word = talloc(parser, struct grub2_word); + word->type = GRUB2_WORD_VAR; + word->var.name = talloc_strdup(word, name); + word->var.split = split; word->next = NULL; return word; } diff --git a/discover/grub2/script.c b/discover/grub2/script.c index 3fee470..5361394 100644 --- a/discover/grub2/script.c +++ b/discover/grub2/script.c @@ -1,6 +1,5 @@ #include -#include #include #include @@ -19,50 +18,32 @@ struct env_entry { }; static const char *env_lookup(struct grub2_script *script, - const char *name, int name_len) + const char *name) { struct env_entry *entry; list_for_each_entry(&script->environment, entry, list) - if (!strncmp(entry->name, name, name_len) - && entry->name[name_len] == '\0') + if (!strcmp(entry->name, name)) return entry->value; return NULL; } -static bool expand_word(struct grub2_script *script, struct grub2_word *word) +static bool expand_var(struct grub2_script *script, struct grub2_word *word) { - const char *val, *src; - char *dest = NULL; - regmatch_t match; - int n, i; + const char *val; - src = word->text; - - n = regexec(&script->var_re, src, 1, &match, 0); - if (n != 0) - return false; - - i = 0; - if (src[match.rm_so + 1] == '{') - i++; - - val = env_lookup(script, src + match.rm_so + 1 + i, - match.rm_eo - match.rm_so - 1 - (i * 2)); + val = env_lookup(script, word->var.name); if (!val) val = ""; - dest = talloc_strndup(script, src, match.rm_so); - dest = talloc_asprintf_append(dest, "%s%s", val, src + match.rm_eo); + word->type = GRUB2_WORD_TEXT; + word->text = talloc_strdup(script, val); - word->text = dest; return true; } -/* iterate through the words in an argv, looking for expansions. If a - * word is marked with expand == true, then we process any variable - * substitutions. +/* iterate through the words in an argv, looking for GRUB2_WORD_VAR expansions. * * Once that's done, we may (if split == true) have to split the word to create * new argv items @@ -70,13 +51,23 @@ static bool expand_word(struct grub2_script *script, struct grub2_word *word) static void process_expansions(struct grub2_script *script, struct grub2_argv *argv) { - struct grub2_word *word; - - list_for_each_entry(&argv->words, word, argv_list) { - if (!word->expand) - continue; - - expand_word(script, word); + struct grub2_word *top_word, *word; + + list_for_each_entry(&argv->words, top_word, argv_list) { + /* expand vars and squash the list of words into the top struct. + * todo: splitting + */ + for (word = top_word; word; word = word->next) { + if (word->type == GRUB2_WORD_VAR) + expand_var(script, word); + + if (word == top_word) + continue; + + top_word->text = talloc_asprintf_append(top_word->text, + "%s", word->text); + } + top_word->next = NULL; } } @@ -147,33 +138,12 @@ void script_execute(struct grub2_script *script) statements_execute(script, script->statements); } -static int script_destroy(void *p) -{ - struct grub2_script *script = p; - regfree(&script->var_re); - return 0; -} - struct grub2_script *create_script(void *ctx) { struct grub2_script *script; - int rc; script = talloc(ctx, struct grub2_script); - rc = regcomp(&script->var_re, - "\\$\\{?([[:alpha:]][_[:alnum:]]*|[0-9]|[\\?@\\*#])\\}?", - REG_EXTENDED); - if (rc) { - char err[200]; - regerror(rc, &script->var_re, err, sizeof(err)); - fprintf(stderr, "RE error %d: %s\n", rc, err); - talloc_free(script); - return NULL; - - } - talloc_set_destructor(script, script_destroy); - init_env(script); return script;