Indentation fix, cleanup.
[AROS.git] / arch / all-pc / boot / grub2-aros / grub-core / script / script.c
blobec4d4337c660802eef7f232ad3dab327c042e7ee
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,2009,2010 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_sh.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 assigned
28 to the parsed script when parsing was successful.
30 In case of the normal malloc, some additional bytes are allocated
31 for this datastructure. All reserved memory is stored in a linked
32 list so it can be easily freed. The original memory can be found
33 from &mem. */
34 struct grub_script_mem
36 struct grub_script_mem *next;
37 char mem;
40 /* Return malloc'ed memory and keep track of the allocation. */
41 void *
42 grub_script_malloc (struct grub_parser_param *state, grub_size_t size)
44 struct grub_script_mem *mem;
45 mem = (struct grub_script_mem *) grub_malloc (size + sizeof (*mem)
46 - sizeof (char));
47 if (!mem)
48 return 0;
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 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 struct grub_script *s;
98 struct grub_script *t;
100 if (! script)
101 return;
103 if (script->mem)
104 grub_script_mem_free (script->mem);
106 s = script->children;
107 while (s) {
108 t = s->next_siblings;
109 grub_script_unref (s);
110 s = t;
112 grub_free (script);
117 /* Extend the argument arg with a variable or string of text. If ARG
118 is zero a new list is created. */
119 struct grub_script_arg *
120 grub_script_arg_add (struct grub_parser_param *state,
121 struct grub_script_arg *arg, grub_script_arg_type_t type,
122 char *str)
124 struct grub_script_arg *argpart;
125 struct grub_script_arg *ll;
126 int len;
128 argpart =
129 (struct grub_script_arg *) grub_script_malloc (state, sizeof (*arg));
130 if (!argpart)
131 return arg;
133 argpart->type = type;
134 argpart->script = 0;
136 len = grub_strlen (str) + 1;
137 argpart->str = grub_script_malloc (state, len);
138 if (!argpart->str)
139 return arg; /* argpart is freed later, during grub_script_free. */
141 grub_memcpy (argpart->str, str, len);
142 argpart->next = 0;
144 if (!arg)
145 return argpart;
147 for (ll = arg; ll->next; ll = ll->next);
148 ll->next = argpart;
150 return arg;
153 /* Add the argument ARG to the end of the argument list LIST. If LIST
154 is zero, a new list will be created. */
155 struct grub_script_arglist *
156 grub_script_add_arglist (struct grub_parser_param *state,
157 struct grub_script_arglist *list,
158 struct grub_script_arg *arg)
160 struct grub_script_arglist *link;
161 struct grub_script_arglist *ll;
163 grub_dprintf ("scripting", "arglist\n");
165 link =
166 (struct grub_script_arglist *) grub_script_malloc (state, sizeof (*link));
167 if (!link)
168 return list;
170 link->next = 0;
171 link->arg = arg;
172 link->argcount = 0;
174 if (!list)
176 link->argcount++;
177 return link;
180 list->argcount++;
182 /* Look up the last link in the chain. */
183 for (ll = list; ll->next; ll = ll->next);
184 ll->next = link;
186 return list;
189 /* Create a command that describes a single command line. CMDLINE
190 contains the name of the command that should be executed. ARGLIST
191 holds all arguments for this command. */
192 struct grub_script_cmd *
193 grub_script_create_cmdline (struct grub_parser_param *state,
194 struct grub_script_arglist *arglist)
196 struct grub_script_cmdline *cmd;
198 grub_dprintf ("scripting", "cmdline\n");
200 cmd = grub_script_malloc (state, sizeof (*cmd));
201 if (!cmd)
202 return 0;
204 cmd->cmd.exec = grub_script_execute_cmdline;
205 cmd->cmd.next = 0;
206 cmd->arglist = arglist;
208 return (struct grub_script_cmd *) cmd;
211 /* Create a command that functions as an if statement. If BOOL is
212 evaluated to true (the value is returned in envvar '?'), the
213 interpreter will run the command TRUE, otherwise the interpreter
214 runs the command FALSE. */
215 struct grub_script_cmd *
216 grub_script_create_cmdif (struct grub_parser_param *state,
217 struct grub_script_cmd *exec_to_evaluate,
218 struct grub_script_cmd *exec_on_true,
219 struct grub_script_cmd *exec_on_false)
221 struct grub_script_cmdif *cmd;
223 grub_dprintf ("scripting", "cmdif\n");
225 cmd = grub_script_malloc (state, sizeof (*cmd));
226 if (!cmd)
227 return 0;
229 cmd->cmd.exec = grub_script_execute_cmdif;
230 cmd->cmd.next = 0;
231 cmd->exec_to_evaluate = exec_to_evaluate;
232 cmd->exec_on_true = exec_on_true;
233 cmd->exec_on_false = exec_on_false;
235 return (struct grub_script_cmd *) cmd;
238 /* Create a command that functions as a for statement. */
239 struct grub_script_cmd *
240 grub_script_create_cmdfor (struct grub_parser_param *state,
241 struct grub_script_arg *name,
242 struct grub_script_arglist *words,
243 struct grub_script_cmd *list)
245 struct grub_script_cmdfor *cmd;
247 grub_dprintf ("scripting", "cmdfor\n");
249 cmd = grub_script_malloc (state, sizeof (*cmd));
250 if (! cmd)
251 return 0;
253 cmd->cmd.exec = grub_script_execute_cmdfor;
254 cmd->cmd.next = 0;
255 cmd->name = name;
256 cmd->words = words;
257 cmd->list = list;
259 return (struct grub_script_cmd *) cmd;
262 /* Create a "while" or "until" command. */
263 struct grub_script_cmd *
264 grub_script_create_cmdwhile (struct grub_parser_param *state,
265 struct grub_script_cmd *cond,
266 struct grub_script_cmd *list,
267 int is_an_until_loop)
269 struct grub_script_cmdwhile *cmd;
271 cmd = grub_script_malloc (state, sizeof (*cmd));
272 if (! cmd)
273 return 0;
275 cmd->cmd.exec = grub_script_execute_cmdwhile;
276 cmd->cmd.next = 0;
277 cmd->cond = cond;
278 cmd->list = list;
279 cmd->until = is_an_until_loop;
281 return (struct grub_script_cmd *) cmd;
284 /* Create a chain of commands. LAST contains the command that should
285 be added at the end of LIST's list. If LIST is zero, a new list
286 will be created. */
287 struct grub_script_cmd *
288 grub_script_append_cmd (struct grub_parser_param *state,
289 struct grub_script_cmd *list,
290 struct grub_script_cmd *last)
292 struct grub_script_cmd *ptr;
294 grub_dprintf ("scripting", "append command\n");
296 if (! last)
297 return list;
299 if (! list)
301 list = grub_script_malloc (state, sizeof (*list));
302 if (! list)
303 return 0;
305 list->exec = grub_script_execute_cmdlist;
306 list->next = last;
308 else
310 ptr = list;
311 while (ptr->next)
312 ptr = ptr->next;
314 ptr->next = last;
317 return list;
322 struct grub_script *
323 grub_script_create (struct grub_script_cmd *cmd, struct grub_script_mem *mem)
325 struct grub_script *parsed;
327 parsed = grub_malloc (sizeof (*parsed));
328 if (! parsed)
329 return 0;
331 parsed->mem = mem;
332 parsed->cmd = cmd;
333 parsed->refcnt = 0;
334 parsed->children = 0;
335 parsed->next_siblings = 0;
337 return parsed;
340 /* Parse the script passed in SCRIPT and return the parsed
341 datastructure that is ready to be interpreted. */
342 struct grub_script *
343 grub_script_parse (char *script,
344 grub_reader_getline_t getline, void *getline_data)
346 struct grub_script *parsed;
347 struct grub_script_mem *membackup;
348 struct grub_lexer_param *lexstate;
349 struct grub_parser_param *parsestate;
351 parsed = grub_script_create (0, 0);
352 if (!parsed)
353 return 0;
355 parsestate = grub_zalloc (sizeof (*parsestate));
356 if (!parsestate)
358 grub_free (parsed);
359 return 0;
362 /* Initialize the lexer. */
363 lexstate = grub_script_lexer_init (parsestate, script,
364 getline, getline_data);
365 if (!lexstate)
367 grub_free (parsed);
368 grub_free (parsestate);
369 return 0;
372 parsestate->lexerstate = lexstate;
374 membackup = grub_script_mem_record (parsestate);
376 /* Parse the script. */
377 if (grub_script_yyparse (parsestate) || parsestate->err)
379 struct grub_script_mem *memfree;
380 memfree = grub_script_mem_record_stop (parsestate, membackup);
381 grub_script_mem_free (memfree);
382 grub_script_lexer_fini (lexstate);
383 grub_free (parsestate);
384 grub_free (parsed);
385 return 0;
388 parsed->mem = grub_script_mem_record_stop (parsestate, membackup);
389 parsed->cmd = parsestate->parsed;
390 parsed->children = parsestate->scripts;
392 grub_script_lexer_fini (lexstate);
393 grub_free (parsestate);
395 return parsed;