1 /* parser.c - the part of the parser that can return partial tokens */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2005,2007,2009 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/>.
20 #include <grub/parser.h>
22 #include <grub/misc.h>
26 /* All the possible state transitions on the command line. If a
27 transition can not be found, it is assumed that there is no
28 transition and keep_value is assumed to be 1. */
29 static struct grub_parser_state_transition state_transitions
[] =
31 { GRUB_PARSER_STATE_TEXT
, GRUB_PARSER_STATE_QUOTE
, '\'', 0},
32 { GRUB_PARSER_STATE_TEXT
, GRUB_PARSER_STATE_DQUOTE
, '\"', 0},
33 { GRUB_PARSER_STATE_TEXT
, GRUB_PARSER_STATE_VAR
, '$', 0},
34 { GRUB_PARSER_STATE_TEXT
, GRUB_PARSER_STATE_ESC
, '\\', 0},
36 { GRUB_PARSER_STATE_ESC
, GRUB_PARSER_STATE_TEXT
, 0, 1},
38 { GRUB_PARSER_STATE_QUOTE
, GRUB_PARSER_STATE_TEXT
, '\'', 0},
40 { GRUB_PARSER_STATE_DQUOTE
, GRUB_PARSER_STATE_TEXT
, '\"', 0},
41 { GRUB_PARSER_STATE_DQUOTE
, GRUB_PARSER_STATE_QVAR
, '$', 0},
43 { GRUB_PARSER_STATE_VAR
, GRUB_PARSER_STATE_VARNAME2
, '{', 0},
44 { GRUB_PARSER_STATE_VAR
, GRUB_PARSER_STATE_VARNAME
, 0, 1},
45 { GRUB_PARSER_STATE_VARNAME
, GRUB_PARSER_STATE_TEXT
, ' ', 1},
46 { GRUB_PARSER_STATE_VARNAME2
, GRUB_PARSER_STATE_TEXT
, '}', 0},
48 { GRUB_PARSER_STATE_QVAR
, GRUB_PARSER_STATE_QVARNAME2
, '{', 0},
49 { GRUB_PARSER_STATE_QVAR
, GRUB_PARSER_STATE_QVARNAME
, 0, 1},
50 { GRUB_PARSER_STATE_QVARNAME
, GRUB_PARSER_STATE_TEXT
, '\"', 0},
51 { GRUB_PARSER_STATE_QVARNAME
, GRUB_PARSER_STATE_DQUOTE
, ' ', 1},
52 { GRUB_PARSER_STATE_QVARNAME2
, GRUB_PARSER_STATE_DQUOTE
, '}', 0},
58 /* Determines the state following STATE, determined by C. */
60 grub_parser_cmdline_state (grub_parser_state_t state
, char c
, char *result
)
62 struct grub_parser_state_transition
*transition
;
63 struct grub_parser_state_transition default_transition
;
65 default_transition
.to_state
= state
;
66 default_transition
.keep_value
= 1;
68 /* Look for a good translation. */
69 for (transition
= state_transitions
; transition
->from_state
; transition
++)
71 if (transition
->from_state
!= state
)
73 /* An exact match was found, use it. */
74 if (transition
->input
== c
)
77 if (transition
->input
== ' ' && ! grub_isalpha (c
)
78 && ! grub_isdigit (c
) && c
!= '_')
81 /* A less perfect match was found, use this one if no exact
82 match can be found. */
83 if (transition
->input
== 0)
87 if (! transition
->from_state
)
88 transition
= &default_transition
;
90 if (transition
->keep_value
)
94 return transition
->to_state
;
99 grub_parser_split_cmdline (const char *cmdline
, grub_reader_getline_t getline
,
100 int *argc
, char ***argv
)
102 grub_parser_state_t state
= GRUB_PARSER_STATE_TEXT
;
103 /* XXX: Fixed size buffer, perhaps this buffer should be dynamically
107 char *rd
= (char *) cmdline
;
113 auto int check_varstate (grub_parser_state_t s
);
115 int check_varstate (grub_parser_state_t s
)
117 return (s
== GRUB_PARSER_STATE_VARNAME
118 || s
== GRUB_PARSER_STATE_VARNAME2
119 || s
== GRUB_PARSER_STATE_QVARNAME
120 || s
== GRUB_PARSER_STATE_QVARNAME2
);
123 auto void add_var (grub_parser_state_t newstate
);
125 void add_var (grub_parser_state_t newstate
)
129 /* Check if a variable was being read in and the end of the name
131 if (! (check_varstate (state
) && !check_varstate (newstate
)))
135 val
= grub_env_get (varname
);
140 /* Insert the contents of the variable in the buffer. */
157 grub_parser_state_t newstate
;
160 newstate
= grub_parser_cmdline_state (state
, *rd
, &use
);
162 /* If a variable was being processed and this character does
163 not describe the variable anymore, write the variable to
167 if (check_varstate (newstate
))
174 if (newstate
== GRUB_PARSER_STATE_TEXT
175 && state
!= GRUB_PARSER_STATE_ESC
&& use
== ' ')
177 /* Don't add more than one argument if multiple
179 if (bp
!= buffer
&& *(bp
- 1))
190 } while (state
!= GRUB_PARSER_STATE_TEXT
&& !check_varstate (state
));
193 /* A special case for when the last character was part of a
195 add_var (GRUB_PARSER_STATE_TEXT
);
198 /* Reserve memory for the return values. */
199 args
= grub_malloc (bp
- buffer
);
202 grub_memcpy (args
, buffer
, bp
- buffer
);
204 *argv
= grub_malloc (sizeof (char *) * (*argc
+ 1));
211 /* The arguments are separated with 0's, setup argv so it points to
214 for (i
= 0; i
< *argc
; i
++)
227 struct grub_handler_class grub_parser_class
=
233 grub_parser_execute (char *source
)
235 auto grub_err_t
getline (char **line
, int cont
);
236 grub_err_t
getline (char **line
, int cont
__attribute__ ((unused
)))
246 p
= grub_strchr (source
, '\n');
250 *line
= grub_strdup (source
);
258 grub_parser_t parser
;
261 parser
= grub_parser_get_current ();
262 parser
->parse_line (line
, getline
);