2007-06-24 Bean * kern/parser.c (state_transitions): Add new case. * normal/execute.c (grub_script_argument_to_string): Output empty string when variable does not exist. * normal/lexer.c (grub_script_yylex2): Handle mixed text properly. * normal/parser.y : token GRUB_PARSER_TOKEN_VAR returns arg instead of text. Index: kern/parser.c =================================================================== RCS file: /sources/grub/grub2/kern/parser.c,v retrieving revision 1.2 diff -u -r1.2 parser.c --- kern/parser.c 23 Nov 2005 03:36:24 -0000 1.2 +++ kern/parser.c 24 Jun 2007 11:23:48 -0000 @@ -44,6 +44,7 @@ { GRUB_PARSER_STATE_VAR, GRUB_PARSER_STATE_VARNAME2, '{', 0}, { GRUB_PARSER_STATE_VAR, GRUB_PARSER_STATE_VARNAME, 0, 1}, { GRUB_PARSER_STATE_VARNAME, GRUB_PARSER_STATE_TEXT, ' ', 1}, + { GRUB_PARSER_STATE_VARNAME, GRUB_PARSER_STATE_TEXT, '/', 1}, { GRUB_PARSER_STATE_VARNAME2, GRUB_PARSER_STATE_TEXT, '}', 0}, { GRUB_PARSER_STATE_QVAR, GRUB_PARSER_STATE_QVARNAME2, '{', 0}, Index: normal/execute.c =================================================================== RCS file: /sources/grub/grub2/normal/execute.c,v retrieving revision 1.4 diff -u -r1.4 execute.c --- normal/execute.c 28 May 2006 21:58:34 -0000 1.4 +++ normal/execute.c 24 Jun 2007 11:23:48 -0000 @@ -50,7 +50,8 @@ if (argi->type == 1) { val = grub_env_get (argi->str); - size += grub_strlen (val); + if (val) + size += grub_strlen (val); } else size += grub_strlen (argi->str); @@ -68,7 +69,8 @@ if (argi->type == 1) { val = grub_env_get (argi->str); - grub_strcat (chararg, val); + if (val) + grub_strcat (chararg, val); } else grub_strcat (chararg, argi->str); Index: normal/lexer.c =================================================================== RCS file: /sources/grub/grub2/normal/lexer.c,v retrieving revision 1.6 diff -u -r1.6 lexer.c --- normal/lexer.c 4 Jun 2006 15:56:55 -0000 1.6 +++ normal/lexer.c 24 Jun 2007 11:23:48 -0000 @@ -50,7 +50,7 @@ struct grub_lexer_param *param; param = grub_malloc (sizeof (*param)); - if (! param) + if (!param) return 0; param->state = GRUB_PARSER_STATE_TEXT; @@ -100,7 +100,7 @@ if (state->recording[--state->recordpos] != '}') { grub_printf ("Internal error while parsing menu entry"); - for (;;); /* XXX */ + for (;;); /* XXX */ } state->recording[state->recordpos] = '\0'; } @@ -118,7 +118,7 @@ char *old = state->recording; state->recordlen += 100; state->recording = grub_realloc (state->recording, state->recordlen); - if (! state->recording) + if (!state->recording) { grub_free (old); state->record = 0; @@ -137,10 +137,10 @@ } int -grub_script_yylex2 (YYSTYPE *yylval, struct grub_parser_param *parsestate); +grub_script_yylex2 (YYSTYPE * yylval, struct grub_parser_param *parsestate); int -grub_script_yylex (YYSTYPE *yylval, struct grub_parser_param *parsestate) +grub_script_yylex (YYSTYPE * yylval, struct grub_parser_param *parsestate) { int r = -1; @@ -154,31 +154,32 @@ } int -grub_script_yylex2 (YYSTYPE *yylval, struct grub_parser_param *parsestate) +grub_script_yylex2 (YYSTYPE * yylval, struct grub_parser_param *parsestate) { grub_parser_state_t newstate; char use; char *buffer; char *bp; struct grub_lexer_param *state = parsestate->lexerstate; + struct grub_script_arg *arg = 0; + int done = 0; if (state->done) return 0; - if (! *state->script) + if (!*state->script) { /* Check if more tokens are requested by the parser. */ if ((state->refs - || state->state == GRUB_PARSER_STATE_ESC) - && state->getline) + || state->state == GRUB_PARSER_STATE_ESC) && state->getline) { - while (!state->script || ! grub_strlen (state->script)) + while (!state->script || !grub_strlen (state->script)) { grub_free (state->newscript); state->newscript = 0; state->getline (&state->newscript); state->script = state->newscript; - if (! state->script) + if (!state->script) return 0; } grub_dprintf ("scripting", "token=`\\n'\n"); @@ -196,163 +197,192 @@ } } - newstate = grub_parser_cmdline_state (state->state, *state->script, &use); - - /* Check if it is a text. */ - if (check_textstate (newstate)) + while (1) { - /* In case the string is not quoted, this can be a one char - length symbol. */ - if (newstate == GRUB_PARSER_STATE_TEXT) + newstate = + grub_parser_cmdline_state (state->state, *state->script, &use); + + /* Check if it is a text. */ + if (check_textstate (newstate)) { - switch (*state->script) + /* In case the string is not quoted, this can be a one char + length symbol. */ + if (newstate == GRUB_PARSER_STATE_TEXT) { - case ' ': - while (*state->script) + switch (*state->script) { - newstate = grub_parser_cmdline_state (state->state, - *state->script, &use); - if (! (state->state == GRUB_PARSER_STATE_TEXT - && *state->script == ' ')) + case ' ': + while (*state->script) { - grub_dprintf ("scripting", "token=` '\n"); - return ' '; + newstate = grub_parser_cmdline_state (state->state, + *state->script, + &use); + if (! + (state->state == GRUB_PARSER_STATE_TEXT + && *state->script == ' ')) + { + grub_dprintf ("scripting", "token=` '\n"); + return ' '; + } + state->state = newstate; + nextchar (state); } - state->state = newstate; - nextchar (state); + grub_dprintf ("scripting", "token=` '\n"); + return ' '; + case '{': + case '}': + case ';': + case '\n': + { + char c; + grub_dprintf ("scripting", "token=`%c'\n", + *state->script); + c = *state->script;; + nextchar (state); + return c; + } } - grub_dprintf ("scripting", "token=` '\n"); - return ' '; - case '{': - case '}': - case ';': - case '\n': - { - char c; - grub_dprintf ("scripting", "token=`%c'\n", *state->script); - c = *state->script;; - nextchar (state); - return c; - } } - } - - /* XXX: Use a better size. */ - buffer = grub_script_malloc (parsestate, 2048); - if (! buffer) - return 0; - bp = buffer; + /* XXX: Use a better size. */ + buffer = grub_script_malloc (parsestate, 2048); + if (!buffer) + return 0; - /* Read one token, possible quoted. */ - while (*state->script) - { - newstate = grub_parser_cmdline_state (state->state, - *state->script, &use); + bp = buffer; - /* Check if a variable name starts. */ - if (check_varstate (newstate)) - break; - - /* If the string is not quoted or escaped, stop processing - when a special token was found. It will be recognised - next time when this function is called. */ - if (newstate == GRUB_PARSER_STATE_TEXT - && state->state != GRUB_PARSER_STATE_ESC) + /* Read one token, possible quoted. */ + while (*state->script) { - int breakout = 0; + newstate = grub_parser_cmdline_state (state->state, + *state->script, &use); + + /* Check if a variable name starts. */ + if (check_varstate (newstate)) + break; - switch (use) + /* If the string is not quoted or escaped, stop processing + when a special token was found. It will be recognised + next time when this function is called. */ + if (newstate == GRUB_PARSER_STATE_TEXT + && state->state != GRUB_PARSER_STATE_ESC) { - case ' ': - case '{': - case '}': - case ';': - case '\n': - breakout = 1; + switch (use) + { + case ' ': + case '{': + case '}': + case ';': + case '\n': + done = 1; + } + if (done) + break; } - if (breakout) - break; - *(bp++) = use; + + if (use) + *(bp++) = use; + + state->state = newstate; + nextchar (state); } - else if (use) - *(bp++) = use; - state->state = newstate; - nextchar (state); - } + /* A string of text was read in. */ + *bp = '\0'; + grub_dprintf ("scripting", "token=`%s'\n", buffer); - /* A string of text was read in. */ - *bp = '\0'; - grub_dprintf ("scripting", "token=`%s'\n", buffer); - yylval->string = buffer; - - /* Detect some special tokens. */ - if (! grub_strcmp (buffer, "while")) - return GRUB_PARSER_TOKEN_WHILE; - else if (! grub_strcmp (buffer, "if")) - return GRUB_PARSER_TOKEN_IF; - else if (! grub_strcmp (buffer, "function")) - return GRUB_PARSER_TOKEN_FUNCTION; - else if (! grub_strcmp (buffer, "menuentry")) - return GRUB_PARSER_TOKEN_MENUENTRY; - else if (! grub_strcmp (buffer, "@")) - return GRUB_PARSER_TOKEN_MENUENTRY; - else if (! grub_strcmp (buffer, "else")) - return GRUB_PARSER_TOKEN_ELSE; - else if (! grub_strcmp (buffer, "then")) - return GRUB_PARSER_TOKEN_THEN; - else if (! grub_strcmp (buffer, "fi")) - return GRUB_PARSER_TOKEN_FI; - else - return GRUB_PARSER_TOKEN_NAME; - } - else if (newstate == GRUB_PARSER_STATE_VAR - || newstate == GRUB_PARSER_STATE_QVAR) - { - /* XXX: Use a better size. */ - buffer = grub_script_malloc (parsestate, 2096); - if (! buffer) - return 0; + if (!*state->script) + done = 1; - bp = buffer; + if ((done) && (!arg)) + { + yylval->string = buffer; + + /* Detect some special tokens. */ + if (!grub_strcmp (buffer, "while")) + return GRUB_PARSER_TOKEN_WHILE; + else if (!grub_strcmp (buffer, "if")) + return GRUB_PARSER_TOKEN_IF; + else if (!grub_strcmp (buffer, "function")) + return GRUB_PARSER_TOKEN_FUNCTION; + else if (!grub_strcmp (buffer, "menuentry")) + return GRUB_PARSER_TOKEN_MENUENTRY; + else if (!grub_strcmp (buffer, "@")) + return GRUB_PARSER_TOKEN_MENUENTRY; + else if (!grub_strcmp (buffer, "else")) + return GRUB_PARSER_TOKEN_ELSE; + else if (!grub_strcmp (buffer, "then")) + return GRUB_PARSER_TOKEN_THEN; + else if (!grub_strcmp (buffer, "fi")) + return GRUB_PARSER_TOKEN_FI; + else + return GRUB_PARSER_TOKEN_NAME; + } - /* This is a variable, read the variable name. */ - while (*state->script) + if (bp != buffer) + arg = + grub_script_arg_add (parsestate, arg, GRUB_SCRIPT_ARG_TYPE_STR, + buffer); + } + else if (newstate == GRUB_PARSER_STATE_VAR + || newstate == GRUB_PARSER_STATE_QVAR) { - newstate = grub_parser_cmdline_state (state->state, - *state->script, &use); + /* XXX: Use a better size. */ + buffer = grub_script_malloc (parsestate, 2096); + if (!buffer) + return 0; + + bp = buffer; - /* Check if this character is not part of the variable name - anymore. */ - if (! (check_varstate (newstate))) + /* This is a variable, read the variable name. */ + while (*state->script) { - if (state->state == GRUB_PARSER_STATE_VARNAME2 - || state->state == GRUB_PARSER_STATE_QVARNAME2) - nextchar (state); + newstate = grub_parser_cmdline_state (state->state, + *state->script, &use); + + /* Check if this character is not part of the variable name + anymore. */ + if (!(check_varstate (newstate))) + { + if (state->state == GRUB_PARSER_STATE_VARNAME2 + || state->state == GRUB_PARSER_STATE_QVARNAME2) + nextchar (state); + state->state = newstate; + break; + } + + if (use) + *(bp++) = use; + nextchar (state); state->state = newstate; - break; } - if (use) - *(bp++) = use; - nextchar (state); + *bp = '\0'; state->state = newstate; - } - *bp = '\0'; - state->state = newstate; - yylval->string = buffer; - grub_dprintf ("scripting", "vartoken=`%s'\n", buffer); + if (bp != buffer) + arg = + grub_script_arg_add (parsestate, arg, GRUB_SCRIPT_ARG_TYPE_VAR, + buffer); + } + else + { + /* There is either text or a variable name. In the case you + arrive here there is a serious problem with the lexer. */ + grub_error (GRUB_ERR_BAD_ARGUMENT, "Internal error\n"); + return 0; + } - return GRUB_PARSER_TOKEN_VAR; - } - else - { - /* There is either text or a variable name. In the case you - arrive here there is a serious problem with the lexer. */ - grub_error (GRUB_ERR_BAD_ARGUMENT, "Internal error\n"); - return 0; + if ((done) || (!*state->script)) + { + if (arg) + { + yylval->arg = arg; + return GRUB_PARSER_TOKEN_VAR; + } + else + return ' '; + } } } Index: normal/parser.y =================================================================== RCS file: /sources/grub/grub2/normal/parser.y,v retrieving revision 1.6 diff -u -r1.6 parser.y --- normal/parser.y 4 Jun 2006 15:56:55 -0000 1.6 +++ normal/parser.y 24 Jun 2007 11:23:48 -0000 @@ -46,9 +46,9 @@ %token GRUB_PARSER_TOKEN_VAR %type script grubcmd command commands commandblock menuentry if %type arguments; -%type argument; +%type argument GRUB_PARSER_TOKEN_VAR; %type "if" "while" "function" "else" "then" "fi" -%type text GRUB_PARSER_TOKEN_NAME GRUB_PARSER_TOKEN_VAR +%type text GRUB_PARSER_TOKEN_NAME %pure-parser %lex-param { struct grub_parser_param *state }; @@ -86,7 +86,7 @@ for example: `foo${bar}baz'. */ argument: GRUB_PARSER_TOKEN_VAR { - $$ = grub_script_arg_add (state, 0, GRUB_SCRIPT_ARG_TYPE_VAR, $1); + $$ = $1; } | text {