source: grub-pc/trunk/fuentes/grub-core/script/lexer.c @ 22

Last change on this file since 22 was 22, checked in by mabarracus, 4 years ago

updated version and apply net.ifnames=0 into debian/rules

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