The ultimate GIB bugfix commit, including reworked semantic processing,

a fix for arguments passed to a GIB function run via rcon, and various
other fixes.
This commit is contained in:
Brian Koropoff 2003-04-11 02:57:11 +00:00
parent 645b7ca3d6
commit d8c0f50c11
12 changed files with 200 additions and 340 deletions

View file

@ -4,10 +4,10 @@ includedir = $(prefix)/include/QF
include_HEADERS = bspfile.h cbuf.h cdaudio.h checksum.h clip_hull.h cmd.h \
console.h crc.h csqc.h cvar.h dstring.h draw.h gib_buffer.h \
gib_builtin.h gib_execute.h gib_function.h gib_init.h gib_parse.h \
gib_process.h gib_regex.h gib_thread.h gib_tree.h gib_vars.h hash.h hl.h \
idparse.h in_event.h info.h input.h joystick.h keys.h link.h locs.h \
mathlib.h mdfour.h model.h modelgen.h msg.h pak.h pakfile.h pcx.h \
plugin.h pr_comp.h pr_debug.h pr_obj.h progs.h qargs.h qdefs.h qendian.h \
qfplist.h qtypes.h quakefs.h quakeio.h render.h riff.h screen.h sizebuf.h \
skin.h sound.h spritegn.h sys.h teamplay.h texture.h tga.h uint32.h va.h \
ver_check.h vid.h wad.h zone.h
gib_process.h gib_regex.h gib_semantics.h gib_thread.h gib_tree.h \
gib_vars.h hash.h hl.h idparse.h in_event.h info.h input.h joystick.h \
keys.h link.h locs.h mathlib.h mdfour.h model.h modelgen.h msg.h pak.h \
pakfile.h pcx.h plugin.h pr_comp.h pr_debug.h pr_obj.h progs.h qargs.h \
qdefs.h qendian.h qfplist.h qtypes.h quakefs.h quakeio.h render.h riff.h \
screen.h sizebuf.h skin.h sound.h spritegn.h sys.h teamplay.h texture.h \
tga.h uint32.h va.h ver_check.h vid.h wad.h zone.h

View file

@ -48,7 +48,9 @@ typedef struct gib_function_s {
void GIB_Function_Define (const char *name, const char *text, gib_tree_t *program, gib_script_t *script, hashtab_t *globals);
gib_function_t *GIB_Function_Find (const char *name);
void GIB_Function_Prepare_Args (cbuf_t *cbuf, dstring_t **args, unsigned int argc);
void GIB_Function_Execute (cbuf_t *cbuf, gib_function_t *func, dstring_t **args, unsigned int argc);
void GIB_Function_Prepare_Args (cbuf_t *cbuf, const char **args, unsigned int argc);
void GIB_Function_Prepare_Args_D (cbuf_t *cbuf, dstring_t **args, unsigned int argc);
void GIB_Function_Execute (cbuf_t *cbuf, gib_function_t *func, const char **args, unsigned int argc);
void GIB_Function_Execute_D (cbuf_t *cbuf, gib_function_t *func, dstring_t **args, unsigned int argc);
#endif

View file

@ -40,8 +40,9 @@ char GIB_Parse_Match_Paren (const char *str, unsigned int *i);
char GIB_Parse_Match_Var (const char *str, unsigned int *i);
gib_tree_t *GIB_Parse_Lines (const char *program, unsigned int pofs);
gib_tree_t *GIB_Parse_Embedded (const char *program, unsigned int pofs, gib_tree_t **embedded);
gib_tree_t *GIB_Parse_Embedded (gib_tree_t *token);
extern qboolean gib_parse_error;
void GIB_Parse_Error (const char *msg, unsigned int pos);
const char *GIB_Parse_ErrorMsg (void);
unsigned int GIB_Parse_ErrorPos (void);

View file

@ -54,10 +54,10 @@ typedef struct gib_tree_s {
TREE_T_COND, // Conditional jump
TREE_T_ASSIGN, // Assignment
TREE_T_JUMP, // Jump
TREE_T_JUMPPLUS, // Jump, go to next instruction
TREE_T_ARG, // Argument (not a line)
TREE_T_FORNEXT, // Fetch next arg in for loop
TREE_T_META // Info node
TREE_T_META, // Info node
TREE_T_NOP // Do nothing (label, etc)
} type;
struct gib_tree_s *children, *next, *jump;
} gib_tree_t;
@ -66,5 +66,5 @@ gib_tree_t *GIB_Tree_New (enum gib_tree_type_e type);
void GIB_Tree_Free_Recursive (gib_tree_t *tree);
void GIB_Tree_Ref (gib_tree_t **tp);
void GIB_Tree_Unref (gib_tree_t **tp);
#endif /* __GIB_TREE_H */

