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 <jk@ozlabs.org>
#ifndef GRUB2_H
#define GRUB2_H
#ifndef GRUB2_H
#define GRUB2_H
#include <stdbool.h>
#include <list/list.h>
struct grub2_script;
struct grub2_word {
#include <stdbool.h>
#include <list/list.h>
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;
};
struct grub2_word *next;
struct list_item argv_list;
};
struct grub2_script {
struct grub2_statements *statements;
struct list environment;
struct grub2_script {
struct grub2_statements *statements;
struct list environment;
struct grub2_statement *create_statement_block(struct grub2_parser *parser,
struct grub2_statements *stmts);
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);
struct grub2_argv *create_argv(struct grub2_parser *parser);
/* anything that's not a metachar: return as a plain word */
{WORD} {
/* 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}\} {
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);
yy_pop_state(yyscanner);
}
<sqstring>[^']+ {
yy_pop_state(yyscanner);
}
<sqstring>[^']+ {
- yylval->word = create_word(yyget_extra(yyscanner), yytext,
- false, false);
+ yylval->word = create_word_text(yyget_extra(yyscanner), yytext);
<dqstring>\" {
yy_pop_state(yyscanner);
}
<dqstring>\" {
yy_pop_state(yyscanner);
}
-<dqstring>([^"]|\\\")+ {
- yylval->word = create_word(yyget_extra(yyscanner), yytext,
- true, false);
+<dqstring>([^"\$]|\\\")+ {
+ yylval->word = create_word_text(yyget_extra(yyscanner), yytext);
+<dqstring>\${VARNAME} |
+<dqstring>\$\{{VARNAME}\} {
+ if (yytext[1] == '{') {
+ yytext[yyleng-1] = '\0';
+ yytext++;
+ }
+ yytext++;
+ yylval->word = create_word_var(yyget_extra(yyscanner), yytext,
+ false);
+ return TOKEN_WORD;
+ }
+
list_add_tail(&stmts->list, &stmt->list);
}
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);
{
struct grub2_word *word = talloc(parser, struct grub2_word);
+ word->type = GRUB2_WORD_TEXT;
word->text = talloc_strdup(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;
}
word->next = NULL;
return word;
}
#include <string.h>
#include <talloc/talloc.h>
#include <string.h>
#include <talloc/talloc.h>
};
static const char *env_lookup(struct grub2_script *script,
};
static const char *env_lookup(struct grub2_script *script,
- const char *name, int name_len)
{
struct env_entry *entry;
list_for_each_entry(&script->environment, entry, list)
{
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;
}
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;
- 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);
- 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);
-/* 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
*
* Once that's done, we may (if split == true) have to split the word to create
* new argv items
static void process_expansions(struct grub2_script *script,
struct grub2_argv *argv)
{
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;
statements_execute(script, script->statements);
}
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;
struct grub2_script *create_script(void *ctx)
{
struct grub2_script *script;
script = talloc(ctx, struct grub2_script);
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;
init_env(script);
return script;