diff --git a/include/grub/script_sh.h b/include/grub/script_sh.h index b55b6a806..447b3a375 100644 --- a/include/grub/script_sh.h +++ b/include/grub/script_sh.h @@ -195,6 +195,12 @@ struct grub_lexer_param /* Type of text. */ grub_script_arg_type_t type; + /* Flag to indicate resplit in progres. */ + unsigned resplit; + + /* Text that is unput. */ + char *prefix; + /* Flex scanner. */ void *yyscanner; @@ -284,7 +290,7 @@ void grub_script_lexer_ref (struct grub_lexer_param *); void grub_script_lexer_deref (struct grub_lexer_param *); void grub_script_lexer_record_start (struct grub_parser_param *); char *grub_script_lexer_record_stop (struct grub_parser_param *); -int grub_script_lexer_yywrap (struct grub_parser_param *); +int grub_script_lexer_yywrap (struct grub_parser_param *, const char *input); void grub_script_lexer_record (struct grub_parser_param *, char *); /* Functions to track allocated memory. */ diff --git a/script/lexer.c b/script/lexer.c index 42a570348..63b74e2e0 100644 --- a/script/lexer.c +++ b/script/lexer.c @@ -98,8 +98,6 @@ grub_script_lexer_record_stop (struct grub_parser_param *parser) return result; } -#define MAX(a,b) ((a) < (b) ? (b) : (a)) - /* Record STR if input recording is enabled. */ void grub_script_lexer_record (struct grub_parser_param *parser, char *str) @@ -115,7 +113,7 @@ grub_script_lexer_record (struct grub_parser_param *parser, char *str) if (lexer->recordpos + len + 1 > lexer->recordlen) { old = lexer->recording; - lexer->recordlen = MAX (len, lexer->recordlen) * 2; + lexer->recordlen = grub_max (len, lexer->recordlen) * 2; lexer->recording = grub_realloc (lexer->recording, lexer->recordlen); if (!lexer->recording) { @@ -131,76 +129,85 @@ grub_script_lexer_record (struct grub_parser_param *parser, char *str) lexer->recordpos += len; } -/* Append '\n' to SRC, before '\0' */ -static char * -append_newline (const char *src) -{ - char *line; - grub_size_t len; - - len = grub_strlen (src); - line = grub_malloc (len + 2); - if (!line) - return 0; - - grub_strcpy (line, src); - - line[len] = '\n'; - line[len + 1] = '\0'; - return line; -} - /* Read next line of input if necessary, and set yyscanner buffers. */ int -grub_script_lexer_yywrap (struct grub_parser_param *parserstate) +grub_script_lexer_yywrap (struct grub_parser_param *parserstate, + const char *input) { int len; - char *line; - char *line2; + char *p = 0; + char *line = 0; YY_BUFFER_STATE buffer; struct grub_lexer_param *lexerstate = parserstate->lexerstate; - if (!lexerstate->refs) - return 0; + if (! lexerstate->refs && ! lexerstate->prefix && ! input) + return 1; - if (!lexerstate->getline) + if (! lexerstate->getline && ! input) { grub_script_yyerror (parserstate, "unexpected end of file"); - return 0; + return 1; } line = 0; - buffer = 0; - lexerstate->getline (&line, 1); - if (!line) + if (! input) + lexerstate->getline (&line, 1); + else + line = grub_strdup (input); + if (! line) { - grub_script_yyerror (parserstate, 0); /* XXX this could be for ^C case? */ - return 0; + grub_script_yyerror (parserstate, 0); + return 1; } len = grub_strlen (line); - if (line[len - 1] == '\n') + if (lexerstate->prefix) { - buffer = yy_scan_string (line, lexerstate->yyscanner); - } - else - { - line2 = append_newline (line); - if (line2) + int plen = grub_strlen (lexerstate->prefix); + + p = grub_malloc (len + plen + 2); + if (! p) { - buffer = yy_scan_string (line2, lexerstate->yyscanner); - grub_free (line2); + grub_free (line); + return 1; } + grub_strcpy (p, lexerstate->prefix); + lexerstate->prefix = 0; + + if (! line[0]) + { + line = "\n"; + len = 1; + } + grub_strcpy (p + plen, line); + + line = p; + len = len + plen; } + if (line[len - 1] != '\n') + { + char *p; + p = grub_realloc (line, len + 2); + if (! p) + { + grub_free (line); + return 1; + } + line = p; + line[len++] = '\n'; + line[len] = '\0'; + } + + buffer = yy_scan_string (line, lexerstate->yyscanner); grub_free (line); - if (!buffer) + + if (! buffer) { grub_script_yyerror (parserstate, 0); - return 0; + return 1; } - - return 1; + return 0; } struct grub_lexer_param * @@ -231,35 +238,18 @@ grub_script_lexer_init (struct grub_parser_param *parser, char *script, grub_free (lexerstate); return 0; } + yyset_extra (parser, lexerstate->yyscanner); + parser->lexerstate = lexerstate; - buffer = 0; - script = script ? : "\n"; - len = grub_strlen (script); - - if (script[len - 1] == '\n') - { - buffer = yy_scan_string (script, lexerstate->yyscanner); - } - else - { - script2 = append_newline (script); - if (script2) - { - buffer = yy_scan_string (script2, lexerstate->yyscanner); - grub_free (script2); - } - } - - if (!buffer) + if (grub_script_lexer_yywrap (parser, script ?: "\n")) { + parser->lexerstate = 0; yylex_destroy (lexerstate->yyscanner); grub_free (lexerstate->yyscanner); - grub_free (lexerstate->text); grub_free (lexerstate); return 0; } - yyset_extra (parser, lexerstate->yyscanner); return lexerstate; } diff --git a/script/yylex.l b/script/yylex.l index 658bcfdf8..025810da3 100644 --- a/script/yylex.l +++ b/script/yylex.l @@ -58,7 +58,9 @@ #define YY_INPUT(buf,res,max) do { res = 0; } while (0) /* forward declarations */ -static int resplit (const char *input, yyscan_t yyscanner); +static int grub_lexer_unput (const char *input, yyscan_t yyscanner); +static int grub_lexer_resplit (const char *input, yyscan_t yyscanner); + static void grub_lexer_yyfree (void *, yyscan_t yyscanner); static void* grub_lexer_yyalloc (yy_size_t, yyscan_t yyscanner); static void* grub_lexer_yyrealloc (void*, yy_size_t, yyscan_t yyscanner); @@ -100,10 +102,9 @@ typedef size_t yy_size_t; %option never-interactive %option noyyfree noyyalloc noyyrealloc -%option nounistd nostdinit nodefault noyylineno noyywrap +%option nounistd nostdinit nodefault noyylineno /* Reduce lexer size, by not defining these. */ -%option noyy_top_state %option noinput nounput %option noyyget_in noyyset_in %option noyyget_out noyyset_out @@ -120,20 +121,19 @@ DIGITS [[:digit:]]+ NAME [[:alpha:]_][[:alnum:][:digit:]_]* ESC \\. +SQCHR [^\'] +DQCHR {ESC}|[^\"] +DQSTR \"{DQCHR}*\" +SQSTR \'{SQCHR}*\' VARIABLE ${NAME}|$\{{NAME}\}|${DIGITS}|$\{{DIGITS}\}|$\?|$\{\?\} -DQSTR \"([^\"]|{ESC})*\" -SQSTR \'([^\'])*\' WORD ({CHAR}|{DQSTR}|{SQSTR}|{ESC}|{VARIABLE})+ -DQSTR2 {WORD}?\"({ESC}|[^\"])*\n -SQSTR2 {WORD}?\'({ESC}|[^\'])*\n +MULTILINE {WORD}?((\"{DQCHR}*)|(\'{SQCHR}*)) %x SPLIT %x DQUOTE %x SQUOTE %x VAR -%x DQMULTILINE -%x SQMULTILINE %% @@ -179,55 +179,22 @@ SQSTR2 {WORD}?\'({ESC}|[^\'])*\n {NAME} { RECORD; return GRUB_PARSER_TOKEN_NAME; } {WORD} { RECORD; + yyextra->lexerstate->resplit = 1; yypush_buffer_state (YY_CURRENT_BUFFER, yyscanner); - if (resplit (yytext, yyscanner)) + if (grub_lexer_resplit (yytext, yyscanner)) { yypop_buffer_state (yyscanner); return GRUB_PARSER_TOKEN_WORD; } } -{DQSTR2} { - yy_push_state (DQMULTILINE, yyscanner); - grub_script_lexer_ref (yyextra->lexerstate); - yymore (); +{MULTILINE} { + if (grub_lexer_unput (yytext, yyscanner)) + return GRUB_PARSER_TOKEN_BAD; + } +. { + grub_script_yyerror (yyextra, yytext); + return GRUB_PARSER_TOKEN_BAD; } -{ - \"{WORD}? { - RECORD; - grub_script_lexer_deref (yyextra->lexerstate); - yy_pop_state (yyscanner); - yypush_buffer_state (YY_CURRENT_BUFFER, yyscanner); - if (resplit (yytext, yyscanner)) - { - yypop_buffer_state (yyscanner); - return GRUB_PARSER_TOKEN_WORD; - } - } - {ESC} { yymore(); } - [^\"] { yymore(); } -} - -{SQSTR2} { - yy_push_state (SQMULTILINE, yyscanner); - grub_script_lexer_ref (yyextra->lexerstate); - yymore (); - } - -{ - \'{WORD}? { - RECORD; - grub_script_lexer_deref (yyextra->lexerstate); - yy_pop_state (yyscanner); - yypush_buffer_state (YY_CURRENT_BUFFER, yyscanner); - if (resplit (yytext, yyscanner)) - { - yypop_buffer_state (yyscanner); - return GRUB_PARSER_TOKEN_WORD; - } - } - {ESC} { yymore(); } - [^\'] { yymore(); } -} /* Split word into multiple args */ @@ -250,6 +217,7 @@ SQSTR2 {WORD}?\'({ESC}|[^\'])*\n <> { yy_pop_state (yyscanner); yypop_buffer_state (yyscanner); + yyextra->lexerstate->resplit = 0; yyextra->lexerstate->merge_end = 1; ARG (GRUB_SCRIPT_ARG_TYPE_TEXT); } @@ -305,37 +273,21 @@ SQSTR2 {WORD}?\'({ESC}|[^\'])*\n (.|\n) { COPY (yytext, yyleng); } } -. { /* ignore */ } <> { yypop_buffer_state (yyscanner); - if (! grub_script_lexer_yywrap (yyextra)) - { - yyextra->lexerstate->eof = 1; - return GRUB_PARSER_TOKEN_EOF; - } + yyextra->lexerstate->eof = 1; + return GRUB_PARSER_TOKEN_EOF; } %% -#if 0 int yywrap (yyscan_t yyscanner) { - char *line = 0; - struct grub_lexer_param *lexerstate = yyget_extra(yyscanner)->lexerstate; + if (yyget_extra (yyscanner)->lexerstate->resplit) + return 1; - grub_printf ("yywrap\n"); - if (lexerstate->getline) - { - lexerstate->getline (&line, 1); - if (! line) - return 1; - - yy_scan_string (line, yyscanner); - return 0; - } - return 1; + return grub_script_lexer_yywrap (yyget_extra (yyscanner), 0); } -#endif static void grub_lexer_yyfree (void *ptr, yyscan_t yyscanner __attribute__ ((unused))) @@ -381,7 +333,7 @@ static void copy_string (struct grub_parser_param *parser, const char *str, unsi } static int -resplit (const char *text, yyscan_t yyscanner) +grub_lexer_resplit (const char *text, yyscan_t yyscanner) { /* resplit text */ if (yy_scan_string (text, yyscanner)) @@ -393,3 +345,23 @@ resplit (const char *text, yyscan_t yyscanner) grub_script_yyerror (yyget_extra (yyscanner), 0); return 1; } + +static int +grub_lexer_unput (const char *text, yyscan_t yyscanner) +{ + struct grub_lexer_param *lexerstate = yyget_extra (yyscanner)->lexerstate; + + if (lexerstate->prefix) + { + grub_free (lexerstate->prefix); + lexerstate->prefix = 0; + } + + lexerstate->prefix = grub_strdup (text); + if (! lexerstate->prefix) + { + grub_script_yyerror (yyget_extra (yyscanner), "out of memory"); + return 1; + } + return 0; +}