2009-01-26 Daniel Mierswa <impulze@impulze.org>
[grub2/bean.git] / normal / script.c
blob5169e4949d8e4a547047d3fef190deedf8adc8cb
1 /* script.c -- Functions to create an in memory description of the script. */
2 /*
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>
23 #include <grub/mm.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. */
30 /* XXX */
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
35 from &mem. */
36 struct grub_script_mem
38 struct grub_script_mem *next;
39 char mem;
42 /* Return malloc'ed memory and keep track of the allocation. */
43 void *
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)
48 - sizeof (char));
50 grub_dprintf ("scripting", "malloc %p\n", mem);
51 mem->next = state->memused;
52 state->memused = mem;
53 return (void *) &mem->mem;
56 /* Free all memory described by MEM. */
57 static void
58 grub_script_mem_free (struct grub_script_mem *mem)
60 struct grub_script_mem *memfree;
62 while (mem)
64 memfree = mem->next;
65 grub_dprintf ("scripting", "free %p\n", mem);
66 grub_free (mem);
67 mem = memfree;
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;
77 state->memused = 0;
79 return mem;
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;
90 return mem;
93 /* Free the memory reserved for CMD and all of it's children. */
94 void
95 grub_script_free (struct grub_script *script)
97 if (! script)
98 return;
99 grub_script_mem_free (script->mem);
100 grub_free (script);
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;
116 argpart->str = str;
117 argpart->next = 0;
119 if (! arg)
120 return argpart;
122 for (ll = arg; ll->next; ll = ll->next);
123 ll->next = argpart;
125 return arg;
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));
140 link->next = 0;
141 link->arg = arg;
142 link->argcount = 0;
144 if (! list)
146 link->argcount++;
147 return link;
150 list->argcount++;
152 /* Look up the last link in the chain. */
153 for (ll = list; ll->next; ll = ll->next);
154 ll->next = link;
156 return list;
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;
172 cmd->cmd.next = 0;
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;
195 cmd->cmd.next = 0;
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,
210 char *sourcecode,
211 int options)
213 struct grub_script_cmd_menuentry *cmd;
214 int i;
216 /* Skip leading newlines to make the sourcecode better readable when
217 using the editor. */
218 while (*sourcecode == '\n')
219 sourcecode++;
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')
226 break;
227 sourcecode[i] = '\0';
230 cmd = grub_script_malloc (state, sizeof (*cmd));
231 cmd->cmd.exec = grub_script_execute_menuentry;
232 cmd->cmd.next = 0;
233 /* XXX: Check if this memory is properly freed. */
234 cmd->sourcecode = sourcecode;
235 cmd->title = title;
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");
251 if (! cmd)
252 return (struct grub_script_cmd *) cmdblock;
254 if (! cmdblock)
256 cmdblock = (struct grub_script_cmdblock *) grub_script_malloc (state,
257 sizeof (*cmdblock));
258 cmdblock->cmd.exec = grub_script_execute_cmdblock;
259 cmdblock->cmd.next = 0;
260 cmdblock->cmdlist = cmd;
261 cmd->next = 0;
263 else
265 cmd->next = cmdblock->cmdlist;
266 cmdblock->cmdlist = cmd;
269 return (struct grub_script_cmd *) cmdblock;
274 struct grub_script *
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));
280 if (! parsed)
282 grub_script_mem_free (mem);
283 grub_free (cmd);
285 return 0;
288 parsed->mem = mem;
289 parsed->cmd = cmd;
291 return parsed;
294 /* Parse the script passed in SCRIPT and return the parsed
295 datastructure that is ready to be interpreted. */
296 struct grub_script *
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));
305 if (! parsed)
306 return 0;
308 parsestate = grub_malloc (sizeof (*parsestate));
309 if (! parsestate)
310 return 0;
312 parsestate->err = 0;
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);
319 if (! lexstate)
321 grub_free (parsed);
322 grub_free (parsestate);
323 return 0;
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);
338 return 0;
341 parsed->mem = grub_script_mem_record_stop (parsestate, membackup);
342 parsed->cmd = parsestate->parsed;
344 grub_free (lexstate);
345 grub_free (parsestate);
347 return parsed;