]> git.proxmox.com Git - grub2.git/blame - grub-core/script/lexer.c
* grub-core/normal/menu_entry.c (run): Quieten uninitialised
[grub2.git] / grub-core / script / lexer.c
CommitLineData
daac212a 1/* lexer.c - The scripting lexer. */
2/*
3 * GRUB -- GRand Unified Bootloader
547e494f 4 * Copyright (C) 2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc.
daac212a 5 *
5a79f472 6 * GRUB is free software: you can redistribute it and/or modify
daac212a 7 * it under the terms of the GNU General Public License as published by
5a79f472 8 * the Free Software Foundation, either version 3 of the License, or
daac212a 9 * (at your option) any later version.
10 *
5a79f472 11 * GRUB is distributed in the hope that it will be useful,
daac212a 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.
15 *
16 * You should have received a copy of the GNU General Public License
5a79f472 17 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
daac212a 18 */
19
1d12cf29
YB
20#include <config.h>
21
daac212a 22#include <grub/parser.h>
23#include <grub/misc.h>
24#include <grub/mm.h>
d558e6b5 25#include <grub/script_sh.h>
daac212a 26
27#include "grub_script.tab.h"
547e494f 28#include "grub_script.yy.h"
daac212a 29
30void
bfa2bd9e 31grub_script_lexer_ref (struct grub_lexer_param *state)
daac212a 32{
bfa2bd9e 33 state->refs++;
daac212a 34}
35
36void
bfa2bd9e 37grub_script_lexer_deref (struct grub_lexer_param *state)
daac212a 38{
bfa2bd9e 39 state->refs--;
daac212a 40}
41
77c4a393 42/* Start recording all characters passing through the lexer. */
0993355a 43unsigned
547e494f 44grub_script_lexer_record_start (struct grub_parser_param *parser)
77c4a393 45{
547e494f
BC
46 struct grub_lexer_param *lexer = parser->lexerstate;
47
0993355a
BC
48 lexer->record++;
49 if (lexer->recording)
50 return lexer->recordpos;
547e494f 51
0993355a 52 lexer->recordpos = 0;
bae09d0d 53 lexer->recordlen = GRUB_LEXER_INITIAL_RECORD_SIZE;
547e494f 54 lexer->recording = grub_malloc (lexer->recordlen);
547e494f
BC
55 if (!lexer->recording)
56 {
57 grub_script_yyerror (parser, 0);
547e494f
BC
58 lexer->recordlen = 0;
59 }
0993355a 60 return lexer->recordpos;
77c4a393 61}
62
63char *
0993355a 64grub_script_lexer_record_stop (struct grub_parser_param *parser, unsigned offset)
77c4a393 65{
0993355a 66 int count;
547e494f
BC
67 char *result;
68 struct grub_lexer_param *lexer = parser->lexerstate;
69
0993355a 70 if (!lexer->record)
547e494f 71 return 0;
77c4a393 72
0993355a
BC
73 lexer->record--;
74 if (!lexer->recording)
75 return 0;
547e494f 76
0993355a
BC
77 count = lexer->recordpos - offset;
78 result = grub_script_malloc (parser, count + 1);
79 if (result) {
80 grub_strncpy (result, lexer->recording + offset, count);
81 result[count] = '\0';
82 }
547e494f 83
0993355a
BC
84 if (lexer->record == 0)
85 {
86 grub_free (lexer->recording);
87 lexer->recording = 0;
88 lexer->recordlen = 0;
89 lexer->recordpos = 0;
90 }
547e494f 91 return result;
77c4a393 92}
93
547e494f
BC
94/* Record STR if input recording is enabled. */
95void
96grub_script_lexer_record (struct grub_parser_param *parser, char *str)
77c4a393 97{
547e494f 98 int len;
bae09d0d 99 char *old;
547e494f
BC
100 struct grub_lexer_param *lexer = parser->lexerstate;
101
0993355a 102 if (!lexer->record || !lexer->recording)
547e494f
BC
103 return;
104
105 len = grub_strlen (str);
bae09d0d 106 if (lexer->recordpos + len + 1 > lexer->recordlen)
77c4a393 107 {
bae09d0d 108 old = lexer->recording;
0993355a 109 lexer->recordlen = grub_max (len, lexer->recordlen) * 2;
547e494f
BC
110 lexer->recording = grub_realloc (lexer->recording, lexer->recordlen);
111 if (!lexer->recording)
77c4a393 112 {
113 grub_free (old);
bae09d0d 114 lexer->recordpos = 0;
0993355a 115 lexer->recordlen = 0;
547e494f
BC
116 grub_script_yyerror (parser, 0);
117 return;
77c4a393 118 }
119 }
547e494f
BC
120 grub_strcpy (lexer->recording + lexer->recordpos, str);
121 lexer->recordpos += len;
77c4a393 122}
123
547e494f 124/* Read next line of input if necessary, and set yyscanner buffers. */
daac212a 125int
b06f83e3
BC
126grub_script_lexer_yywrap (struct grub_parser_param *parserstate,
127 const char *input)
daac212a 128{
05d2ed32 129 int len = 0;
b06f83e3
BC
130 char *p = 0;
131 char *line = 0;
547e494f
BC
132 YY_BUFFER_STATE buffer;
133 struct grub_lexer_param *lexerstate = parserstate->lexerstate;
daac212a 134
b06f83e3
BC
135 if (! lexerstate->refs && ! lexerstate->prefix && ! input)
136 return 1;
547e494f 137
b06f83e3 138 if (! lexerstate->getline && ! input)
547e494f
BC
139 {
140 grub_script_yyerror (parserstate, "unexpected end of file");
b06f83e3 141 return 1;
547e494f 142 }
daac212a 143
547e494f 144 line = 0;
b06f83e3
BC
145 if (! input)
146 lexerstate->getline (&line, 1);
147 else
148 line = grub_strdup (input);
0500dfd1
BC
149
150 /* Ensure '\n' at the end. */
151 if (line && line[0] == '\0')
daac212a 152 {
0500dfd1
BC
153 grub_free (line);
154 line = grub_strdup ("\n");
daac212a 155 }
156
0500dfd1 157 if (line && (len = grub_strlen(line)) && line[len - 1] != '\n')
547e494f 158 {
0500dfd1
BC
159 p = grub_realloc (line, len + 2);
160 if (p)
161 {
162 p[len++] = '\n';
163 p[len] = '\0';
164 }
165 line = p;
547e494f 166 }
0500dfd1 167
b06f83e3 168 if (! line)
daac212a 169 {
0500dfd1 170 grub_script_yyerror (parserstate, "out of memory");
b06f83e3 171 return 1;
daac212a 172 }
173
0500dfd1 174 /* Prepend any left over unput-text. */
b06f83e3 175 if (lexerstate->prefix)
daac212a 176 {
b06f83e3
BC
177 int plen = grub_strlen (lexerstate->prefix);
178
0500dfd1 179 p = grub_malloc (len + plen + 1);
b06f83e3 180 if (! p)
daac212a 181 {
b06f83e3
BC
182 grub_free (line);
183 return 1;
daac212a 184 }
b06f83e3
BC
185 grub_strcpy (p, lexerstate->prefix);
186 lexerstate->prefix = 0;
187
b06f83e3 188 grub_strcpy (p + plen, line);
0500dfd1 189 grub_free (line);
b06f83e3
BC
190
191 line = p;
192 len = len + plen;
547e494f
BC
193 }
194
b06f83e3 195 buffer = yy_scan_string (line, lexerstate->yyscanner);
547e494f 196 grub_free (line);
b06f83e3
BC
197
198 if (! buffer)
547e494f
BC
199 {
200 grub_script_yyerror (parserstate, 0);
b06f83e3 201 return 1;
547e494f 202 }
b06f83e3 203 return 0;
547e494f 204}
daac212a 205
547e494f
BC
206struct grub_lexer_param *
207grub_script_lexer_init (struct grub_parser_param *parser, char *script,
208 grub_reader_getline_t getline)
209{
547e494f
BC
210 struct grub_lexer_param *lexerstate;
211
212 lexerstate = grub_zalloc (sizeof (*lexerstate));
213 if (!lexerstate)
214 return 0;
215
df6dc211
BC
216 lexerstate->size = GRUB_LEXER_INITIAL_TEXT_SIZE;
217 lexerstate->text = grub_malloc (lexerstate->size);
547e494f
BC
218 if (!lexerstate->text)
219 {
220 grub_free (lexerstate);
221 return 0;
222 }
b39f9d20 223
547e494f
BC
224 lexerstate->getline = getline; /* rest are all zeros already */
225 if (yylex_init (&lexerstate->yyscanner))
226 {
227 grub_free (lexerstate->text);
228 grub_free (lexerstate);
229 return 0;
230 }
231
b06f83e3
BC
232 yyset_extra (parser, lexerstate->yyscanner);
233 parser->lexerstate = lexerstate;
547e494f 234
b06f83e3 235 if (grub_script_lexer_yywrap (parser, script ?: "\n"))
547e494f 236 {
b06f83e3 237 parser->lexerstate = 0;
547e494f
BC
238 yylex_destroy (lexerstate->yyscanner);
239 grub_free (lexerstate->yyscanner);
547e494f
BC
240 grub_free (lexerstate->text);
241 grub_free (lexerstate);
242 return 0;
243 }
547e494f
BC
244
245 return lexerstate;
246}
247
248void
249grub_script_lexer_fini (struct grub_lexer_param *lexerstate)
250{
251 if (!lexerstate)
252 return;
253
254 yylex_destroy (lexerstate->yyscanner);
255
256 grub_free (lexerstate->recording);
257 grub_free (lexerstate->text);
258 grub_free (lexerstate);
259}
260
261int
262grub_script_yylex (union YYSTYPE *value,
263 struct grub_parser_param *parserstate)
264{
265 char *str;
266 int token;
267 grub_script_arg_type_t type;
268 struct grub_lexer_param *lexerstate = parserstate->lexerstate;
269
270 value->arg = 0;
271 if (parserstate->err)
272 return GRUB_PARSER_TOKEN_BAD;
273
274 if (lexerstate->eof)
275 return GRUB_PARSER_TOKEN_EOF;
276
277 /*
278 * Words with environment variables, like foo${bar}baz needs
279 * multiple tokens to be merged into a single grub_script_arg. We
280 * use two variables to achieve this: lexerstate->merge_start and
281 * lexerstate->merge_end
282 */
283
284 lexerstate->merge_start = 0;
285 lexerstate->merge_end = 0;
286 do
287 {
288 /* Empty lexerstate->text. */
df6dc211 289 lexerstate->used = 1;
547e494f
BC
290 lexerstate->text[0] = '\0';
291
292 token = yylex (value, lexerstate->yyscanner);
293 if (token == GRUB_PARSER_TOKEN_BAD)
294 break;
295
296 /* Merging feature uses lexerstate->text instead of yytext. */
297 if (lexerstate->merge_start)
fda6cb98 298 {
547e494f
BC
299 str = lexerstate->text;
300 type = lexerstate->type;
daac212a 301 }
fda6cb98 302 else
303 {
547e494f
BC
304 str = yyget_text (lexerstate->yyscanner);
305 type = GRUB_SCRIPT_ARG_TYPE_TEXT;
fda6cb98 306 }
83672756 307 grub_dprintf("lexer", "token %u text [%s]\n", token, str);
b39f9d20 308
547e494f 309 value->arg = grub_script_arg_add (parserstate, value->arg, type, str);
fda6cb98 310 }
547e494f 311 while (lexerstate->merge_start && !lexerstate->merge_end);
daac212a 312
547e494f
BC
313 if (!value->arg || parserstate->err)
314 return GRUB_PARSER_TOKEN_BAD;
daac212a 315
547e494f 316 return token;
daac212a 317}
318
319void
547e494f 320grub_script_yyerror (struct grub_parser_param *state, char const *err)
daac212a 321{
547e494f
BC
322 if (err)
323 grub_error (GRUB_ERR_INVALID_COMMAND, err);
324
325 grub_print_error ();
326 state->err++;
daac212a 327}