date fix
[grub2/jjazz.git] / script / sh / script.c
blobc04a4496690d0b7b65ec560178ac43417c1bc3c8
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 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
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;
113 int len;
115 argpart = (struct grub_script_arg *) grub_script_malloc (state, sizeof (*arg));
116 argpart->type = type;
117 len = grub_strlen (str) + 1;
118 argpart->str = grub_script_malloc (state, len);
119 grub_memcpy (argpart->str, str, len);
120 argpart->next = 0;
122 if (! arg)
123 return argpart;
125 for (ll = arg; ll->next; ll = ll->next);
126 ll->next = argpart;
128 return arg;
131 /* Add the argument ARG to the end of the argument list LIST. If LIST
132 is zero, a new list will be created. */
133 struct grub_script_arglist *
134 grub_script_add_arglist (struct grub_parser_param *state,
135 struct grub_script_arglist *list, struct grub_script_arg *arg)
137 struct grub_script_arglist *link;
138 struct grub_script_arglist *ll;
140 grub_dprintf ("scripting", "arglist\n");
142 link = (struct grub_script_arglist *) grub_script_malloc (state, sizeof (*link));
143 link->next = 0;
144 link->arg = arg;
145 link->argcount = 0;
147 if (! list)
149 link->argcount++;
150 return link;
153 list->argcount++;
155 /* Look up the last link in the chain. */
156 for (ll = list; ll->next; ll = ll->next);
157 ll->next = link;
159 return list;
162 /* Create a command that describes a single command line. CMDLINE
163 contains the name of the command that should be executed. ARGLIST
164 holds all arguments for this command. */
165 struct grub_script_cmd *
166 grub_script_create_cmdline (struct grub_parser_param *state,
167 struct grub_script_arglist *arglist)
169 struct grub_script_cmdline *cmd;
171 grub_dprintf ("scripting", "cmdline\n");
173 cmd = grub_script_malloc (state, sizeof (*cmd));
174 cmd->cmd.exec = grub_script_execute_cmdline;
175 cmd->cmd.next = 0;
176 cmd->arglist = arglist;
178 return (struct grub_script_cmd *) cmd;
181 /* Create a command that functions as an if statement. If BOOL is
182 evaluated to true (the value is returned in envvar '?'), the
183 interpreter will run the command TRUE, otherwise the interpreter
184 runs the command FALSE. */
185 struct grub_script_cmd *
186 grub_script_create_cmdif (struct grub_parser_param *state,
187 struct grub_script_cmd *exec_to_evaluate,
188 struct grub_script_cmd *exec_on_true,
189 struct grub_script_cmd *exec_on_false)
191 struct grub_script_cmdif *cmd;
193 grub_dprintf ("scripting", "cmdif\n");
195 cmd = grub_script_malloc (state, sizeof (*cmd));
196 cmd->cmd.exec = grub_script_execute_cmdif;
197 cmd->cmd.next = 0;
198 cmd->exec_to_evaluate = exec_to_evaluate;
199 cmd->exec_on_true = exec_on_true;
200 cmd->exec_on_false = exec_on_false;
202 return (struct grub_script_cmd *) cmd;
205 /* Create a command that adds a menu entry to the menu. Title is an
206 argument that is parsed to generate a string that can be used as
207 the title. The sourcecode for this entry is passed in SOURCECODE.
208 The options for this entry are passed in OPTIONS. */
209 struct grub_script_cmd *
210 grub_script_create_cmdmenu (struct grub_parser_param *state,
211 struct grub_script_arglist *arglist,
212 char *sourcecode,
213 int options)
215 struct grub_script_cmd_menuentry *cmd;
216 int i;
218 /* Skip leading newlines to make the sourcecode better readable when
219 using the editor. */
220 while (*sourcecode == '\n')
221 sourcecode++;
223 /* Having trailing returns can some some annoying conflicts, remove
224 them. XXX: Can the parser be improved to handle this? */
225 for (i = grub_strlen (sourcecode) - 1; i > 0; i--)
227 if (sourcecode[i] != '\n')
228 break;
229 sourcecode[i] = '\0';
232 cmd = grub_script_malloc (state, sizeof (*cmd));
233 cmd->cmd.exec = grub_script_execute_menuentry;
234 cmd->cmd.next = 0;
235 /* XXX: Check if this memory is properly freed. */
236 cmd->sourcecode = sourcecode;
237 cmd->arglist = arglist;
238 cmd->options = options;
240 return (struct grub_script_cmd *) cmd;
243 /* Create a block of commands. CMD contains the command that should
244 be added at the end of CMDBLOCK's list. If CMDBLOCK is zero, a new
245 cmdblock will be created. */
246 struct grub_script_cmd *
247 grub_script_add_cmd (struct grub_parser_param *state,
248 struct grub_script_cmdblock *cmdblock,
249 struct grub_script_cmd *cmd)
251 grub_dprintf ("scripting", "cmdblock\n");
253 if (! cmd)
254 return (struct grub_script_cmd *) cmdblock;
256 if (! cmdblock)
258 cmdblock = (struct grub_script_cmdblock *) grub_script_malloc (state,
259 sizeof (*cmdblock));
260 cmdblock->cmd.exec = grub_script_execute_cmdblock;
261 cmdblock->cmd.next = 0;
262 cmdblock->cmdlist = cmd;
263 cmd->next = 0;
265 else
267 cmd->next = cmdblock->cmdlist;
268 cmdblock->cmdlist = cmd;
271 return (struct grub_script_cmd *) cmdblock;
276 struct grub_script *
277 grub_script_create (struct grub_script_cmd *cmd, struct grub_script_mem *mem)
279 struct grub_script *parsed;
281 parsed = grub_malloc (sizeof (*parsed));
282 if (! parsed)
284 grub_script_mem_free (mem);
285 grub_free (cmd);
287 return 0;
290 parsed->mem = mem;
291 parsed->cmd = cmd;
293 return parsed;
296 /* Parse the script passed in SCRIPT and return the parsed
297 datastructure that is ready to be interpreted. */
298 struct grub_script *
299 grub_script_parse (char *script, grub_reader_getline_t getline)
301 struct grub_script *parsed;
302 struct grub_script_mem *membackup;
303 struct grub_lexer_param *lexstate;
304 struct grub_parser_param *parsestate;
306 parsed = grub_malloc (sizeof (*parsed));
307 if (! parsed)
308 return 0;
310 parsestate = grub_zalloc (sizeof (*parsestate));
311 if (! parsestate)
312 return 0;
314 /* Initialize the lexer. */
315 lexstate = grub_script_lexer_init (script, getline);
316 if (! lexstate)
318 grub_free (parsed);
319 grub_free (parsestate);
320 return 0;
323 parsestate->lexerstate = lexstate;
325 membackup = grub_script_mem_record (parsestate);
327 /* Parse the script. */
328 if (grub_script_yyparse (parsestate) || parsestate->err)
330 struct grub_script_mem *memfree;
331 memfree = grub_script_mem_record_stop (parsestate, membackup);
332 grub_script_mem_free (memfree);
333 grub_free (lexstate);
334 grub_free (parsestate);
335 return 0;
338 parsed->mem = grub_script_mem_record_stop (parsestate, membackup);
339 parsed->cmd = parsestate->parsed;
341 grub_free (lexstate);
342 grub_free (parsestate);
344 return parsed;