1 /* parser.c - the part of the parser that can return partial tokens */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2005,2007 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_DQUOTE
, ' ', 1},
51 { GRUB_PARSER_STATE_QVARNAME
, GRUB_PARSER_STATE_TEXT
, '\"', 0},
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
*next_match
= 0;
64 struct grub_parser_state_transition default_transition
;
67 default_transition
.to_state
= state
;
68 default_transition
.keep_value
= 1;
70 /* Look for a good translation. */
71 for (transition
= state_transitions
; transition
->from_state
; transition
++)
73 /* An exact match was found, use it. */
74 if (transition
->from_state
== state
&& transition
->input
== c
)
80 /* A less perfect match was found, use this one if no exact
81 match can be found. */
82 if (transition
->from_state
== state
&& transition
->input
== 0)
83 next_match
= transition
;
89 transition
= next_match
;
91 transition
= &default_transition
;
94 if (transition
->keep_value
)
98 return transition
->to_state
;
103 grub_parser_split_cmdline (const char *cmdline
, grub_err_t (*getline
) (char **),
104 int *argc
, char ***argv
)
106 grub_parser_state_t state
= GRUB_PARSER_STATE_TEXT
;
107 /* XXX: Fixed size buffer, perhaps this buffer should be dynamically
111 char *rd
= (char *) cmdline
;
117 auto int check_varstate (grub_parser_state_t s
);
119 int check_varstate (grub_parser_state_t s
)
121 return (s
== GRUB_PARSER_STATE_VARNAME
122 || s
== GRUB_PARSER_STATE_VARNAME2
123 || s
== GRUB_PARSER_STATE_QVARNAME
124 || s
== GRUB_PARSER_STATE_QVARNAME2
);
127 auto void add_var (grub_parser_state_t newstate
);
129 void add_var (grub_parser_state_t newstate
)
133 /* Check if a variable was being read in and the end of the name
135 if (! (check_varstate (state
) && !check_varstate (newstate
)))
139 val
= grub_env_get (varname
);
144 /* Insert the contents of the variable in the buffer. */
161 grub_parser_state_t newstate
;
164 newstate
= grub_parser_cmdline_state (state
, *rd
, &use
);
166 /* If a variable was being processed and this character does
167 not describe the variable anymore, write the variable to
171 if (check_varstate (newstate
))
178 if (newstate
== GRUB_PARSER_STATE_TEXT
179 && state
!= GRUB_PARSER_STATE_ESC
&& use
== ' ')
181 /* Don't add more than one argument if multiple
183 if (bp
!= buffer
&& *(bp
- 1))
194 } while (state
!= GRUB_PARSER_STATE_TEXT
&& !check_varstate (state
));
197 /* A special case for when the last character was part of a
199 add_var (GRUB_PARSER_STATE_TEXT
);
202 /* Reserve memory for the return values. */
203 args
= grub_malloc (bp
- buffer
);
206 grub_memcpy (args
, buffer
, bp
- buffer
);
208 *argv
= grub_malloc (sizeof (char *) * (*argc
+ 1));
215 /* The arguments are separated with 0's, setup argv so it points to
218 for (i
= 0; i
< *argc
; i
++)