View file

@ -7,4 +7,5 @@ lib_LTLIBRARIES= libQFgib.la
libQFgib_la_LDFLAGS= -version-info 1:0:0
libQFgib_la_SOURCES= \
gib_buffer.c gib_builtin.c gib_execute.c gib_function.c gib_parse.c gib_process.c \
gib_regex.c gib_thread.c gib_vars.c gib_init.c gib_tree.c ops.c exp.c regex.c
gib_regex.c gib_thread.c gib_vars.c gib_init.c gib_tree.c gib_semantics.c ops.c \
exp.c regex.c

View file

@ -208,6 +208,9 @@ GIB_Local_f (void)
if (GIB_Argc () >= 3)
GIB_Var_Assign (var, index, cbuf_active->args->argv + 3,
GIB_Argc () - 3);
if (GIB_CanReturn ())
for (i = 3; i < GIB_Argc(); i++)
GIB_Return (GIB_Argv(i));
} else for (i = 1; i < GIB_Argc(); i++)
var = GIB_Var_Get_Complex (&GIB_DATA (cbuf_active)->locals, &zero,
GIB_Argv (i), &index, true);
@ -229,6 +232,9 @@ GIB_Global_f (void)
if (GIB_Argc () >= 3)
GIB_Var_Assign (var, index, cbuf_active->args->argv + 3,
GIB_Argc () - 3);
if (GIB_CanReturn ())
for (i = 3; i < GIB_Argc(); i++)
GIB_Return (GIB_Argv(i));
} else for (i = 1; i < GIB_Argc(); i++)
var = GIB_Var_Get_Complex (&GIB_DATA (cbuf_active)->globals, &zero,
GIB_Argv (i), &index, true);
@ -321,19 +327,21 @@ static void
GIB_Runexported_f (void)
{
gib_function_t *f;
const char **args;
if (!(f = GIB_Function_Find (Cmd_Argv (0))))
Sys_Printf ("Error: No function found for exported command \"%s\".\n"
"This is most likely a bug, please report it to"
"The QuakeForge developers.", Cmd_Argv (0));
else {
cbuf_t *sub = Cbuf_New (&gib_interp);
cbuf_t *sub = Cbuf_PushStack (&gib_interp);
unsigned int i;
GIB_Function_Execute (sub, f, cbuf_active->args->argv,
cbuf_active->args->argc);
cbuf_active->down = sub;
sub->up = cbuf_active;
cbuf_active->state = CBUF_STATE_STACK;
args = malloc (sizeof (char *) * Cmd_Argc());
for (i = 0; i < Cmd_Argc(); i++)
args[i] = Cmd_Argv(i);
GIB_Function_Execute (sub, f, args, Cmd_Argc());
free (args);
}
}
@ -586,7 +594,7 @@ GIB_Thread_Create_f (void)
else {
gib_thread_t *thread = GIB_Thread_New ();
GIB_Function_Execute (thread->cbuf, f, cbuf_active->args->argv + 1,
GIB_Function_Execute_D (thread->cbuf, f, cbuf_active->args->argv + 1,
cbuf_active->args->argc - 1);
GIB_Thread_Add (thread);
if (GIB_CanReturn ())

View file

@ -58,8 +58,7 @@ GIB_Execute_Generate_Composite (struct cbuf_s *cbuf)
for (i = 0; i < args->argc; i++) {
// ->str could be moved by realloc when a dstring is resized
// so save the offset instead of the pointer
args->args[i] =
(const char *) strlen (GIB_DATA (cbuf)->arg_composite->str);
args->args[i] = (const char *) strlen (GIB_DATA (cbuf)->arg_composite->str);
dstring_appendstr (GIB_DATA (cbuf)->arg_composite, args->argv[i]->str);
dstring_appendstr (GIB_DATA (cbuf)->arg_composite, " ");
}
@ -71,8 +70,7 @@ GIB_Execute_Generate_Composite (struct cbuf_s *cbuf)
for (i = 0; i < args->argc; i++)
// now that arg_composite is done we can add the pointer to the stored
// offsets and get valid pointers. This *should* be portable.
args->args[i] +=
(unsigned long int) GIB_DATA (cbuf)->arg_composite->str;
args->args[i] += (unsigned long int) GIB_DATA (cbuf)->arg_composite->str;
}
static void
@ -101,9 +99,11 @@ GIB_Execute_Split_Var (cbuf_t * cbuf)
break;
}
cbuf->args->argc--;
if (!(var = GIB_Var_Get_Complex (&GIB_DATA (cbuf)->locals,
&GIB_DATA (cbuf)->globals, str, &i, false)))
return;
if (!(var = GIB_Var_Get_Complex (
&GIB_DATA (cbuf)->locals,
&GIB_DATA (cbuf)->globals,
str, &i, false)))
return;
if (end < 0)
end += var->size;
else if (end > var->size)
@ -123,17 +123,19 @@ GIB_Execute_Split_Var (cbuf_t * cbuf)
}
} else {
gib_var_t **vlist, **v;
cbuf->args->argc--;
if (!(var = GIB_Var_Get_Complex (&GIB_DATA (cbuf)->locals,
&GIB_DATA (cbuf)->globals, str, &i, false)))
return;
if (!(var = GIB_Var_Get_Complex (
&GIB_DATA (cbuf)->locals,
&GIB_DATA (cbuf)->globals,
str, &i, false)))
return;
if (!var->array[i].leaves)
return;
vlist = (gib_var_t **) Hash_GetList (var->array[i].leaves);
for (v = vlist; *v; v++)
Cbuf_ArgsAdd (cbuf->args, (*v)->key);
}
}
}
static int
@ -175,17 +177,17 @@ GIB_Execute_For_Next (cbuf_t * cbuf)
{
unsigned int index;
gib_var_t *var;
struct gib_dsarray_s *array =
GIB_DATA (cbuf)->stack.values + GIB_DATA (cbuf)->stack.p - 1;
struct gib_dsarray_s *array = GIB_DATA (cbuf)->stack.values + GIB_DATA (cbuf)->stack.p - 1;
if (array->size == 1) {
GIB_Buffer_Pop_Sstack (cbuf);
return -1;
}
array->size--;
var =
GIB_Var_Get_Complex (&GIB_DATA (cbuf)->locals,
&GIB_DATA (cbuf)->globals, array->dstrs[0]->str,
&index, true);
var = GIB_Var_Get_Complex (
&GIB_DATA (cbuf)->locals,
&GIB_DATA (cbuf)->globals, array->dstrs[0]->str,
&index, true
);
dstring_clearstr (var->array[index].value);
dstring_appendstr (var->array[index].value, array->dstrs[array->size]->str);
return 0;
@ -199,40 +201,53 @@ GIB_Execute (cbuf_t * cbuf)
gib_function_t *f;
unsigned int index;
gib_var_t *var;
unsigned int i;
if (!g->program)
return;
g->ip = g->ip ? g->ip->next : g->program;
while (g->ip) {
switch (g->ip->type) {
case TREE_T_JUMP:
case TREE_T_NOP: // Move to next instruction
g->ip = g->ip->next;
continue;
case TREE_T_JUMP: // Absolute jump
g->ip = g->ip->jump;
continue;
case TREE_T_JUMPPLUS:
g->ip = g->ip->jump->next;
continue;
case TREE_T_FORNEXT:
case TREE_T_FORNEXT: // Fetch next value in a for loop
if (GIB_Execute_For_Next (cbuf))
g->ip = g->ip->jump->next;
else
g->ip = g->ip->next;
continue;
case TREE_T_COND:
case TREE_T_COND: // Conditional jump, move to next instruction
if (GIB_Execute_Prepare_Line (cbuf, g->ip))
return;
if (g->ip->flags & TREE_L_NOT ? atof (cbuf->args->argv[1]->str) : !atof (cbuf->args->argv[1]->str))
g->ip = g->ip->jump->next;
if (g->ip->flags & TREE_L_NOT ?
atof (cbuf->args->argv[1]->str) :
!atof (cbuf->args->argv[1]->str))
g->ip = g->ip->jump->next;
else
g->ip = g->ip->next;
continue;
case TREE_T_ASSIGN:
case TREE_T_ASSIGN: // Assignment
if (GIB_Execute_Prepare_Line (cbuf, g->ip))
return;
var = GIB_Var_Get_Complex (&g->locals, &g->globals, cbuf->args->argv[0]->str, &index, true);
var = GIB_Var_Get_Complex (
&g->locals,
&g->globals,
cbuf->args->argv[0]->str, &index, true);
GIB_Var_Assign (var, index, cbuf->args->argv + 2, cbuf->args->argc - 2);
if (g->ip->flags & TREE_L_EMBED) {
GIB_Buffer_Push_Sstack (cbuf);
g->waitret = true;
for (i = 2; i < cbuf->args->argc; i++)
GIB_Return (cbuf->args->argv[i]->str);
} else
g->waitret = false;
g->ip = g->ip->next;
continue;
case TREE_T_CMD:
case TREE_T_CMD: // Normal command
if (GIB_Execute_Prepare_Line (cbuf, g->ip))
return;
if (g->ip->flags & TREE_L_EMBED) {
@ -246,13 +261,17 @@ GIB_Execute (cbuf_t * cbuf)
b->func ();
else if ((f = GIB_Function_Find (cbuf->args->argv[0]->str))) {
cbuf_t *new = Cbuf_PushStack (&gib_interp);
GIB_Function_Execute (new, f, cbuf->args->argv, cbuf->args->argc);
GIB_Function_Execute_D (
new, f,
cbuf->args->argv, cbuf->args->argc
);
} else {
GIB_Execute_Generate_Composite (cbuf);
if (Cmd_Command (cbuf->args))
GIB_Error (
"command",
"No builtin, function, or console command named '%s' was found.",
"No builtin, function, or console command "
"named '%s' was found.",
cbuf->args->argv[0]->str
);
}
@ -261,8 +280,11 @@ GIB_Execute (cbuf_t * cbuf)
}
g->ip = g->ip->next;
continue;
default:
GIB_Error ("QUAKEFORGE-BUG-PLEASE-REPORT", "Unknown instruction type; tastes like chicken.");
default: // We should never get here
GIB_Error (
"QUAKEFORGE-BUG-PLEASE-REPORT",
"Unknown instruction type; tastes like chicken."
);
return;
}
}

View file

@ -149,7 +149,29 @@ GIB_Function_Find (const char *name)
}
void
GIB_Function_Prepare_Args (cbuf_t * cbuf, dstring_t ** args, unsigned int argc)
GIB_Function_Prepare_Args (cbuf_t * cbuf, const char **args, unsigned int argc)
{
static hashtab_t *zero = 0;
unsigned int i;
gib_var_t *var;
static char argss[] = "args";
var =
GIB_Var_Get_Complex (&GIB_DATA (cbuf)->locals, &zero, argss, &i, true);
var->array = realloc (var->array, sizeof (struct gib_varray_s) * argc);
memset (var->array + 1, 0, (argc - 1) * sizeof (struct gib_varray_s));
var->size = argc;
for (i = 0; i < argc; i++) {
if (var->array[i].value)
dstring_clearstr (var->array[i].value);
else
var->array[i].value = dstring_newstr ();
dstring_appendstr (var->array[i].value, args[i]);
}
}
void
GIB_Function_Prepare_Args_D (cbuf_t * cbuf, dstring_t **args, unsigned int argc)
{
static hashtab_t *zero = 0;
unsigned int i;
@ -178,7 +200,7 @@ GIB_Function_Prepare_Args (cbuf_t * cbuf, dstring_t ** args, unsigned int argc)
*/
void
GIB_Function_Execute (cbuf_t * cbuf, gib_function_t * func, dstring_t ** args,
GIB_Function_Execute (cbuf_t * cbuf, gib_function_t * func, const char ** args,
unsigned int argc)
{
GIB_Tree_Ref (&func->program);
@ -189,3 +211,16 @@ GIB_Function_Execute (cbuf_t * cbuf, gib_function_t * func, dstring_t ** args,
GIB_DATA (cbuf)->globals = func->globals;
GIB_Function_Prepare_Args (cbuf, args, argc);
}
void
GIB_Function_Execute_D (cbuf_t * cbuf, gib_function_t * func, dstring_t ** args,
unsigned int argc)
{
GIB_Tree_Ref (&func->program);
if (func->script)
func->script->refs++;
GIB_Buffer_Set_Program (cbuf, func->program);
GIB_DATA (cbuf)->script = func->script;
GIB_DATA (cbuf)->globals = func->globals;
GIB_Function_Prepare_Args_D (cbuf, args, argc);
}

View file

@ -50,6 +50,7 @@ const char rcsid[] = "$Id$";
#include "QF/gib_function.h"
#include "QF/gib_vars.h"
#include "QF/gib_parse.h"
#include "QF/gib_semantics.h"
/*
@ -78,7 +79,7 @@ GIB_Escaped (const char *str, int i)
matching character is found, calling themselves and their
neighbors recursively to handle sections of string that they
are uninterested in.
FIXME: Make sure everything is calling everything else it might
need to. Make appropriate functions intolerant of newlines.
*/
@ -195,7 +196,7 @@ qboolean gib_parse_error;
unsigned int gib_parse_error_pos;
const char *gib_parse_error_msg;
static void
void
GIB_Parse_Error (const char *msg, unsigned int pos)
{
gib_parse_error = true;
@ -215,14 +216,12 @@ GIB_Parse_ErrorPos (void)
return gib_parse_error_pos;
}
// FIXME: Concatenation in stupid circumstances should generate errors
static gib_tree_t *
GIB_Parse_Tokens (const char *program, unsigned int *i, unsigned int pofs, gib_tree_t ** embedded)
GIB_Parse_Tokens (const char *program, unsigned int *i, unsigned int pofs)
{
char c = 0, delim, *str;
unsigned int tstart, start;
gib_tree_t *nodes = 0, *cur, *new, *embs = 0, *tmp;
gib_tree_t *nodes = 0, *cur, *new;
gib_tree_t **node = &nodes;
enum {CAT_NORMAL = 0, CAT_DISALLOW, CAT_CONCAT} cat = CAT_DISALLOW;
const char *catestr = "Comma found before first argument, nothing to concatenate to.";
@ -314,25 +313,6 @@ GIB_Parse_Tokens (const char *program, unsigned int *i, unsigned int pofs, gib_t
cur->children = new;
// Check for embedded commands/variables
} else if (cur->delim == ' ' || cur->delim == '(') {
if (!
(cur->children =
GIB_Parse_Embedded (str, tstart + pofs, &new))) {
// There could be no embedded elements, so check for a real
// error
if (gib_parse_error)
goto ERROR;
} else {
// Link/set flags
cur->flags |= TREE_A_EMBED;
// Add any embedded commands to top of chain
if (new) {
for (tmp = new; tmp->next; tmp = tmp->next);
tmp->next = embs;
embs = new;
}
}
// Check for array splitting
// Concatenating this onto something else is non-sensical
if (cur->delim == ' ' && (str[0] == '@' || str[0] == '%')) {
if (cat == CAT_CONCAT) {
GIB_Parse_Error ("Variable expansions may not be concatenated with other arguments.", start + pofs);
@ -342,10 +322,9 @@ GIB_Parse_Tokens (const char *program, unsigned int *i, unsigned int pofs, gib_t
cat = CAT_DISALLOW;
cur->flags |= TREE_A_EXPAND;
}
// We can handle escape characters now
// We can handle escape characters now
} else if (cur->delim == '\"')
GIB_Process_Escapes (str);
if (cat == CAT_CONCAT)
cur->flags |= TREE_A_CONCAT;
// Nothing left to parse?
@ -357,217 +336,20 @@ GIB_Parse_Tokens (const char *program, unsigned int *i, unsigned int pofs, gib_t
node = &cur->next;
}
DONE:
*embedded = embs;
return nodes;
ERROR:
if (c)
GIB_Parse_Error (va ("Could not find match for '%c'.", c), *i + pofs);
if (nodes)
GIB_Tree_Unref (&nodes);
if (embs)
GIB_Tree_Unref (&embs);
return 0;
}
static gib_tree_t *
GIB_Parse_Semantic_Preprocess (gib_tree_t * line)
{
gib_tree_t *p, *start = line;
// If second token is concatenated, than the first can't possibly mean anything
if (line->children->next && line->children->next->flags & TREE_A_CONCAT)
return line;
while (!strcmp (line->children->str, "if")
|| !strcmp (line->children->str, "ifnot")) {
// Sanity checking
if (!line->children->next || !line->children->next->next) {
GIB_Parse_Error ("Not enough arguments to 'if' statement.",
line->start);
return line;
} else if (!line->children->next->next->children
|| line->children->next->next->delim != '{') {
GIB_Parse_Error
("First program block in 'if' statement not enclosed in braces or invalid.",
line->start);
return line;
} else if (line->flags & TREE_L_EMBED) {
GIB_Parse_Error
("'if' statements may not be used in embedded commands.",
line->start);
return line;
}
// Set as conditional
line->type = TREE_T_COND;
if (line->children->str[2])
line->flags |= TREE_L_NOT;
// Save our spot
p = line;
// Move subprogram inline
line->next = line->children->next->next->children;
line->children->next->next->children = 0;
// Find end of subprogram
while (line->next)
line = line->next;
// Handle "else"
if (p->children->next->next->next
&& !strcmp (p->children->next->next->next->str, "else")) {
// Sanity checking
if (!p->children->next->next->next->next) {
GIB_Parse_Error
("'if' statement contains 'else' but no secondary program block or command.",
line->start);
return line;
}
// On 'true' first block must jump past this
// We will figure out jump target later
line->next = GIB_Tree_New (TREE_T_JUMPPLUS);
line = line->next;
// Jump to else block on 'false'
p->jump = line;
// Is "else" followed by a subprogram?
if (p->children->next->next->next->next->delim == '{') {
// Move subprogram inline
line->next = p->children->next->next->next->next->children;
p->children->next->next->next->next->children = 0;
while (line->next)
line = line->next;
} else {
// Push rest of tokens into a new line
line->next = GIB_Tree_New (TREE_T_CMD);
line->next->children = p->children->next->next->next->next;
p->children->next->next->next->next = 0;
line = line->next;
}
} else {
// Jump past block on 'false'
p->jump = line;
break; // Don't touch if statements in the sub program
}
}
// Now we know exit point from if-else if chain, set our jumps
while (start) {
if (start->type == TREE_T_JUMPPLUS && !start->jump)
start->jump = line;
start = start->next;
}
// Nothing expanded from a line remains, exit now
if (!line->children)
return line;
// If we have a while loop, handle that
if (!strcmp (line->children->str, "while")) {
// Sanity checks
if (!line->children->next || !line->children->next->next) {
GIB_Parse_Error ("Not enough arguments to 'while' statement.",
line->start);
return line;
} else if (!line->children->next->next->children
|| line->children->next->next->delim != '{') {
GIB_Parse_Error
("Program block in 'while' statement not enclosed in braces or invalid.",
line->start);
return line;
} else if (line->flags & TREE_L_EMBED) {
GIB_Parse_Error
("'while' statements may not be used in embedded commands.",
line->start);
return line;
}
// Set conditional flag
line->type = TREE_T_COND;
// Save our spot
p = line;
// Move subprogram inline
line->next = line->children->next->next->children;
line->children->next->next->children = 0;
// Find end of subprogram
for (; line->next; line = line->next)
if (!line->jump && line->children) {
if (!strcmp (line->children->str, "continue")) {
line->type = TREE_T_JUMP;
line->jump = p;
} else if (!strcmp (line->children->str, "break"))
line->type = TREE_T_JUMPPLUS;
}
line->next = GIB_Tree_New (TREE_T_JUMP);
line->next->jump = p;
line = line->next;
// Mark jump point out of loop
p->jump = line;
// Set jumps out of loop for "break" commands;
while (p) {
if (p->type == TREE_T_JUMPPLUS && !p->jump)
p->jump = line;
p = p->next;
}
} else if (!strcmp (line->children->str, "for")) {
gib_tree_t *tmp;
// Sanity checks
if (!line->children->next || !line->children->next->next
|| strcmp (line->children->next->next->str, "in")
|| !line->children->next->next->next
|| !line->children->next->next->next->next) {
GIB_Parse_Error ("Malformed 'for' statement.", line->start);
return line;
} else if (line->flags & TREE_L_EMBED) {
GIB_Parse_Error ("'for' statements may not be used in embedded commands.", line->start);
return line;
}
// Find last token in line (contains program block)
for (tmp = line->children->next->next->next->next; tmp->next;
tmp = tmp->next);
// More sanity
if (tmp->delim != '{' || !tmp->children) {
GIB_Parse_Error
("Program block in 'for' statement not enclosed in braces or invalid.",
line->start);
return line;
}
// Add instruction to fetch next argument (this is the true loop start)
line->next = GIB_Tree_New (TREE_T_FORNEXT);
line = line->next;
p = line;
// Move subprogram inline
line->next = tmp->children;
tmp->children = 0;
// Find end of subprogram
for (; line->next; line = line->next)
if (!line->jump && line->children) {
if (!strcmp (line->children->str, "continue")) {
line->type = TREE_T_JUMP;
line->jump = p;
} else if (!strcmp (line->children->str, "break"))
line->type = TREE_T_JUMPPLUS;
}
line->next = GIB_Tree_New (TREE_T_JUMP);
line->next->jump = p;
line = line->next;
// Mark jump point out of loop
p->jump = line;
// Mark jump point out of loop for break command
while (p) {
if (p->type == TREE_T_JUMPPLUS && !p->jump)
p->jump = line;
p = p->next;
}
} else if (
line->children->next &&
!(line->children->next->flags & TREE_A_CONCAT) &&
line->children->next->delim == ' ' &&
!strcmp (line->children->next->str, "=")
) {
if (line->flags & TREE_L_EMBED)
GIB_Parse_Error ("Assignment may not be used as an embedded command.", line->start);
line->type = TREE_T_ASSIGN;
}
return line;
}
gib_tree_t *
GIB_Parse_Lines (const char *program, unsigned int pofs)
{
unsigned int i = 0, lstart;
gib_tree_t *lines = 0, *cur, *tokens, **line = &lines, *embs;
gib_tree_t *lines = 0, *cur, *tokens, **line = &lines, *temp;
char *str;
while (1) {
@ -577,26 +359,26 @@ GIB_Parse_Lines (const char *program, unsigned int pofs)
break;
lstart = i;
// If we parse something useful...
if ((tokens = GIB_Parse_Tokens (program, &i, pofs, &embs))) {
// Link it in
cur = GIB_Tree_New (TREE_T_CMD);
cur->delim = '\n';
str = calloc (i - lstart + 1, sizeof (char));
if ((tokens = GIB_Parse_Tokens (program, &i, pofs))) {
str = calloc (i - lstart + 1, sizeof(char));
memcpy (str, program + lstart, i - lstart);
cur->str = str;
cur->start = lstart + pofs;
cur->end = i + pofs;
cur->children = tokens;
// Line contains embedded commands?
if (embs) {
// Add them to chain before actual line
*line = embs;
for (; embs->next; embs = embs->next);
embs->next = cur;
} else
*line = cur;
// Do preprocessing
line = &(GIB_Parse_Semantic_Preprocess (cur))->next;
// All settings for the line must be passed here
cur = GIB_Semantic_Tokens_To_Lines (
tokens, str, 0,
lstart+pofs,
i+pofs
);
if (gib_parse_error) {
free (str);
goto ERROR;
}
// Find last line
for (temp = cur; temp->next; temp = temp->next);
// Link it to lines we already have
*line = cur;
line = &temp->next;
}
if (gib_parse_error)
goto ERROR;
@ -609,16 +391,16 @@ GIB_Parse_Lines (const char *program, unsigned int pofs)
}
gib_tree_t *
GIB_Parse_Embedded (const char *program, unsigned int pofs, gib_tree_t ** embedded)
GIB_Parse_Embedded (gib_tree_t *token)
{
unsigned int i, n, t;
unsigned int i, n, t, start, end;
char c, d, *str;
gib_tree_t *lines = 0, **line = &lines, *cur, *tokens, *emb, *tmp, **embfirst;
unsigned int start, end;
const char *program = token->str;
gib_tree_t *lines = 0, *cur, *tokens, **metanext, *temp;
gib_parse_error = false;
embfirst = embedded;
*embedded = 0;
metanext = &token->children;
for (i = 0; program[i]; i++) {
if (program[i] == '`' || (program[i] == '$' && program[i + 1] == '(')) {
@ -634,45 +416,56 @@ GIB_Parse_Embedded (const char *program, unsigned int pofs, gib_tree_t ** embedd
goto ERROR;
}
end = i + 1;
// Construct the actual line to be executed
cur = GIB_Tree_New (TREE_T_CMD);
cur->flags |= TREE_L_EMBED;
cur->delim = '`';
str = calloc (i - n + 1, sizeof (char));
memcpy (str, program + n, i - n);
cur->str = str;
cur->start = start + pofs;
cur->end = end + pofs;
// Reset error condition
c = 0;
// Location to begin parsing from
t = 0;
if (!(tokens = GIB_Parse_Tokens (cur->str, &t, start + pofs, &emb))) {
GIB_Tree_Unref (&cur);
// Extract embedded command into a new string
str = calloc (end - start + 1, sizeof(char));
memcpy (str, program + n, i - n);
// Attempt to parse tokens from it
tokens = GIB_Parse_Tokens (str, &t, start + token->start);
if (!tokens) {
free (str);
goto ERROR;
}
cur->children = tokens;
GIB_Parse_Semantic_Preprocess (cur)->next = *embedded;
// All settings for the line must be passed here
cur = GIB_Semantic_Tokens_To_Lines (
tokens, str, TREE_L_EMBED,
start + token->start,
end + token->start
);
if (gib_parse_error) {
GIB_Tree_Unref (&cur);
free (str);
goto ERROR;
}
// Did this have embedded commands of it's own?
if (emb) {
// Link them in first
for (tmp = emb; tmp->next; tmp = tmp->next);
tmp->next = cur;
*embedded = emb;
} else
*embedded = cur;
// Create a representative child node for GIB_Process_Embedded to
// use
// Find last line
for (temp = cur; temp->next; temp = temp->next);
// Link it to lines we already have
// (new lines are added to the start)
temp->next = lines;
lines = cur;
// Create a representative child node for
// GIB_Process_Embedded to use
cur = GIB_Tree_New (TREE_T_META);
cur->delim = '`';
// Save start/end indices
cur->start = start;
cur->end = end;
*line = cur;
line = &cur->next;
// Check for variable substitution
// Link it to end of children list for token we are processing
*metanext = cur;
metanext = &cur->next;
// Check for variable substitution
} else if (program[i] == '$' || program[i] == '#') {
// Extract variable name
start = i;
@ -699,8 +492,8 @@ GIB_Parse_Embedded (const char *program, unsigned int pofs, gib_tree_t ** embedd
// Save start/end indices
cur->start = start;
cur->end = end;
*line = cur;
line = &cur->next;
*metanext = cur;
metanext = &cur->next;
// Don't skip anything important
if (program[n - 1] != '{')
i--;
@ -709,10 +502,8 @@ GIB_Parse_Embedded (const char *program, unsigned int pofs, gib_tree_t ** embedd
return lines;
ERROR:
if (c)
GIB_Parse_Error (va ("Could not find match for '%c'.", c), i + pofs);
GIB_Parse_Error (va ("Could not find match for '%c'.", c), i + token->start);
if (lines)
GIB_Tree_Unref (&lines);
if (*embfirst)
GIB_Tree_Unref (embfirst);
return 0;
}

View file

@ -95,7 +95,7 @@ GIB_Process_Embedded (gib_tree_t * node, cbuf_args_t * args)
Cbuf_ArgsAdd (args, retvals->dstrs[j]->str);
args->argm[args->argc - 1] = node;
}
if (str[prev] || retvals->size) // Still more stuff left?
if (str[prev] && retvals->size) // Still more stuff left?
Cbuf_ArgsAdd (args, "");
} else
dstring_appendstr (args->argv[args->argc - 1],

View file

@ -186,7 +186,7 @@ GIB_Event_Callback (gib_event_t * event, unsigned int argc, ...)
va_end (ap);
GIB_Function_Execute (thread->cbuf, f, args->argv, args->argc);
GIB_Function_Execute_D (thread->cbuf, f, args->argv, args->argc);
GIB_Thread_Add (thread);
Cbuf_ArgsDelete (args);
}

View file

@ -73,7 +73,7 @@ Carne_Execute_Script (const char *path, cbuf_args_t *args)
goto ERROR;
}
GIB_Function_Prepare_Args (mbuf, args->argv, args->argc);
GIB_Function_Prepare_Args_D (mbuf, args->argv, args->argc);
// Main loop
while (1) {