1 /* lexer.c - The scripting lexer. */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc.
6 * GRUB is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * GRUB is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
22 #include <grub/parser.h>
23 #include <grub/misc.h>
25 #include <grub/script_sh.h>
26 #include <grub/i18n.h>
28 #define yytext_ptr char *
29 #include "grub_script.tab.h"
30 #include "grub_script.yy.h"
33 grub_script_lexer_ref (struct grub_lexer_param
*state
)
39 grub_script_lexer_deref (struct grub_lexer_param
*state
)
44 /* Start recording all characters passing through the lexer. */
46 grub_script_lexer_record_start (struct grub_parser_param
*parser
)
48 struct grub_lexer_param
*lexer
= parser
->lexerstate
;
52 return lexer
->recordpos
;
55 lexer
->recordlen
= GRUB_LEXER_INITIAL_RECORD_SIZE
;
56 lexer
->recording
= grub_malloc (lexer
->recordlen
);
57 if (!lexer
->recording
)
59 grub_script_yyerror (parser
, 0);
62 return lexer
->recordpos
;
66 grub_script_lexer_record_stop (struct grub_parser_param
*parser
, unsigned offset
)
70 struct grub_lexer_param
*lexer
= parser
->lexerstate
;
76 if (!lexer
->recording
)
79 count
= lexer
->recordpos
- offset
;
80 result
= grub_script_malloc (parser
, count
+ 1);
82 grub_strncpy (result
, lexer
->recording
+ offset
, count
);
86 if (lexer
->record
== 0)
88 grub_free (lexer
->recording
);
96 /* Record STR if input recording is enabled. */
98 grub_script_lexer_record (struct grub_parser_param
*parser
, char *str
)
102 struct grub_lexer_param
*lexer
= parser
->lexerstate
;
104 if (!lexer
->record
|| !lexer
->recording
)
107 len
= grub_strlen (str
);
108 if (lexer
->recordpos
+ len
+ 1 > lexer
->recordlen
)
110 old
= lexer
->recording
;
111 if (lexer
->recordlen
< len
)
112 lexer
->recordlen
= len
;
113 lexer
->recordlen
*= 2;
114 lexer
->recording
= grub_realloc (lexer
->recording
, lexer
->recordlen
);
115 if (!lexer
->recording
)
118 lexer
->recordpos
= 0;
119 lexer
->recordlen
= 0;
120 grub_script_yyerror (parser
, 0);
124 grub_strcpy (lexer
->recording
+ lexer
->recordpos
, str
);
125 lexer
->recordpos
+= len
;
128 /* Read next line of input if necessary, and set yyscanner buffers. */
130 grub_script_lexer_yywrap (struct grub_parser_param
*parserstate
,
136 YY_BUFFER_STATE buffer
;
137 struct grub_lexer_param
*lexerstate
= parserstate
->lexerstate
;
139 if (! lexerstate
->refs
&& ! lexerstate
->prefix
&& ! input
)
142 if (! lexerstate
->getline
&& ! input
)
144 grub_script_yyerror (parserstate
, N_("unexpected end of file"));
150 lexerstate
->getline (&line
, 1, lexerstate
->getline_data
);
152 line
= grub_strdup (input
);
156 grub_script_yyerror (parserstate
, N_("out of memory"));
160 len
= grub_strlen (line
);
162 /* Ensure '\n' at the end. */
166 line
= grub_strdup ("\n");
169 else if (len
&& line
[len
- 1] != '\n')
171 p
= grub_realloc (line
, len
+ 2);
182 grub_script_yyerror (parserstate
, N_("out of memory"));
186 /* Prepend any left over unput-text. */
187 if (lexerstate
->prefix
)
189 int plen
= grub_strlen (lexerstate
->prefix
);
191 p
= grub_malloc (len
+ plen
+ 1);
197 grub_strcpy (p
, lexerstate
->prefix
);
198 lexerstate
->prefix
= 0;
200 grub_strcpy (p
+ plen
, line
);
207 buffer
= yy_scan_string (line
, lexerstate
->yyscanner
);
212 grub_script_yyerror (parserstate
, 0);
218 struct grub_lexer_param
*
219 grub_script_lexer_init (struct grub_parser_param
*parser
, char *script
,
220 grub_reader_getline_t arg_getline
, void *getline_data
)
222 struct grub_lexer_param
*lexerstate
;
224 lexerstate
= grub_zalloc (sizeof (*lexerstate
));
228 lexerstate
->size
= GRUB_LEXER_INITIAL_TEXT_SIZE
;
229 lexerstate
->text
= grub_malloc (lexerstate
->size
);
230 if (!lexerstate
->text
)
232 grub_free (lexerstate
);
236 lexerstate
->getline
= arg_getline
;
237 lexerstate
->getline_data
= getline_data
;
238 /* The other elements of lexerstate are all zeros already. */
240 if (yylex_init (&lexerstate
->yyscanner
))
242 grub_free (lexerstate
->text
);
243 grub_free (lexerstate
);
247 yyset_extra (parser
, lexerstate
->yyscanner
);
248 parser
->lexerstate
= lexerstate
;
250 if (grub_script_lexer_yywrap (parser
, script
?: "\n"))
252 parser
->lexerstate
= 0;
253 yylex_destroy (lexerstate
->yyscanner
);
254 grub_free (lexerstate
->yyscanner
);
255 grub_free (lexerstate
->text
);
256 grub_free (lexerstate
);
264 grub_script_lexer_fini (struct grub_lexer_param
*lexerstate
)
269 yylex_destroy (lexerstate
->yyscanner
);
271 grub_free (lexerstate
->recording
);
272 grub_free (lexerstate
->text
);
273 grub_free (lexerstate
);
277 grub_script_yylex (union YYSTYPE
*value
,
278 struct grub_parser_param
*parserstate
)
282 grub_script_arg_type_t type
;
283 struct grub_lexer_param
*lexerstate
= parserstate
->lexerstate
;
286 if (parserstate
->err
)
287 return GRUB_PARSER_TOKEN_BAD
;
290 return GRUB_PARSER_TOKEN_EOF
;
293 * Words with environment variables, like foo${bar}baz needs
294 * multiple tokens to be merged into a single grub_script_arg. We
295 * use two variables to achieve this: lexerstate->merge_start and
296 * lexerstate->merge_end
299 lexerstate
->merge_start
= 0;
300 lexerstate
->merge_end
= 0;
303 /* Empty lexerstate->text. */
304 lexerstate
->used
= 1;
305 lexerstate
->text
[0] = '\0';
307 token
= yylex (value
, lexerstate
->yyscanner
);
308 if (token
== GRUB_PARSER_TOKEN_BAD
)
311 /* Merging feature uses lexerstate->text instead of yytext. */
312 if (lexerstate
->merge_start
)
314 str
= lexerstate
->text
;
315 type
= lexerstate
->type
;
319 str
= yyget_text (lexerstate
->yyscanner
);
320 type
= GRUB_SCRIPT_ARG_TYPE_TEXT
;
322 grub_dprintf("lexer", "token %u text [%s]\n", token
, str
);
324 value
->arg
= grub_script_arg_add (parserstate
, value
->arg
, type
, str
);
326 while (lexerstate
->merge_start
&& !lexerstate
->merge_end
);
328 if (!value
->arg
|| parserstate
->err
)
329 return GRUB_PARSER_TOKEN_BAD
;
335 grub_script_yyerror (struct grub_parser_param
*state
, char const *err
)
338 grub_error (GRUB_ERR_INVALID_COMMAND
, err
);