~ubuntu-branches/debian/sid/grub2/sid-200907171837

« back to all changes in this revision

Viewing changes to normal/lexer.c

  • Committer: Bazaar Package Importer
  • Author(s): Robert Millan
  • Date: 2009-07-02 13:23:51 UTC
  • mfrom: (1.1.10 upstream)
  • Revision ID: james.westby@ubuntu.com-20090702132351-tanpn0ryyijp93gu
Tags: 1.96+20090702-1
* New SVN snapshot.
* rules: Remove duplicated files in sparc64-ieee1275 port.
* rules: Comment out -DGRUB_ASSUME_LINUX_HAS_FB_SUPPORT=1 setting.  We'll
  re-evaluate using it when it's more mature.  (Closes: #535026).

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* lexer.c - The scripting lexer.  */
2
 
/*
3
 
 *  GRUB  --  GRand Unified Bootloader
4
 
 *  Copyright (C) 2005,2006,2007  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 <grub/parser.h>
21
 
#include <grub/misc.h>
22
 
#include <grub/mm.h>
23
 
#include <grub/script.h>
24
 
 
25
 
#include "grub_script.tab.h"
26
 
 
27
 
static int
28
 
check_varstate (grub_parser_state_t state)
29
 
{
30
 
  return (state == GRUB_PARSER_STATE_VARNAME
31
 
          || state == GRUB_PARSER_STATE_VAR
32
 
          || state == GRUB_PARSER_STATE_QVAR
33
 
          || state == GRUB_PARSER_STATE_VARNAME2
34
 
          || state == GRUB_PARSER_STATE_QVARNAME
35
 
          || state == GRUB_PARSER_STATE_QVARNAME2);
36
 
}
37
 
 
38
 
static int
39
 
check_textstate (grub_parser_state_t state)
40
 
{
41
 
  return (state == GRUB_PARSER_STATE_TEXT
42
 
          || state == GRUB_PARSER_STATE_QUOTE
43
 
          || state == GRUB_PARSER_STATE_DQUOTE);
44
 
}
45
 
 
46
 
struct grub_lexer_param *
47
 
grub_script_lexer_init (char *script, grub_err_t (*getline) (char **))
48
 
{
49
 
  struct grub_lexer_param *param;
50
 
 
51
 
  param = grub_malloc (sizeof (*param));
52
 
  if (! param)
53
 
    return 0;
54
 
 
55
 
  param->state = GRUB_PARSER_STATE_TEXT;
56
 
  param->getline = getline;
57
 
  param->refs = 0;
58
 
  param->done = 0;
59
 
  param->newscript = 0;
60
 
  param->script = script;
61
 
  param->record = 0;
62
 
  param->recording = 0;
63
 
  param->recordpos = 0;
64
 
  param->recordlen = 0;
65
 
 
66
 
  return param;
67
 
}
68
 
 
69
 
void
70
 
grub_script_lexer_ref (struct grub_lexer_param *state)
71
 
{
72
 
  state->refs++;
73
 
}
74
 
 
75
 
void
76
 
grub_script_lexer_deref (struct grub_lexer_param *state)
77
 
{
78
 
  state->refs--;
79
 
}
80
 
 
81
 
/* Start recording all characters passing through the lexer.  */
82
 
void
83
 
grub_script_lexer_record_start (struct grub_lexer_param *state)
84
 
{
85
 
  state->record = 1;
86
 
  state->recordlen = 100;
87
 
  state->recording = grub_malloc (state->recordlen);
88
 
  state->recordpos = 0;
89
 
}
90
 
 
91
 
char *
92
 
grub_script_lexer_record_stop (struct grub_lexer_param *state)
93
 
{
94
 
  state->record = 0;
95
 
 
96
 
  /* Delete the last character, it is a `}'.  */
97
 
  if (state->recordpos > 0)
98
 
    {
99
 
      if (state->recording[--state->recordpos] != '}')
100
 
        {
101
 
          grub_printf ("Internal error while parsing menu entry");
102
 
          for (;;); /* XXX */
103
 
        }
104
 
      state->recording[state->recordpos] = '\0';
105
 
    }
106
 
 
107
 
  return state->recording;
108
 
}
109
 
 
110
 
/* When recording is enabled, record the character C as the next item
111
 
   in the character stream.  */
112
 
static void
113
 
recordchar (struct grub_lexer_param *state, char c)
114
 
{
115
 
  if (state->recordpos == state->recordlen)
116
 
    {
117
 
      char *old = state->recording;
118
 
      state->recordlen += 100;
119
 
      state->recording = grub_realloc (state->recording, state->recordlen);
120
 
      if (! state->recording)
121
 
        {
122
 
          grub_free (old);
123
 
          state->record = 0;
124
 
        }
125
 
    }
126
 
  state->recording[state->recordpos++] = c;
127
 
}
128
 
 
129
 
/* Fetch the next character for the lexer.  */
130
 
static void
131
 
nextchar (struct grub_lexer_param *state)
132
 
{
133
 
  if (state->record)
134
 
    recordchar (state, *state->script);
135
 
  state->script++;
136
 
}
137
 
 
138
 
int
139
 
grub_script_yylex2 (YYSTYPE *yylval, struct grub_parser_param *parsestate);
140
 
 
141
 
int
142
 
grub_script_yylex (YYSTYPE *yylval, struct grub_parser_param *parsestate)
143
 
{
144
 
  int r = -1;
145
 
 
146
 
  while (r == -1)
147
 
    {
148
 
      r = grub_script_yylex2 (yylval, parsestate);
149
 
      if (r == ' ')
150
 
        r = -1;
151
 
    }
152
 
  return r;
153
 
}
154
 
 
155
 
int
156
 
grub_script_yylex2 (YYSTYPE *yylval, struct grub_parser_param *parsestate)
157
 
