pull-in block-arg again

This commit is contained in:
BVK Chaitanya 2010-07-22 05:34:38 +05:30
commit 8527be0c5d
6 changed files with 79 additions and 5 deletions

View file

@ -42,6 +42,10 @@ struct grub_script
unsigned refcnt;
struct grub_script_mem *mem;
struct grub_script_cmd *cmd;
/* Other grub_script's from block arguments. */
struct grub_script *siblings;
struct grub_script *children;
};
typedef enum
@ -207,6 +211,9 @@ struct grub_parser_param
/* The memory that was used while parsing and scanning. */
struct grub_script_mem *memused;
/* The block argument scripts. */
struct grub_script *scripts;
/* The result of the parser. */
struct grub_script_cmd *parsed;
@ -331,6 +338,7 @@ grub_script_function_t grub_script_function_create (struct grub_script_arg *func
struct grub_script *cmd);
void grub_script_function_remove (const char *name);
grub_script_function_t grub_script_function_find (char *functionname);
grub_err_t grub_script_function_call (grub_script_function_t func,
int argc, char **args);
@ -340,13 +348,17 @@ grub_script_execute_arglist_to_argv (struct grub_script_arglist *arglist, int *c
static inline struct grub_script *
grub_script_get (struct grub_script *script)
{
script->refcnt++;
if (script)
script->refcnt++;
return script;
}
static inline void
grub_script_put (struct grub_script *script)
{
if (! script)
return;
if (script->refcnt == 0)
grub_script_free (script);
else

View file

@ -52,9 +52,12 @@ grub_script_argv_free (struct grub_script_argv *argv)
grub_free (argv->args);
}
if (argv->script)
grub_script_put (argv->script);
argv->argc = 0;
argv->args = 0;
argv->script = 0;
}
/* Prepare for next argc. */

View file

@ -201,7 +201,7 @@ grub_script_arglist_to_argv (struct grub_script_arglist *arglist,
grub_script_argv_append (&result, arg->str) ||
grub_script_argv_append (&result, "}"))
goto fail;
result.script = arg->script;
result.script = grub_script_get (arg->script);
break;
case GRUB_SCRIPT_ARG_TYPE_TEXT:

View file

@ -34,7 +34,7 @@ grub_normal_parse_line (char *line, grub_reader_getline_t getline)
grub_script_execute (parsed_script);
/* The parsed script was executed, throw it away. */
grub_script_free (parsed_script);
grub_script_put (parsed_script);
}
return grub_errno;

View file

@ -38,6 +38,7 @@
struct {
unsigned offset;
struct grub_script_mem *memory;
struct grub_script *scripts;
};
}
@ -149,16 +150,45 @@ argument : "case" { $$ = grub_script_add_arglist (state, 0, $1); }
| word { $$ = $1; }
;
/*
Block parameter is passed to commands in two forms: as unparsed
string and as pre-parsed grub_script object. Passing as grub_script
object makes memory management difficult, because:
(1) Command may want to keep a reference to grub_script objects for
later use, so script framework may not free the grub_script
object after command completes.
(2) Command may get called multiple times with same grub_script
object under loops, so we should not let command implementation
to free the grub_script object.
To solve above problems, we rely on reference counting for
grub_script objects. Commands that want to keep the grub_script
object must take a reference to it.
Other complexity comes with arbitrary nesting of grub_script
objects: a grub_script object may have commands with several block
parameters, and each block parameter may further contain multiple
block parameters nested. We use temporary variable, state->scripts
to collect nested child scripts (that are linked by siblings and
children members), and will build grub_scripts tree from bottom.
*/
block: "{"
{
grub_script_lexer_ref (state->lexerstate);
$<offset>$ = grub_script_lexer_record_start (state);
$<memory>$ = grub_script_mem_record (state);
/* save currently known scripts. */
$<scripts>$ = state->scripts;
state->scripts = 0;
}
commands1 delimiters0 "}"
{
char *p;
struct grub_script_mem *memory;
struct grub_script *s = $<scripts>2;
memory = grub_script_mem_record_stop (state, $<memory>2);
if ((p = grub_script_lexer_record_stop (state, $<offset>2)))
@ -168,6 +198,19 @@ block: "{"
if (! $$ || ! ($$->script = grub_script_create ($3, memory)))
grub_script_mem_free (memory);
else {
/* attach nested scripts to $$->script as children */
$$->script->children = state->scripts;
/* restore old scripts; append $$->script to siblings. */
state->scripts = $<scripts>2 ?: $$->script;
if (s) {
while (s->siblings)
s = s->siblings;
s->siblings = $$->script;
}
}
grub_script_lexer_deref (state->lexerstate);
}
;
@ -240,10 +283,13 @@ commands1: newlines0 command
}
;
function: "function" "name"
function: "function" "name"
{
grub_script_lexer_ref (state->lexerstate);
state->func_mem = grub_script_mem_record (state);
$<scripts>$ = state->scripts;
state->scripts = 0;
}
delimiters0 "{" commands1 delimiters1 "}"
{
@ -253,9 +299,12 @@ function: "function" "name"
script = grub_script_create ($6, state->func_mem);
if (! script)
grub_script_mem_free (state->func_mem);
else
else {
script->children = state->scripts;
grub_script_function_create ($2, script);
}
state->scripts = $<scripts>3;
grub_script_lexer_deref (state->lexerstate);
}
;

View file

@ -94,12 +94,19 @@ grub_script_mem_record_stop (struct grub_parser_param *state,
void
grub_script_free (struct grub_script *script)
{
struct grub_script *s;
if (!script)
return;
if (script->mem)
grub_script_mem_free (script->mem);
s = script->children;
while (s) {
grub_script_put (s);
s = s->siblings;
}
grub_free (script);
}
@ -322,6 +329,8 @@ grub_script_create (struct grub_script_cmd *cmd, struct grub_script_mem *mem)
parsed->mem = mem;
parsed->cmd = cmd;
parsed->refcnt = 0;
parsed->siblings = 0;
parsed->children = 0;
return parsed;
}
@ -370,6 +379,7 @@ grub_script_parse (char *script, grub_reader_getline_t getline)
parsed->mem = grub_script_mem_record_stop (parsestate, membackup);
parsed->cmd = parsestate->parsed;
parsed->children = parsestate->scripts;
grub_script_lexer_fini (lexstate);
grub_free (parsestate);