pull-in block-arg again
This commit is contained in:
commit
8527be0c5d
6 changed files with 79 additions and 5 deletions
|
@ -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
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
;
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue