| %{ |
| /* yylex.l The scripting lexer. */ |
| /* |
| * GRUB -- GRand Unified Bootloader |
| * Copyright (C) 2009,2010 Free Software Foundation, Inc. |
| * |
| * GRUB is free software: you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation, either version 3 of the License, or |
| * (at your option) any later version. |
| * |
| * GRUB is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with GRUB. If not, see <http://www.gnu.org/licenses/>. |
| */ |
| |
| #include <grub/parser.h> |
| #include <grub/misc.h> |
| #include <grub/mm.h> |
| #include <grub/script_sh.h> |
| #include <grub/i18n.h> |
| #include "grub_script.tab.h" |
| |
| #pragma GCC diagnostic ignored "-Wunused-parameter" |
| #pragma GCC diagnostic ignored "-Wmissing-prototypes" |
| #pragma GCC diagnostic ignored "-Wmissing-declarations" |
| #pragma GCC diagnostic ignored "-Wunsafe-loop-optimizations" |
| |
| #define yyfree grub_lexer_yyfree |
| #define yyalloc grub_lexer_yyalloc |
| #define yyrealloc grub_lexer_yyrealloc |
| |
| /* |
| * As we don't have access to yyscanner, we cannot do much except to |
| * print the fatal error. |
| */ |
| #define YY_FATAL_ERROR(msg) \ |
| do { \ |
| grub_printf (_("fatal error: %s\n"), _(msg)); \ |
| } while (0) |
| |
| #define COPY(str, hint) \ |
| do { \ |
| copy_string (yyextra, str, hint); \ |
| } while (0) |
| |
| |
| #define RECORD \ |
| do { \ |
| grub_script_lexer_record (yyextra, yytext); \ |
| } while (0) |
| |
| #define ARG(t) \ |
| do { \ |
| yyextra->lexerstate->type = t; \ |
| return GRUB_PARSER_TOKEN_WORD; \ |
| } while (0) |
| |
| /* We don't need YY_INPUT, as we rely on yy_scan_strings */ |
| #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); |
| static void copy_string (struct grub_parser_param *, const char *, |
| unsigned hint); |
| |
| %} |
| |
| %top{ |
| |
| #include <config.h> |
| |
| #include <sys/types.h> |
| |
| typedef size_t yy_size_t; |
| #define YY_TYPEDEF_YY_SIZE_T 1 |
| |
| /* |
| * Some flex hacks for -nostdinc; XXX We need to fix these when libc |
| * support becomes availble in GRUB. |
| */ |
| |
| #ifndef GRUB_UTIL |
| #define stdin 0 |
| #define stdout 0 |
| |
| #define fprintf(...) 0 |
| #define exit(...) |
| #endif |
| |
| } |
| |
| %option ecs |
| %option meta-ecs |
| |
| %option warn |
| %option array |
| %option stack |
| %option reentrant |
| %option bison-bridge |
| %option never-interactive |
| |
| %option noyyfree noyyalloc noyyrealloc |
| %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 |
| %option noyyget_debug noyyset_debug |
| %option noyyget_lineno noyyset_lineno |
| |
| %option extra-type="struct grub_parser_param*" |
| |
| BLANK [ \t] |
| COMMENT #.*$ |
| |
| CHAR [^{}|&$;<> \t\n\'\"\\] |
| DIGITS [[:digit:]]+ |
| NAME [[:alpha:]_][[:alnum:]_]* |
| |
| ESC \\(.|\n) |
| SQCHR [^\'] |
| DQCHR {ESC}|[^\\\"] |
| DQSTR \"{DQCHR}*\" |
| I18NSTR \$\"{DQCHR}*\" |
| SQSTR \'{SQCHR}*\' |
| SPECIAL \?|\#|\*|\@ |
| VARIABLE ${NAME}|$\{{NAME}\}|${DIGITS}|$\{{DIGITS}\}|${SPECIAL}|$\{{SPECIAL}\} |
| WORD ({CHAR}|{DQSTR}|{SQSTR}|{ESC}|{VARIABLE}|{I18NSTR})+ |
| |
| MULTILINE {WORD}?((\"{DQCHR}*)|(\$\"{DQCHR}*)|(\'{SQCHR}*)) |
| POS_MULTILINE {WORD}?\\\n |
| |
| %x SPLIT |
| %x DQUOTE |
| %x I18NQUOTE |
| %x SQUOTE |
| %x VAR |
| |
| %% |
| |
| /* White spaces */ |
| {BLANK}+ { RECORD; } |
| {COMMENT} { RECORD; } |
| |
| /* Special symbols */ |
| "\n" { RECORD; return GRUB_PARSER_TOKEN_NEWLINE; } |
| "||" { RECORD; return GRUB_PARSER_TOKEN_OR; } |
| "&&" { RECORD; return GRUB_PARSER_TOKEN_AND; } |
| ";;" { RECORD; return GRUB_PARSER_TOKEN_SEMI2; } |
| "|" { RECORD; return GRUB_PARSER_TOKEN_PIPE; } |
| "&" { RECORD; return GRUB_PARSER_TOKEN_AMP; } |
| ";" { RECORD; return GRUB_PARSER_TOKEN_SEMI; } |
| "<" { RECORD; return GRUB_PARSER_TOKEN_LT; } |
| ">" { RECORD; return GRUB_PARSER_TOKEN_GT; } |
| |
| /* Reserved words */ |
| "{" { RECORD; return GRUB_PARSER_TOKEN_LBR; } |
| "}" { RECORD; return GRUB_PARSER_TOKEN_RBR; } |
| "[[" { RECORD; return GRUB_PARSER_TOKEN_RSQBR2; } |
| "]]" { RECORD; return GRUB_PARSER_TOKEN_LSQBR2; } |
| "case" { RECORD; return GRUB_PARSER_TOKEN_CASE; } |
| "do" { RECORD; return GRUB_PARSER_TOKEN_DO; } |
| "done" { RECORD; return GRUB_PARSER_TOKEN_DONE; } |
| "elif" { RECORD; return GRUB_PARSER_TOKEN_ELIF; } |
| "else" { RECORD; return GRUB_PARSER_TOKEN_ELSE; } |
| "esac" { RECORD; return GRUB_PARSER_TOKEN_ESAC; } |
| "fi" { RECORD; return GRUB_PARSER_TOKEN_FI; } |
| "for" { RECORD; return GRUB_PARSER_TOKEN_FOR; } |
| "if" { RECORD; return GRUB_PARSER_TOKEN_IF; } |
| "in" { RECORD; return GRUB_PARSER_TOKEN_IN; } |
| "select" { RECORD; return GRUB_PARSER_TOKEN_SELECT; } |
| "then" { RECORD; return GRUB_PARSER_TOKEN_THEN; } |
| "until" { RECORD; return GRUB_PARSER_TOKEN_UNTIL; } |
| "while" { RECORD; return GRUB_PARSER_TOKEN_WHILE; } |
| "function" { RECORD; return GRUB_PARSER_TOKEN_FUNCTION; } |
| |
| {MULTILINE} { |
| if (grub_lexer_unput (yytext, yyscanner)) |
| return GRUB_PARSER_TOKEN_BAD; |
| } |
| |
| {POS_MULTILINE} { |
| if (yyg->yy_c_buf_p + 1 == &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] ) |
| { |
| if (grub_lexer_unput (yytext, yyscanner)) |
| return GRUB_PARSER_TOKEN_BAD; |
| } |
| else |
| { |
| RECORD; |
| 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; |
| } |
| } |
| |
| |
| {NAME} { RECORD; return GRUB_PARSER_TOKEN_NAME; } |
| {WORD} { |
| RECORD; |
| 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; |
| } |
| . { |
| grub_script_yyerror (yyextra, yytext); |
| return GRUB_PARSER_TOKEN_BAD; |
| } |
| |
| /* Split word into multiple args */ |
| |
| <SPLIT>{ |
| \\. { COPY (yytext, yyleng); } |
| \\\n { /* ignore */ } |
| \" { |
| yy_push_state (DQUOTE, yyscanner); |
| ARG (GRUB_SCRIPT_ARG_TYPE_TEXT); |
| } |
| \' { |
| yy_push_state (SQUOTE, yyscanner); |
| ARG (GRUB_SCRIPT_ARG_TYPE_TEXT); |
| } |
| "\$\"" { |
| yy_push_state (I18NQUOTE, yyscanner); |
| ARG (GRUB_SCRIPT_ARG_TYPE_GETTEXT); |
| } |
| \$ { |
| yy_push_state (VAR, yyscanner); |
| ARG (GRUB_SCRIPT_ARG_TYPE_TEXT); |
| } |
| \\ | |
| [^\"\'\$\\]+ { COPY (yytext, yyleng); } |
| <<EOF>> { |
| yy_pop_state (yyscanner); |
| yypop_buffer_state (yyscanner); |
| yyextra->lexerstate->resplit = 0; |
| yyextra->lexerstate->merge_end = 1; |
| ARG (GRUB_SCRIPT_ARG_TYPE_TEXT); |
| } |
| } |
| |
| <VAR>{ |
| {SPECIAL} | |
| {DIGITS} | |
| {NAME} { |
| COPY (yytext, yyleng); |
| yy_pop_state (yyscanner); |
| if (YY_START == SPLIT) |
| ARG (GRUB_SCRIPT_ARG_TYPE_VAR); |
| else |
| ARG (GRUB_SCRIPT_ARG_TYPE_DQVAR); |
| } |
| \{{SPECIAL}\} | |
| \{{DIGITS}\} | |
| \{{NAME}\} { |
| yytext[yyleng - 1] = '\0'; |
| COPY (yytext + 1, yyleng - 2); |
| yy_pop_state (yyscanner); |
| if (YY_START == SPLIT) |
| ARG (GRUB_SCRIPT_ARG_TYPE_VAR); |
| else |
| ARG (GRUB_SCRIPT_ARG_TYPE_DQVAR); |
| } |
| .|\n { return GRUB_PARSER_TOKEN_BAD; } |
| } |
| |
| <SQUOTE>{ |
| \' { |
| yy_pop_state (yyscanner); |
| ARG (GRUB_SCRIPT_ARG_TYPE_SQSTR); |
| } |
| [^\']+ { COPY (yytext, yyleng); } |
| } |
| |
| <DQUOTE>{ |
| \\\$ { COPY ("$", 1); } |
| \\\\ { COPY ("\\", 1); } |
| \\\" { COPY ("\"", 1); } |
| \\\n { /* ignore */ } |
| [^\"\$\\\n]+ { COPY (yytext, yyleng); } |
| \" { |
| yy_pop_state (yyscanner); |
| ARG (GRUB_SCRIPT_ARG_TYPE_DQSTR); |
| } |
| \$ { |
| yy_push_state (VAR, yyscanner); |
| ARG (GRUB_SCRIPT_ARG_TYPE_DQSTR); |
| } |
| (.|\n) { COPY (yytext, yyleng); } |
| } |
| |
| <I18NQUOTE>{ |
| \\\\ { COPY ("\\\\", 2); } |
| \\\" { COPY ("\"", 1); } |
| \\\n { /* ignore */ } |
| [^\"\\\n]+ { COPY (yytext, yyleng); } |
| \" { |
| yy_pop_state (yyscanner); |
| ARG (GRUB_SCRIPT_ARG_TYPE_GETTEXT); |
| } |
| \\ { COPY ("\\", 1); } |
| (.|\n) { COPY (yytext, yyleng); } |
| } |
| |
| <<EOF>> { |
| yypop_buffer_state (yyscanner); |
| 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))) |
| { |
| grub_free(ptr); |
| } |
| |
| static void* |
| grub_lexer_yyalloc (yy_size_t size, yyscan_t yyscanner __attribute__ ((unused))) |
| { |
| return grub_malloc (size); |
| } |
| |
| static void* |
| grub_lexer_yyrealloc (void *ptr, yy_size_t size, |
| yyscan_t yyscanner __attribute__ ((unused))) |
| { |
| return grub_realloc (ptr, size); |
| } |
| |
| static void copy_string (struct grub_parser_param *parser, const char *str, unsigned hint) |
| { |
| grub_size_t size; |
| char *ptr; |
| unsigned len; |
| |
| len = hint ? hint : grub_strlen (str); |
| if (parser->lexerstate->used + len >= parser->lexerstate->size) |
| { |
| size = len * 2; |
| if (size < parser->lexerstate->size * 2) |
| size = parser->lexerstate->size * 2; |
| ptr = grub_realloc (parser->lexerstate->text, size); |
| if (!ptr) |
| { |
| grub_script_yyerror (parser, 0); |
| return; |
| } |
| |
| parser->lexerstate->text = ptr; |
| parser->lexerstate->size = size; |
| } |
| 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; |
| |
| grub_free (lexerstate->prefix); |
| |
| lexerstate->prefix = grub_strdup (text); |
| if (! lexerstate->prefix) |
| { |
| grub_script_yyerror (yyget_extra (yyscanner), N_("out of memory")); |
| return 1; |
| } |
| return 0; |
| } |