1 /* script.c -- Functions to create an in memory description of the script. */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2005,2006,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/misc.h>
21 #include <grub/script.h>
22 #include <grub/parser.h>
25 /* It is not possible to deallocate the memory when a syntax error was
26 found. Because of that it is required to keep track of all memory
27 allocations. The memory is freed in case of an error, or
28 assigned to the parsed script when parsing was successful. */
32 /* In case of the normal malloc, some additional bytes are allocated
33 for this datastructure. All reserved memory is stored in a linked
34 list so it can be easily freed. The original memory can be found
36 struct grub_script_mem
38 struct grub_script_mem
*next
;
42 /* Return malloc'ed memory and keep track of the allocation. */
44 grub_script_malloc (struct grub_parser_param
*state
, grub_size_t size
)
46 struct grub_script_mem
*mem
;
47 mem
= (struct grub_script_mem
*) grub_malloc (size
+ sizeof (*mem
)
50 grub_dprintf ("scripting", "malloc %p\n", mem
);
51 mem
->next
= state
->memused
;
53 return (void *) &mem
->mem
;
56 /* Free all memory described by MEM. */
58 grub_script_mem_free (struct grub_script_mem
*mem
)
60 struct grub_script_mem
*memfree
;
65 grub_dprintf ("scripting", "free %p\n", mem
);
71 /* Start recording memory usage. Returns the memory that should be
72 restored when calling stop. */
73 struct grub_script_mem
*
74 grub_script_mem_record (struct grub_parser_param
*state
)
76 struct grub_script_mem
*mem
= state
->memused
;
82 /* Stop recording memory usage. Restore previous recordings using
83 RESTORE. Return the recorded memory. */
84 struct grub_script_mem
*
85 grub_script_mem_record_stop (struct grub_parser_param
*state
,
86 struct grub_script_mem
*restore
)
88 struct grub_script_mem
*mem
= state
->memused
;
89 state
->memused
= restore
;
93 /* Free the memory reserved for CMD and all of it's children. */
95 grub_script_free (struct grub_script
*script
)
99 grub_script_mem_free (script
->mem
);
105 /* Extend the argument arg with a variable or string of text. If ARG
106 is zero a new list is created. */
107 struct grub_script_arg
*
108 grub_script_arg_add (struct grub_parser_param
*state
, struct grub_script_arg
*arg
,
109 grub_script_arg_type_t type
, char *str
)
111 struct grub_script_arg
*argpart
;
112 struct grub_script_arg
*ll
;
114 argpart
= (struct grub_script_arg
*) grub_script_malloc (state
, sizeof (*arg
));
115 argpart
->type
= type
;
122 for (ll
= arg
; ll
->next
; ll
= ll
->next
);
128 /* Add the argument ARG to the end of the argument list LIST. If LIST
129 is zero, a new list will be created. */
130 struct grub_script_arglist
*
131 grub_script_add_arglist (struct grub_parser_param
*state
,
132 struct grub_script_arglist
*list
, struct grub_script_arg
*arg
)
134 struct grub_script_arglist
*link
;
135 struct grub_script_arglist
*ll
;
137 grub_dprintf ("scripting", "arglist\n");
139 link
= (struct grub_script_arglist
*) grub_script_malloc (state
, sizeof (*link
));
152 /* Look up the last link in the chain. */
153 for (ll
= list
; ll
->next
; ll
= ll
->next
);
159 /* Create a command that describes a single command line. CMDLINE
160 contains the name of the command that should be executed. ARGLIST
161 holds all arguments for this command. */
162 struct grub_script_cmd
*
163 grub_script_create_cmdline (struct grub_parser_param
*state
,
164 char *cmdname
, struct grub_script_arglist
*arglist
)
166 struct grub_script_cmdline
*cmd
;
168 grub_dprintf ("scripting", "cmdline\n");
170 cmd
= grub_script_malloc (state
, sizeof (*cmd
));
171 cmd
->cmd
.exec
= grub_script_execute_cmdline
;
173 cmd
->arglist
= arglist
;
174 cmd
->cmdname
= cmdname
;
176 return (struct grub_script_cmd
*) cmd
;
179 /* Create a command that functions as an if statement. If BOOL is
180 evaluated to true (the value is returned in envvar '?'), the
181 interpreter will run the command TRUE, otherwise the interpreter
182 runs the command FALSE. */
183 struct grub_script_cmd
*
184 grub_script_create_cmdif (struct grub_parser_param
*state
,
185 struct grub_script_cmd
*exec_to_evaluate
,
186 struct grub_script_cmd
*exec_on_true
,
187 struct grub_script_cmd
*exec_on_false
)
189 struct grub_script_cmdif
*cmd
;
191 grub_dprintf ("scripting", "cmdif\n");
193 cmd
= grub_script_malloc (state
, sizeof (*cmd
));
194 cmd
->cmd
.exec
= grub_script_execute_cmdif
;
196 cmd
->exec_to_evaluate
= exec_to_evaluate
;
197 cmd
->exec_on_true
= exec_on_true
;
198 cmd
->exec_on_false
= exec_on_false
;
200 return (struct grub_script_cmd
*) cmd
;
203 /* Create a command that adds a menu entry to the menu. Title is an
204 argument that is parsed to generate a string that can be used as
205 the title. The sourcecode for this entry is passed in SOURCECODE.
206 The options for this entry are passed in OPTIONS. */
207 struct grub_script_cmd
*
208 grub_script_create_cmdmenu (struct grub_parser_param
*state
,
209 struct grub_script_arg
*title
,
213 struct grub_script_cmd_menuentry
*cmd
;
216 /* Skip leading newlines to make the sourcecode better readable when
218 while (*sourcecode
== '\n')
221 /* Having trailing returns can some some annoying conflicts, remove
222 them. XXX: Can the parser be improved to handle this? */
223 for (i
= grub_strlen (sourcecode
) - 1; i
> 0; i
--)
225 if (sourcecode
[i
] != '\n')
227 sourcecode
[i
] = '\0';
230 cmd
= grub_script_malloc (state
, sizeof (*cmd
));
231 cmd
->cmd
.exec
= grub_script_execute_menuentry
;
233 /* XXX: Check if this memory is properly freed. */
234 cmd
->sourcecode
= sourcecode
;
236 cmd
->options
= options
;
238 return (struct grub_script_cmd
*) cmd
;
241 /* Create a block of commands. CMD contains the command that should
242 be added at the end of CMDBLOCK's list. If CMDBLOCK is zero, a new
243 cmdblock will be created. */
244 struct grub_script_cmd
*
245 grub_script_add_cmd (struct grub_parser_param
*state
,
246 struct grub_script_cmdblock
*cmdblock
,
247 struct grub_script_cmd
*cmd
)
249 grub_dprintf ("scripting", "cmdblock\n");
252 return (struct grub_script_cmd
*) cmdblock
;
256 cmdblock
= (struct grub_script_cmdblock
*) grub_script_malloc (state
,
258 cmdblock
->cmd
.exec
= grub_script_execute_cmdblock
;
259 cmdblock
->cmd
.next
= 0;
260 cmdblock
->cmdlist
= cmd
;
265 cmd
->next
= cmdblock
->cmdlist
;
266 cmdblock
->cmdlist
= cmd
;
269 return (struct grub_script_cmd
*) cmdblock
;
275 grub_script_create (struct grub_script_cmd
*cmd
, struct grub_script_mem
*mem
)
277 struct grub_script
*parsed
;
279 parsed
= grub_malloc (sizeof (*parsed
));
282 grub_script_mem_free (mem
);
294 /* Parse the script passed in SCRIPT and return the parsed
295 datastructure that is ready to be interpreted. */
297 grub_script_parse (char *script
, grub_err_t (*getline
) (char **))
299 struct grub_script
*parsed
;
300 struct grub_script_mem
*membackup
;
301 struct grub_lexer_param
*lexstate
;
302 struct grub_parser_param
*parsestate
;
304 parsed
= grub_malloc (sizeof (*parsed
));
308 parsestate
= grub_malloc (sizeof (*parsestate
));
313 parsestate
->func_mem
= 0;
314 parsestate
->memused
= 0;
315 parsestate
->parsed
= 0;
317 /* Initialize the lexer. */
318 lexstate
= grub_script_lexer_init (script
, getline
);
322 grub_free (parsestate
);
326 parsestate
->lexerstate
= lexstate
;
328 membackup
= grub_script_mem_record (parsestate
);
330 /* Parse the script. */
331 if (grub_script_yyparse (parsestate
) || parsestate
->err
)
333 struct grub_script_mem
*memfree
;
334 memfree
= grub_script_mem_record_stop (parsestate
, membackup
);
335 grub_script_mem_free (memfree
);
336 grub_free (lexstate
);
337 grub_free (parsestate
);
341 parsed
->mem
= grub_script_mem_record_stop (parsestate
, membackup
);
342 parsed
->cmd
= parsestate
->parsed
;
344 grub_free (lexstate
);
345 grub_free (parsestate
);