# Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: address@hidden # target_branch: ../mainline/ # testament_sha1: 8430edc467e1c9276304cd28ecb0baf126c68d14 # timestamp: 2010-06-12 12:23:56 +0530 # base_revision_id: address@hidden # c3z8o8ivju9aetz7 # # Begin patch === modified file 'include/grub/script_sh.h' --- include/grub/script_sh.h 2010-03-26 15:43:06 +0000 +++ include/grub/script_sh.h 2010-06-12 05:36:02 +0000 @@ -195,6 +195,12 @@ /* 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_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. */ === modified file 'script/lexer.c' --- script/lexer.c 2010-02-11 13:19:57 +0000 +++ script/lexer.c 2010-06-12 06:32:06 +0000 @@ -98,8 +98,6 @@ 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 @@ 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,86 @@ 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) - { - grub_script_yyerror (parserstate, 0); /* XXX this could be for ^C case? */ - return 0; - } - - len = grub_strlen (line); - if (line[len - 1] == '\n') - { - buffer = yy_scan_string (line, lexerstate->yyscanner); - } + if (! input) + lexerstate->getline (&line, 1); else - { - line2 = append_newline (line); - if (line2) - { - buffer = yy_scan_string (line2, lexerstate->yyscanner); - grub_free (line2); - } - } - + line = grub_strdup (input); + + /* Ensure '\n' at the end. */ + if (line && line[0] == '\0') + { + grub_free (line); + line = grub_strdup ("\n"); + } + + if (line && (len = grub_strlen(line)) && line[len - 1] != '\n') + { + p = grub_realloc (line, len + 2); + if (p) + { + p[len++] = '\n'; + p[len] = '\0'; + } + line = p; + } + + if (! line) + { + grub_script_yyerror (parserstate, "out of memory"); + return 1; + } + + /* Prepend any left over unput-text. */ + if (lexerstate->prefix) + { + int plen = grub_strlen (lexerstate->prefix); + + p = grub_malloc (len + plen + 1); + if (! p) + { + grub_free (line); + return 1; + } + grub_strcpy (p, lexerstate->prefix); + lexerstate->prefix = 0; + + grub_strcpy (p + plen, line); + grub_free (line); + + line = p; + len = len + plen; + } + + 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 +239,18 @@ grub_free (lexerstate); return 0; } - - 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) - { + yyset_extra (parser, lexerstate->yyscanner); + parser->lexerstate = lexerstate; + + 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; } === modified file 'script/yylex.l' --- script/yylex.l 2010-04-30 08:20:41 +0000 +++ script/yylex.l 2010-06-12 06:53:49 +0000 @@ -58,6 +58,9 @@ #define YY_INPUT(buf,res,max) do { res = 0; } while (0) /* forward declarations */ +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); @@ -99,7 +102,7 @@ %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 @@ -118,12 +121,16 @@ DIGITS [[:digit:]]+ NAME [[:alpha:]_][[:alnum:][:digit:]_]* -ESC \\. +ESC \\(.|\n) +SQCHR [^\'] +DQCHR {ESC}|[^\\\"] +DQSTR \"{DQCHR}*\" +SQSTR \'{SQCHR}*\' VARIABLE ${NAME}|$\{{NAME}\}|${DIGITS}|$\{{DIGITS}\}|$\?|$\{\?\} -DQSTR \"([^\\\"]|{ESC})*\" -SQSTR \'[^\']*\' WORD ({CHAR}|{DQSTR}|{SQSTR}|{ESC}|{VARIABLE})+ +MULTILINE {WORD}?((\"{DQCHR}*)|(\'{SQCHR}*)|(\\\n)) + %x SPLIT %x DQUOTE %x SQUOTE @@ -170,34 +177,32 @@ "function" { RECORD; return GRUB_PARSER_TOKEN_FUNCTION; } "menuentry" { RECORD; return GRUB_PARSER_TOKEN_MENUENTRY; } +{MULTILINE} { + if (grub_lexer_unput (yytext, yyscanner)) + return GRUB_PARSER_TOKEN_BAD; + } + {NAME} { RECORD; return GRUB_PARSER_TOKEN_NAME; } {WORD} { RECORD; - /* resplit yytext */ - grub_dprintf ("lexer", "word: [%s]\n", yytext); - yypush_buffer_state (YY_CURRENT_BUFFER, yyscanner); - if (yy_scan_string (yytext, yyscanner)) - { - yyextra->lexerstate->merge_start = 1; - yy_push_state (SPLIT, yyscanner); - } - else - { - grub_script_yyerror (yyextra, 0); - yypop_buffer_state (yyscanner); - return GRUB_PARSER_TOKEN_WORD; - } + yypush_buffer_state (YY_CURRENT_BUFFER, yyscanner); + if (grub_lexer_resplit (yytext, yyscanner)) + { + yypop_buffer_state (yyscanner); + return GRUB_PARSER_TOKEN_WORD; + } + yyextra->lexerstate->resplit = 1; } - -.|\n { - grub_script_yyerror (yyextra, "unrecognized token"); - return GRUB_PARSER_TOKEN_BAD; +. { + grub_script_yyerror (yyextra, yytext); + return GRUB_PARSER_TOKEN_BAD; } /* Split word into multiple args */ { \\. { COPY (yytext + 1, yyleng - 1); } + \\\n { /* ignore */ } \" { yy_push_state (DQUOTE, yyscanner); ARG (GRUB_SCRIPT_ARG_TYPE_TEXT); @@ -215,6 +220,7 @@ <> { yy_pop_state (yyscanner); yypop_buffer_state (yyscanner); + yyextra->lexerstate->resplit = 0; yyextra->lexerstate->merge_end = 1; ARG (GRUB_SCRIPT_ARG_TYPE_TEXT); } @@ -272,15 +278,20 @@ <> { 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; } - %% +int +yywrap (yyscan_t yyscanner) +{ + if (yyget_extra (yyscanner)->lexerstate->resplit) + return 1; + + return grub_script_lexer_yywrap (yyget_extra (yyscanner), 0); +} + static void grub_lexer_yyfree (void *ptr, yyscan_t yyscanner __attribute__ ((unused))) { @@ -300,8 +311,6 @@ return grub_realloc (ptr, size); } -#define MAX(a,b) ((a) < (b) ? (b) : (a)) - static void copy_string (struct grub_parser_param *parser, const char *str, unsigned hint) { int size; @@ -311,7 +320,7 @@ len = hint ? hint : grub_strlen (str); if (parser->lexerstate->used + len >= parser->lexerstate->size) { - size = MAX (len, parser->lexerstate->size) * 2; + size = grub_max (len, parser->lexerstate->size) * 2; ptr = grub_realloc (parser->lexerstate->text, size); if (!ptr) { @@ -325,3 +334,34 @@ grub_strcpy (parser->lexerstate->text + parser->lexerstate->used - 1, str); parser->lexerstate->used += len; } + +static int +grub_lexer_resplit (const char *text, yyscan_t yyscanner) +{ + /* resplit text */ + if (yy_scan_string (text, yyscanner)) + { + yyget_extra (yyscanner)->lexerstate->merge_start = 1; + yy_push_state (SPLIT, yyscanner); + return 0; + } + 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 = grub_strdup (text); + if (! lexerstate->prefix) + { + grub_script_yyerror (yyget_extra (yyscanner), "out of memory"); + return 1; + } + return 0; +} === modified file 'tests/grub_script_echo1.in' --- tests/grub_script_echo1.in 2010-01-22 13:37:27 +0000 +++ tests/grub_script_echo1.in 2010-06-12 06:53:49 +0000 @@ -30,3 +30,45 @@ foo=echo $foo 1234 + +echo "one +" +echo "one +\"" +echo "one +two" + +echo one"two +"three +echo one"two +\""three +echo one"two +\"three\" +four" + + +echo 'one +' +echo 'one +\' +echo 'one +two' +echo one'two +' +echo one'two +\' +echo one'two +\'three + +# echo "one\ +# two" +# echo 'one\ +# two' +# echo foo\ +# bar +# \ +# echo foo +# echo "one +# +# two" + # Begin bundle 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