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;
|
unsigned refcnt;
|
||||||
struct grub_script_mem *mem;
|
struct grub_script_mem *mem;
|
||||||
struct grub_script_cmd *cmd;
|
struct grub_script_cmd *cmd;
|
||||||
|
|
||||||
|
/* Other grub_script's from block arguments. */
|
||||||
|
struct grub_script *siblings;
|
||||||
|
struct grub_script *children;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
|
@ -207,6 +211,9 @@ struct grub_parser_param
|
||||||
/* The memory that was used while parsing and scanning. */
|
/* The memory that was used while parsing and scanning. */
|
||||||
struct grub_script_mem *memused;
|
struct grub_script_mem *memused;
|
||||||
|
|
||||||
|
/* The block argument scripts. */
|
||||||
|
struct grub_script *scripts;
|
||||||
|
|
||||||
/* The result of the parser. */
|
/* The result of the parser. */
|
||||||
struct grub_script_cmd *parsed;
|
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);
|
struct grub_script *cmd);
|
||||||
void grub_script_function_remove (const char *name);
|
void grub_script_function_remove (const char *name);
|
||||||
grub_script_function_t grub_script_function_find (char *functionname);
|
grub_script_function_t grub_script_function_find (char *functionname);
|
||||||
|
|
||||||
grub_err_t grub_script_function_call (grub_script_function_t func,
|
grub_err_t grub_script_function_call (grub_script_function_t func,
|
||||||
int argc, char **args);
|
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 *
|
static inline struct grub_script *
|
||||||
grub_script_get (struct grub_script *script)
|
grub_script_get (struct grub_script *script)
|
||||||
{
|
{
|
||||||
script->refcnt++;
|
if (script)
|
||||||
|
script->refcnt++;
|
||||||
return script;
|
return script;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
grub_script_put (struct grub_script *script)
|
grub_script_put (struct grub_script *script)
|
||||||
{
|
{
|
||||||
|
if (! script)
|
||||||
|
return;
|
||||||
|
|
||||||
if (script->refcnt == 0)
|
if (script->refcnt == 0)
|
||||||
grub_script_free (script);
|
grub_script_free (script);
|
||||||
else
|
else
|
||||||
|
|
|
@ -52,9 +52,12 @@ grub_script_argv_free (struct grub_script_argv *argv)
|
||||||
|
|
||||||
grub_free (argv->args);
|
grub_free (argv->args);
|
||||||
}
|
}
|
||||||
|
if (argv->script)
|
||||||
|
grub_script_put (argv->script);
|
||||||
|
|
||||||
argv->argc = 0;
|
argv->argc = 0;
|
||||||
argv->args = 0;
|
argv->args = 0;
|
||||||
|
argv->script = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Prepare for next argc. */
|
/* 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, arg->str) ||
|
||||||
grub_script_argv_append (&result, "}"))
|
grub_script_argv_append (&result, "}"))
|
||||||
goto fail;
|
goto fail;
|
||||||
result.script = arg->script;
|
result.script = grub_script_get (arg->script);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GRUB_SCRIPT_ARG_TYPE_TEXT:
|
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);
|
grub_script_execute (parsed_script);
|
||||||
|
|
||||||
/* The parsed script was executed, throw it away. */
|
/* The parsed script was executed, throw it away. */
|
||||||
grub_script_free (parsed_script);
|
grub_script_put (parsed_script);
|
||||||
}
|
}
|
||||||
|
|
||||||
return grub_errno;
|
return grub_errno;
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
struct {
|
struct {
|
||||||
unsigned offset;
|
unsigned offset;
|
||||||
struct grub_script_mem *memory;
|
struct grub_script_mem *memory;
|
||||||
|
struct grub_script *scripts;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,16 +150,45 @@ argument : "case" { $$ = grub_script_add_arglist (state, 0, $1); }
|
||||||
| word { $$ = $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: "{"
|
block: "{"
|
||||||
{
|
{
|
||||||
grub_script_lexer_ref (state->lexerstate);
|
grub_script_lexer_ref (state->lexerstate);
|
||||||
$<offset>$ = grub_script_lexer_record_start (state);
|
$<offset>$ = grub_script_lexer_record_start (state);
|
||||||
$<memory>$ = grub_script_mem_record (state);
|
$<memory>$ = grub_script_mem_record (state);
|
||||||
|
|
||||||
|
/* save currently known scripts. */
|
||||||
|
$<scripts>$ = state->scripts;
|
||||||
|
state->scripts = 0;
|
||||||
}
|
}
|
||||||
commands1 delimiters0 "}"
|
commands1 delimiters0 "}"
|
||||||
{
|
{
|
||||||
char *p;
|
char *p;
|
||||||
struct grub_script_mem *memory;
|
struct grub_script_mem *memory;
|
||||||
|
struct grub_script *s = $<scripts>2;
|
||||||
|
|
||||||
memory = grub_script_mem_record_stop (state, $<memory>2);
|
memory = grub_script_mem_record_stop (state, $<memory>2);
|
||||||
if ((p = grub_script_lexer_record_stop (state, $<offset>2)))
|
if ((p = grub_script_lexer_record_stop (state, $<offset>2)))
|
||||||
|
@ -168,6 +198,19 @@ block: "{"
|
||||||
if (! $$ || ! ($$->script = grub_script_create ($3, memory)))
|
if (! $$ || ! ($$->script = grub_script_create ($3, memory)))
|
||||||
grub_script_mem_free (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);
|
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);
|
grub_script_lexer_ref (state->lexerstate);
|
||||||
state->func_mem = grub_script_mem_record (state);
|
state->func_mem = grub_script_mem_record (state);
|
||||||
|
|
||||||
|
$<scripts>$ = state->scripts;
|
||||||
|
state->scripts = 0;
|
||||||
}
|
}
|
||||||
delimiters0 "{" commands1 delimiters1 "}"
|
delimiters0 "{" commands1 delimiters1 "}"
|
||||||
{
|
{
|
||||||
|
@ -253,9 +299,12 @@ function: "function" "name"
|
||||||
script = grub_script_create ($6, state->func_mem);
|
script = grub_script_create ($6, state->func_mem);
|
||||||
if (! script)
|
if (! script)
|
||||||
grub_script_mem_free (state->func_mem);
|
grub_script_mem_free (state->func_mem);
|
||||||
else
|
else {
|
||||||
|
script->children = state->scripts;
|
||||||
grub_script_function_create ($2, script);
|
grub_script_function_create ($2, script);
|
||||||
|
}
|
||||||
|
|
||||||
|
state->scripts = $<scripts>3;
|
||||||
grub_script_lexer_deref (state->lexerstate);
|
grub_script_lexer_deref (state->lexerstate);
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
|
@ -94,12 +94,19 @@ grub_script_mem_record_stop (struct grub_parser_param *state,
|
||||||
void
|
void
|
||||||
grub_script_free (struct grub_script *script)
|
grub_script_free (struct grub_script *script)
|
||||||
{
|
{
|
||||||
|
struct grub_script *s;
|
||||||
|
|
||||||
if (!script)
|
if (!script)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (script->mem)
|
if (script->mem)
|
||||||
grub_script_mem_free (script->mem);
|
grub_script_mem_free (script->mem);
|
||||||
|
|
||||||
|
s = script->children;
|
||||||
|
while (s) {
|
||||||
|
grub_script_put (s);
|
||||||
|
s = s->siblings;
|
||||||
|
}
|
||||||
grub_free (script);
|
grub_free (script);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -322,6 +329,8 @@ grub_script_create (struct grub_script_cmd *cmd, struct grub_script_mem *mem)
|
||||||
parsed->mem = mem;
|
parsed->mem = mem;
|
||||||
parsed->cmd = cmd;
|
parsed->cmd = cmd;
|
||||||
parsed->refcnt = 0;
|
parsed->refcnt = 0;
|
||||||
|
parsed->siblings = 0;
|
||||||
|
parsed->children = 0;
|
||||||
|
|
||||||
return parsed;
|
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->mem = grub_script_mem_record_stop (parsestate, membackup);
|
||||||
parsed->cmd = parsestate->parsed;
|
parsed->cmd = parsestate->parsed;
|
||||||
|
parsed->children = parsestate->scripts;
|
||||||
|
|
||||||
grub_script_lexer_fini (lexstate);
|
grub_script_lexer_fini (lexstate);
|
||||||
grub_free (parsestate);
|
grub_free (parsestate);
|
||||||
|
|
Loading…
Reference in a new issue