~darkmuggle-deactivatedaccount/ubuntu/quantal/grub2/fix-872244

« back to all changes in this revision

Viewing changes to normal/lexer.c

  • Committer: Bazaar Package Importer
  • Author(s): Otavio Salvador
  • Date: 2006-01-05 15:20:40 UTC
  • mto: (17.3.1 squeeze) (1.9.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 4.
  • Revision ID: james.westby@ubuntu.com-20060105152040-b72i5pq1a82z22yi
Tags: upstream-1.92
ImportĀ upstreamĀ versionĀ 1.92

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  Free Software Foundation, Inc.
 
5
 *
 
6
 *  This program 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 2 of the License, or
 
9
 *  (at your option) any later version.
 
10
 *
 
11
 *  This program 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 this program; if not, write to the Free Software
 
18
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
19
 */
 
20
 
 
21
#include <grub/parser.h>
 
22
#include <grub/misc.h>
 
23
#include <grub/mm.h>
 
24
#include <grub/script.h>
 
25
 
 
26
#include "grub_script.tab.h"
 
27
 
 
28
static grub_parser_state_t grub_script_lexer_state;
 
29
static int grub_script_lexer_done = 0;
 
30
static grub_err_t (*grub_script_lexer_getline) (char **);
 
31
 
 
32
static int
 
33
check_varstate (grub_parser_state_t state)
 
34
{
 
35
  return (state == GRUB_PARSER_STATE_VARNAME
 
36
          || state == GRUB_PARSER_STATE_VAR
 
37
          || state == GRUB_PARSER_STATE_QVAR
 
38
          || state == GRUB_PARSER_STATE_VARNAME2
 
39
          || state == GRUB_PARSER_STATE_QVARNAME
 
40
          || state == GRUB_PARSER_STATE_QVARNAME2);
 
41
}
 
42
 
 
43
static int
 
44
check_textstate (grub_parser_state_t state)
 
45
{
 
46
  return (state == GRUB_PARSER_STATE_TEXT
 
47
          || state == GRUB_PARSER_STATE_QUOTE
 
48
          || state == GRUB_PARSER_STATE_DQUOTE);
 
49
}
 
50
 
 
51
/* The amount of references to the lexer by the parser.  If the parser
 
52
   expects tokens the lexer is referenced.  */
 
53
static int grub_script_lexer_refs = 0;
 
54
static char *script;
 
55
static char *newscript;
 
56
 
 
57
/* XXX: The lexer is not reentrant.  */
 
58
void
 
59
grub_script_lexer_init (char *s, grub_err_t (*getline) (char **))
 
60
{
 
61
  grub_script_lexer_state = GRUB_PARSER_STATE_TEXT;
 
62
  grub_script_lexer_getline = getline;
 
63
  grub_script_lexer_refs = 0;
 
64
  grub_script_lexer_done = 0;
 
65
  newscript = 0;
 
66
  script = s;
 
67
}
 
68
 
 
69
void
 
70
grub_script_lexer_ref (void)
 
71
{
 
72
  grub_script_lexer_refs++;
 
73
}
 
74
 
 
75
void
 
76
grub_script_lexer_deref (void)
 
77
{
 
78
  grub_script_lexer_refs--;
 
79
}
 
80
 
 
81
int
 
82
grub_script_yylex (void)
 
83
{
 
84
  grub_parser_state_t newstate;
 
85
  char use;
 
86
  char *buffer;
 
87
  char *bp;
 
88
 
 
89
  if (grub_script_lexer_done)
 
90
    return 0;
 
91
 
 
92
  if (! *script)
 
93
    {
 
94
      /* Check if more tokens are requested by the parser.  */
 
95
      if ((grub_script_lexer_refs
 
96
           || grub_script_lexer_state == GRUB_PARSER_STATE_ESC)
 
97
          && grub_script_lexer_getline)
 
98
        {
 
99
          while (! grub_strlen (script))
 
100
            {
 
101
              grub_free (newscript);
 
102
              grub_script_lexer_getline (&newscript);
 
103
              script = newscript;
 
104
            }
 
105
          grub_dprintf ("scripting", "token=`\\n'\n");
 
106
          if (grub_script_lexer_state != GRUB_PARSER_STATE_ESC)
 
107
            return '\n';
 
108
        }
 
109
      else
 
110
        {
 
111
          grub_free (newscript);
 
112
          newscript = 0;
 
113
          grub_script_lexer_done = 1;
 
114
          grub_dprintf ("scripting", "token=`\\n'\n");
 
115
          return '\n';
 
116
        }
 
117
    }
 
118
 
 
119
  newstate = grub_parser_cmdline_state (grub_script_lexer_state, *script, &use);
 
120
 
 
121
  /* Check if it is a text.  */
 
122
  if (check_textstate (newstate))
 
123
    {
 
124
      /* In case the string is not quoted, this can be a one char
 
125
         length symbol.  */
 
126
      if (newstate == GRUB_PARSER_STATE_TEXT)
 
127
        {
 
128
          switch (*script)
 
129
            {
 
130
            case ' ':
 
131
              while (*script)
 
132
                {
 
133
                  newstate = grub_parser_cmdline_state (grub_script_lexer_state,
 
134
                                                        *script, &use);
 
135
                  if (! (grub_script_lexer_state == GRUB_PARSER_STATE_TEXT
 
136
                         && *script == ' '))
 
137
                    {
 
138
                      grub_dprintf ("scripting", "token=` '\n");
 
139
                      return ' ';
 
140
                    }
 
141
                  grub_script_lexer_state = newstate;
 
142
                  script++;
 
143
                }
 
144
              grub_dprintf ("scripting", "token=` '\n");
 
145
              return ' ';
 
146
            case '{':
 
147
            case '}':
 
148
            case ';':
 
149
            case '\n':
 
150
              grub_dprintf ("scripting", "token=`%c'\n", *script);
 
151
              return *(script++);
 
152
            }
 
153
        }
 
154
 
 
155
      /* XXX: Use a better size.  */
 
156
      buffer = grub_script_malloc (2096);
 
157
      if (! buffer)
 
158
        return 0;
 
159
 
 
160
      bp = buffer;
 
161
 
 
162
      /* Read one token, possible quoted.  */
 
163
      while (*script)
 
164
        {
 
165
          newstate = grub_parser_cmdline_state (grub_script_lexer_state,
 
166
                                                *script, &use);
 
167
 
 
168
          /* Check if a variable name starts.  */
 
169
          if (check_varstate (newstate))
 
170
            break;
 
171
 
 
172
          /* If the string is not quoted or escaped, stop processing
 
173
             when a special token was found.  It will be recognised
 
174
             next time when this function is called.  */
 
175
          if (newstate == GRUB_PARSER_STATE_TEXT
 
176
              && grub_script_lexer_state != GRUB_PARSER_STATE_ESC)
 
177
            {
 
178
              int breakout = 0;
 
179
 
 
180
              switch (use)
 
181
                {
 
182
                case ' ':
 
183
                case '{':
 
184
                case '}':
 
185
                case ';':
 
186
                case '\n':
 
187
                  breakout = 1;
 
188
                }
 
189
              if (breakout)
 
190
                break;
 
191
              *(bp++) = use;
 
192
            }
 
193
          else if (use)
 
194
            *(bp++) = use;
 
195
 
 
196
          grub_script_lexer_state = newstate;
 
197
          script++;
 
198
        }
 
199
 
 
200
      /* A string of text was read in.  */
 
201
      *bp = '\0';
 
202
      grub_dprintf ("scripting", "token=`%s'\n", buffer);
 
203
      grub_script_yylval.string = buffer;
 
204
 
 
205
      /* Detect some special tokens.  */
 
206
      if (! grub_strcmp (buffer, "while"))
 
207
        return GRUB_PARSER_TOKEN_WHILE;
 
208
      else if (! grub_strcmp (buffer, "if"))
 
209
        return GRUB_PARSER_TOKEN_IF;
 
210
      else if (! grub_strcmp (buffer, "function"))
 
211
        return GRUB_PARSER_TOKEN_FUNCTION;
 
212
      else if (! grub_strcmp (buffer, "else"))
 
213
        return GRUB_PARSER_TOKEN_ELSE;
 
214
      else if (! grub_strcmp (buffer, "then"))
 
215
        return GRUB_PARSER_TOKEN_THEN;
 
216
      else if (! grub_strcmp (buffer, "fi"))
 
217
        return GRUB_PARSER_TOKEN_FI;
 
218
      else
 
219
        return GRUB_PARSER_TOKEN_NAME;
 
220
    }
 
221
  else if (newstate == GRUB_PARSER_STATE_VAR
 
222
           || newstate == GRUB_PARSER_STATE_QVAR)
 
223
    {
 
224
      /* XXX: Use a better size.  */
 
225
      buffer = grub_script_malloc (2096);
 
226
      if (! buffer)
 
227
        return 0;
 
228
 
 
229
      bp = buffer;
 
230
 
 
231
      /* This is a variable, read the variable name.  */
 
232
      while (*script)
 
233
        {
 
234
          newstate = grub_parser_cmdline_state (grub_script_lexer_state,
 
235
                                                *script, &use);
 
236
 
 
237
          /* Check if this character is not part of the variable name
 
238
             anymore.  */
 
239
          if (! (check_varstate (newstate)))
 
240
            {
 
241
              if (grub_script_lexer_state == GRUB_PARSER_STATE_VARNAME2
 
242
                  || grub_script_lexer_state == GRUB_PARSER_STATE_QVARNAME2)
 
243
                script++;
 
244
              grub_script_lexer_state = newstate;
 
245
              break;
 
246
            }
 
247
 
 
248
          if (use)
 
249
            *(bp++) = use;
 
250
          script++;
 
251
          grub_script_lexer_state = newstate;
 
252
        }
 
253
 
 
254
      *bp = '\0';
 
255
      grub_script_lexer_state = newstate;
 
256
      grub_script_yylval.string = buffer;
 
257
      grub_dprintf ("scripting", "vartoken=`%s'\n", buffer);
 
258
 
 
259
      return GRUB_PARSER_TOKEN_VAR;
 
260
    }
 
261
  else
 
262
    {
 
263
      /* There is either text or a variable name.  In the case you
 
264
         arrive here there is a serious problem with the lexer.  */
 
265
      grub_error (GRUB_ERR_BAD_ARGUMENT, "Internal error\n");
 
266
      return 0;
 
267
    }
 
268
}
 
269
 
 
270
void
 
271
grub_script_yyerror (char const *err)
 
272
{
 
273
  grub_printf (err);
 
274
}