{
158
 
  grub_parser_state_t newstate;
159
 
  char use;
160
 
  char *buffer;
161
 
  char *bp;
162
 
  struct grub_lexer_param *state = parsestate->lexerstate;
163
 
 
164
 
  if (state->done)
165
 
    return 0;
166
 
 
167
 
  if (! *state->script)
168
 
    {
169
 
      /* Check if more tokens are requested by the parser.  */
170
 
      if ((state->refs
171
 
           || state->state == GRUB_PARSER_STATE_ESC)
172
 
          && state->getline)
173
 
        {
174
 
          while (!state->script || ! grub_strlen (state->script))
175
 
            {
176
 
              grub_free (state->newscript);
177
 
              state->newscript = 0;
178
 
              state->getline (&state->newscript);
179
 
              state->script = state->newscript;
180
 
              if (! state->script)
181
 
                return 0;
182
 
            }
183
 
          grub_dprintf ("scripting", "token=`\\n'\n");
184
 
          recordchar (state, '\n');
185
 
          if (state->state != GRUB_PARSER_STATE_ESC)
186
 
            return '\n';
187
 
        }
188
 
      else
189
 
        {
190
 
          grub_free (state->newscript);
191
 
          state->newscript = 0;
192
 
          state->done = 1;
193
 
          grub_dprintf ("scripting", "token=`\\n'\n");
194
 
          return '\n';
195
 
        }
196
 
    }
197
 
 
198
 
  newstate = grub_parser_cmdline_state (state->state, *state->script, &use);
199
 
 
200
 
  /* Check if it is a text.  */
201
 
  if (check_textstate (newstate))
202
 
    {
203
 
      /* In case the string is not quoted, this can be a one char
204
 
         length symbol.  */
205
 
      if (newstate == GRUB_PARSER_STATE_TEXT)
206
 
        {
207
 
          switch (*state->script)
208
 
            {
209
 
            case ' ':
210
 
              while (*state->script)
211
 
                {
212
 
                  newstate = grub_parser_cmdline_state (state->state,
213
 
                                                        *state->script, &use);
214
 
                  if (! (state->state == GRUB_PARSER_STATE_TEXT
215
 
                         && *state->script == ' '))
216
 
                    {
217
 
                      grub_dprintf ("scripting", "token=` '\n");
218
 
                      return ' ';
219
 
                    }
220
 
                  state->state = newstate;
221
 
                  nextchar (state);
222
 
                }
223
 
              grub_dprintf ("scripting", "token=` '\n");
224
 
              return ' ';
225
 
            case '{':
226
 
            case '}':
227
 
            case ';':
228
 
            case '\n':
229
 
              {
230
 
                char c;
231
 
                grub_dprintf ("scripting", "token=`%c'\n", *state->script);
232
 
                c = *state->script;;
233
 
                nextchar (state);
234
 
                return c;
235
 
              }
236
 
            }
237
 
        }
238
 
 
239
 
      /* XXX: Use a better size.  */
240
 
      buffer = grub_script_malloc (parsestate, 2048);
241
 
      if (! buffer)
242
 
        return 0;
243
 
 
244
 
      bp = buffer;
245
 
 
246
 
      /* Read one token, possible quoted.  */
247
 
      while (*state->script)
248
 
        {
249
 
          newstate = grub_parser_cmdline_state (state->state,
250
 
                                                *state->script, &use);
251
 
 
252
 
          /* Check if a variable name starts.  */
253
 
          if (check_varstate (newstate))
254
 
            break;
255
 
 
256
 
          /* If the string is not quoted or escaped, stop processing
257
 
             when a special token was found.  It will be recognized
258
 
             next time when this function is called.  */
259
 
          if (newstate == GRUB_PARSER_STATE_TEXT
260
 
              && state->state != GRUB_PARSER_STATE_ESC)
261
 
            {
262
 
              int breakout = 0;
263
 
 
264
 
              switch (use)
265
 
                {
266
 
                case ' ':
267
 
                case '{':
268
 
                case '}':
269
 
                case ';':
270
 
                case '\n':
271
 
                  breakout = 1;
272
 
                }
273
 
              if (breakout)
274
 
                break;
275
 
              *(bp++) = use;
276
 
            }
277
 
          else if (use)
278
 
            *(bp++) = use;
279
 
 
280
 
          state->state = newstate;
281
 
          nextchar (state);
282
 
        }
283
 
 
284
 
      /* A string of text was read in.  */
285
 
      *bp = '\0';
286
 
      grub_dprintf ("scripting", "token=`%s'\n", buffer);
287
 
      yylval->string = buffer;
288
 
 
289
 
      /* Detect some special tokens.  */
290
 
      if (! grub_strcmp (buffer, "while"))
291
 
        return GRUB_PARSER_TOKEN_WHILE;
292
 
      else if (! grub_strcmp (buffer, "if"))
293
 
        return GRUB_PARSER_TOKEN_IF;
294
 
      else if (! grub_strcmp (buffer, "function"))
295
 
        return GRUB_PARSER_TOKEN_FUNCTION;
296
 
      else if (! grub_strcmp (buffer, "menuentry"))
297
 
        return GRUB_PARSER_TOKEN_MENUENTRY;
298
 
      else if (! grub_strcmp (buffer, "@"))
299
 
        return GRUB_PARSER_TOKEN_MENUENTRY;
300
 
      else if (! grub_strcmp (buffer, "else"))
301
 
        return GRUB_PARSER_TOKEN_ELSE;
302
 
      else if (! grub_strcmp (buffer, "then"))
303
 
        return GRUB_PARSER_TOKEN_THEN;
304
 
      else if (! grub_strcmp (buffer, "fi"))
305
 
        return GRUB_PARSER_TOKEN_FI;
306
 
      else
307
 
        return GRUB_PARSER_TOKEN_NAME;
308
 
    }
309
 
  else if (newstate == GRUB_PARSER_STATE_VAR
310
 
           || newstate == GRUB_PARSER_STATE_QVAR)
311
 
    {
312
 
      /* XXX: Use a better size.  */
313
 
      buffer = grub_script_malloc (parsestate, 2096);
314
 
      if (! buffer)
315
 
        return 0;
316
 
 
317
 
      bp = buffer;
318
 
 
319
 
      /* This is a variable, read the variable name.  */
320
 
      while (*state->script)
321
 
        {
322
 
          newstate = grub_parser_cmdline_state (state->state,
323
 
                                                *state->script, &use);
324
 
 
325
 
          /* Check if this character is not part of the variable name
326
 
             anymore.  */
327
 
          if (! (check_varstate (newstate)))
328
 
            {
329
 
              if (state->state == GRUB_PARSER_STATE_VARNAME2
330
 
                  || state->state == GRUB_PARSER_STATE_QVARNAME2)
331
 
                nextchar (state);
332
 
              state->state = newstate;
333
 
              break;
334
 
            }
335
 
 
336
 
          if (use)
337
 
            *(bp++) = use;
338
 
          nextchar (state);
339
 
          state->state = newstate;
340
 
        }
341
 
 
342
 
      *bp = '\0';
343
 
      state->state = newstate;
344
 
      yylval->string = buffer;
345
 
      grub_dprintf ("scripting", "vartoken=`%s'\n", buffer);
346
 
 
347
 
      return GRUB_PARSER_TOKEN_VAR;
348
 
    }
349
 
  else
350
 
    {
351
 
      /* There is either text or a variable name.  In the case you
352
 
         arrive here there is a serious problem with the lexer.  */
353
 
      grub_error (GRUB_ERR_BAD_ARGUMENT, "Internal error\n");
354
 
      return 0;
355
 
    }
356
 
}
357
 
 
358
 
void
359
 
grub_script_yyerror (struct grub_parser_param *lex __attribute__ ((unused)),
360
 
                     char const *err)
361
 
{
362
 
  grub_printf ("%s\n", err);
363
 
}