Various cleanups and bugfixes. Added proper line number reporting to

errors.  A few new builtin functions, such as slice::find and thread::list.
This commit is contained in:
Brian Koropoff 2003-02-14 08:06:01 +00:00
parent 2cb4c7836d
commit 3c522a83bc
24 changed files with 456 additions and 217 deletions

View file

@ -55,7 +55,8 @@ typedef struct cbuf_s {
CBUF_STATE_NORMAL = 0, // Normal condition CBUF_STATE_NORMAL = 0, // Normal condition
CBUF_STATE_WAIT, // Buffer is stalled until next frame CBUF_STATE_WAIT, // Buffer is stalled until next frame
CBUF_STATE_ERROR, // An unrecoverable error occured CBUF_STATE_ERROR, // An unrecoverable error occured
CBUF_STATE_STACK // A buffer has been added to the stack CBUF_STATE_STACK, // A buffer has been added to the stack
CBUF_STATE_JUNK // Buffer can be freed or reused
} state; } state;
qboolean strict; // Should we tolerate unknown commands? qboolean strict; // Should we tolerate unknown commands?
@ -67,6 +68,7 @@ typedef struct cbuf_s {
typedef struct cbuf_interpreter_s { typedef struct cbuf_interpreter_s {
void (*construct) (struct cbuf_s *cbuf); void (*construct) (struct cbuf_s *cbuf);
void (*destruct) (struct cbuf_s *cbuf); void (*destruct) (struct cbuf_s *cbuf);
void (*reset) (struct cbuf_s *cbuf);
void (*add) (struct cbuf_s *cbuf, const char *str); void (*add) (struct cbuf_s *cbuf, const char *str);
void (*insert) (struct cbuf_s *cbuf, const char *str); void (*insert) (struct cbuf_s *cbuf, const char *str);
void (*execute) (struct cbuf_s *cbuf); void (*execute) (struct cbuf_s *cbuf);
@ -83,12 +85,12 @@ cbuf_t * Cbuf_New (cbuf_interpreter_t *interp);
void Cbuf_Delete (cbuf_t *cbuf); void Cbuf_Delete (cbuf_t *cbuf);
void Cbuf_DeleteStack (cbuf_t *stack); void Cbuf_DeleteStack (cbuf_t *stack);
void Cbuf_PushStack (cbuf_t *new); void Cbuf_Reset (cbuf_t *cbuf);
cbuf_t *Cbuf_PushStack (cbuf_interpreter_t *interp);
void Cbuf_AddText (cbuf_t *cbuf, const char *text); void Cbuf_AddText (cbuf_t *cbuf, const char *text);
void Cbuf_InsertText (cbuf_t *cbuf, const char *text); void Cbuf_InsertText (cbuf_t *cbuf, const char *text);
void Cbuf_Execute (cbuf_t *cbuf); void Cbuf_Execute (cbuf_t *cbuf);
void Cbuf_Execute_Stack (cbuf_t *cbuf); void Cbuf_Execute_Stack (cbuf_t *cbuf);
void Cbuf_Execute_Sets (cbuf_t *cbuf); void Cbuf_Execute_Sets (cbuf_t *cbuf);
void Cbuf_Error (const char *class, const char *fmt, ...);
#endif//__QF_cbuf_h #endif//__QF_cbuf_h

View file

@ -57,7 +57,7 @@ int Cmd_Argc (void);
const char *Cmd_Argv (int arg); const char *Cmd_Argv (int arg);
const char *Cmd_Args (int start); const char *Cmd_Args (int start);
struct cbuf_args_s; struct cbuf_args_s;
void Cmd_Command (struct cbuf_args_s *args); int Cmd_Command (struct cbuf_args_s *args);
int Cmd_ExecuteString (const char *text, cmd_source_t src); int Cmd_ExecuteString (const char *text, cmd_source_t src);
struct cbuf_s; struct cbuf_s;
void Cmd_StuffCmds (struct cbuf_s *cbuf); void Cmd_StuffCmds (struct cbuf_s *cbuf);

View file

@ -29,6 +29,9 @@
$Id$ $Id$
*/ */
#ifndef __gib_buffer_h
#define __gib_buffer_h
#include "QF/cbuf.h" #include "QF/cbuf.h"
#include "QF/gib_tree.h" #include "QF/gib_tree.h"
#include "QF/dstring.h" #include "QF/dstring.h"
@ -36,7 +39,13 @@
#define GIB_DATA(buffer) ((gib_buffer_data_t *)(buffer->data)) #define GIB_DATA(buffer) ((gib_buffer_data_t *)(buffer->data))
typedef struct gib_script_s {
const char *text, *file;
unsigned int refs;
} gib_script_t;
typedef struct gib_buffer_data_s { typedef struct gib_buffer_data_s {
struct gib_script_s *script;
struct gib_tree_s *program, *ip; struct gib_tree_s *program, *ip;
struct dstring_s *arg_composite; struct dstring_s *arg_composite;
qboolean done, waitret; qboolean done, waitret;
@ -51,13 +60,18 @@ typedef struct gib_buffer_data_s {
struct hashtab_s *globals; // Current domain struct hashtab_s *globals; // Current domain
} gib_buffer_data_t; } gib_buffer_data_t;
void GIB_Buffer_Construct (struct cbuf_s *cbuf); void GIB_Buffer_Construct (struct cbuf_s *cbuf);
void GIB_Buffer_Destruct (struct cbuf_s *cbuf); void GIB_Buffer_Destruct (struct cbuf_s *cbuf);
void GIB_Buffer_Reset (struct cbuf_s *cbuf);
void GIB_Buffer_Set_Program (cbuf_t *cbuf, gib_tree_t *program); void GIB_Buffer_Set_Program (cbuf_t *cbuf, gib_tree_t *program);
void GIB_Buffer_Add (cbuf_t *cbuf, const char *str); void GIB_Buffer_Add (cbuf_t *cbuf, const char *str);
void GIB_Buffer_Insert (cbuf_t *cbuf, const char *str); void GIB_Buffer_Insert (cbuf_t *cbuf, const char *str);
void GIB_Buffer_Push_Sstack (struct cbuf_s *cbuf); void GIB_Buffer_Push_Sstack (struct cbuf_s *cbuf);
void GIB_Buffer_Pop_Sstack (struct cbuf_s *cbuf); void GIB_Buffer_Pop_Sstack (struct cbuf_s *cbuf);
dstring_t *GIB_Buffer_Dsarray_Get (struct cbuf_s *cbuf); dstring_t *GIB_Buffer_Dsarray_Get (struct cbuf_s *cbuf);
void GIB_Buffer_Error (cbuf_t *cbuf, const char *type, const char *fmt, va_list args);
extern struct cbuf_interpreter_s gib_interp; extern struct cbuf_interpreter_s gib_interp;
#endif // __gib_buffer_h

View file

@ -45,10 +45,13 @@ extern char gib_null_string[];
#define GIB_Argd(x) ((x) < cbuf_active->args->argc ? cbuf_active->args->argv[(x)] : NULL) #define GIB_Argd(x) ((x) < cbuf_active->args->argc ? cbuf_active->args->argv[(x)] : NULL)
#define GIB_Argm(x) ((x) < cbuf_active->args->argc ? (gib_tree_t *)cbuf_active->args->argm[(x)] : NULL) #define GIB_Argm(x) ((x) < cbuf_active->args->argc ? (gib_tree_t *)cbuf_active->args->argm[(x)] : NULL)
#define GIB_USAGE(x) (Cbuf_Error ("syntax", "%s: invalid syntax\nusage: %s %s", GIB_Argv(0), GIB_Argv(0), (x))) #define GIB_USAGE(x) (GIB_Error ("syntax", "%s: invalid syntax\nusage: %s %s", GIB_Argv(0), GIB_Argv(0), (x)))
#define GIB_CanReturn() (GIB_DATA(cbuf_active)->waitret)
void GIB_Arg_Strip_Delim (unsigned int arg); void GIB_Arg_Strip_Delim (unsigned int arg);
dstring_t *GIB_Return (const char *str); dstring_t *GIB_Return (const char *str);
void GIB_Error (const char *type, const char *fmt, ...);
void GIB_Builtin_Add (const char *name, void (*func) (void)); void GIB_Builtin_Add (const char *name, void (*func) (void));
gib_builtin_t *GIB_Builtin_Find (const char *name); gib_builtin_t *GIB_Builtin_Find (const char *name);
void GIB_Builtin_Init (qboolean sandbox); void GIB_Builtin_Init (qboolean sandbox);

View file

@ -35,16 +35,18 @@
#include "QF/dstring.h" #include "QF/dstring.h"
#include "QF/hash.h" #include "QF/hash.h"
#include "QF/gib_tree.h" #include "QF/gib_tree.h"
#include "QF/gib_buffer.h"
typedef struct gib_function_s { typedef struct gib_function_s {
const char *name; const char *name;
struct gib_script_s *script;
struct dstring_s *text; struct dstring_s *text;
struct gib_tree_s *program; struct gib_tree_s *program;
struct hashtab_s *globals; struct hashtab_s *globals;
qboolean exported; qboolean exported;
} gib_function_t; } gib_function_t;
void GIB_Function_Define (const char *name, const char *text, gib_tree_t *program, hashtab_t *globals); 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); 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_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_Execute (cbuf_t *cbuf, gib_function_t *func, dstring_t **args, unsigned int argc);

View file

@ -39,7 +39,9 @@ char GIB_Parse_Match_Index (const char *str, unsigned int *i);
char GIB_Parse_Match_Paren (const char *str, unsigned int *i); char GIB_Parse_Match_Paren (const char *str, unsigned int *i);
char GIB_Parse_Match_Var (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 flags); gib_tree_t *GIB_Parse_Lines (const char *program, unsigned int pofs, gib_tree_flags_t flags);
gib_tree_t *GIB_Parse_Embedded (const char *program, unsigned int flags, gib_tree_t **embedded); gib_tree_t *GIB_Parse_Embedded (const char *program, unsigned int pofs, gib_tree_flags_t flags, gib_tree_t **embedded);
extern qboolean gib_parse_error; extern qboolean gib_parse_error;
const char *GIB_Parse_ErrorMsg (void);
unsigned int GIB_Parse_ErrorPos (void);

View file

@ -38,6 +38,7 @@ typedef struct gib_thread_s {
unsigned long int id; unsigned long int id;
struct cbuf_s *cbuf; struct cbuf_s *cbuf;
struct gib_thread_s *prev, *next; struct gib_thread_s *prev, *next;
qboolean trash;
} gib_thread_t; } gib_thread_t;
typedef struct gib_event_s { typedef struct gib_event_s {
@ -55,4 +56,6 @@ int GIB_Event_Register (const char *name, gib_function_t *func);
void GIB_Event_Callback (gib_event_t *event, unsigned int argc, ...); void GIB_Event_Callback (gib_event_t *event, unsigned int argc, ...);
void GIB_Event_Init (void); void GIB_Event_Init (void);
extern gib_thread_t *gib_threads;
#endif #endif

View file

@ -33,23 +33,30 @@
#define __GIB_TREE_H #define __GIB_TREE_H
#define TREE_NORMAL 0 // Normal node #define TREE_NORMAL 0 // Normal node
// Flags for tokens
#define TREE_CONCAT 1 // Concatenate to previous #define TREE_CONCAT 1 // Concatenate to previous
#define TREE_EMBED 2 // Embedded command (expect return value) #define TREE_P_EMBED 2 // Embedded stuff needs to be processed
#define TREE_P_EMBED 4 // Embedded stuff needs to be processed #define TREE_ASPLIT 4 // Token is the name of an array that should be split
#define TREE_ASPLIT 8 // Token is the name of an array that should be split // Flags for lines
#define TREE_FUNC 16 // Node is the first in a function #define TREE_COND 1 // Conditional jump (if or while command)
#define TREE_COND 32 // Conditional jump (if or while command) #define TREE_NOT 2 // Invert condition
#define TREE_NOT 64 #define TREE_END 4 // Node ends a loop or conditional
#define TREE_END 128 // Node ends a loop or conditional #define TREE_FORNEXT 8 // For loop is starting again
#define TREE_FORNEXT 256 // For loop is starting again #define TREE_EMBED 16 // Embedded command (expect return value)
typedef char gib_tree_flags_t;
typedef struct gib_tree_s { typedef struct gib_tree_s {
const char *str; const char *str;
char delim; char delim;
unsigned int start, end, refs;
gib_tree_flags_t flags;
struct gib_tree_s *children, *next, *jump; struct gib_tree_s *children, *next, *jump;
unsigned int flags, start, end, refs;
} gib_tree_t; } gib_tree_t;
gib_tree_t *GIB_Tree_New (unsigned int flags); gib_tree_t *GIB_Tree_New (gib_tree_flags_t flags);
void GIB_Tree_Free_Recursive (gib_tree_t *tree); 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 */ #endif /* __GIB_TREE_H */

View file

@ -345,11 +345,8 @@ static void
C_GIB_Print_Center_f (void) C_GIB_Print_Center_f (void)
{ {
if (GIB_Argc () != 2) { if (GIB_Argc () != 2) {
Cbuf_Error ("syntax", GIB_USAGE ("text");
"print::center: invalid syntax\n" } else
"usage: print::center text");
return;
}
SCR_CenterPrint (GIB_Argv(1)); SCR_CenterPrint (GIB_Argv(1));
} }

View file

@ -37,7 +37,9 @@ static __attribute__ ((unused)) const char rcsid[] =
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdarg.h>
#include "QF/sys.h"
#include "QF/dstring.h" #include "QF/dstring.h"
#include "QF/cbuf.h" #include "QF/cbuf.h"
#include "QF/hash.h" #include "QF/hash.h"
@ -65,9 +67,12 @@ GIB_Buffer_Destruct (struct cbuf_s *cbuf)
dstring_delete (g->arg_composite); dstring_delete (g->arg_composite);
if (g->locals) if (g->locals)
Hash_DelTable (g->locals); Hash_DelTable (g->locals);
if (g->program) { if (g->program)
g->program->refs--; GIB_Tree_Unref (&g->program);
GIB_Tree_Free_Recursive (g->program); if (g->script && !(--g->script->refs)) {
free ((void *)g->script->text);
free ((void *)g->script->file);
free (g->script);
} }
for (i = 0; i < g->stack.size; i++) { for (i = 0; i < g->stack.size; i++) {
for (j = 0; j < g->stack.values[i].realsize; j++) for (j = 0; j < g->stack.values[i].realsize; j++)
@ -80,12 +85,43 @@ GIB_Buffer_Destruct (struct cbuf_s *cbuf)
free (cbuf->data); free (cbuf->data);
} }
void
GIB_Buffer_Reset (struct cbuf_s *cbuf)
{
gib_buffer_data_t *g = GIB_DATA(cbuf);
if (g->locals)
Hash_FlushTable (g->locals);
g->globals = gib_globals;
if (g->program)
GIB_Tree_Unref (&g->program);
if (g->script && !(--g->script->refs)) {
free ((void *) g->script->text);
free ((void *) g->script->file);
free (g->script);
}
g->script = 0;
g->stack.p = 0;
g->waitret = g->done = false;
}
void void
GIB_Buffer_Set_Program (cbuf_t *cbuf, gib_tree_t *program) GIB_Buffer_Set_Program (cbuf_t *cbuf, gib_tree_t *program)
{ {
GIB_DATA(cbuf)->program = program; GIB_DATA(cbuf)->program = program;
} }
static unsigned int
GIB_Buffer_Get_Line_Num (const char *program, unsigned int pos)
{
unsigned int i, line;
for (i = 0, line = 1; i < pos; i++)
if (program[i] == '\n')
line++;
return line;
}
void void
GIB_Buffer_Add (cbuf_t *cbuf, const char *str) GIB_Buffer_Add (cbuf_t *cbuf, const char *str)
{ {
@ -97,9 +133,14 @@ GIB_Buffer_Add (cbuf_t *cbuf, const char *str)
save = &cur->next; save = &cur->next;
} else } else
save = &g->program; save = &g->program;
*save = GIB_Parse_Lines (str, TREE_NORMAL); if (!(*save = GIB_Parse_Lines (str, 0, TREE_NORMAL)))
if (gib_parse_error) Sys_Printf (
Cbuf_Error ("parse", "Parse error in program!"); "-----------------\n"
"|GIB Parse Error|\n"
"-----------------\n"
"Parse error while adding text to GIB buffer.\n"
"Line %u: %s\n", GIB_Buffer_Get_Line_Num (str, GIB_Parse_ErrorPos()), GIB_Parse_ErrorMsg()
);
} }
void void
@ -108,17 +149,21 @@ GIB_Buffer_Insert (cbuf_t *cbuf, const char *str)
gib_buffer_data_t *g = GIB_DATA (cbuf); gib_buffer_data_t *g = GIB_DATA (cbuf);
gib_tree_t *lines, *cur; gib_tree_t *lines, *cur;
if ((lines = GIB_Parse_Lines (str, TREE_NORMAL))) { if ((lines = GIB_Parse_Lines (str, 0, TREE_NORMAL))) {
for (cur = lines; cur; cur = cur->next); for (cur = lines; cur; cur = cur->next);
//if (g->ip) { // This buffer is already running! //if (g->ip) { // This buffer is already running!
if (g->program) GIB_Tree_Unref (&g->program);
g->program->refs--;
cur->next = g->program; cur->next = g->program;
g->program = lines; g->program = lines;
} } else
if (gib_parse_error) Sys_Printf (
Cbuf_Error ("parse", "Parse error in program!"); "-----------------\n"
"|GIB Parse Error|\n"
"-----------------\n"
"Parse error while inserting text into GIB buffer.\n"
"Line %u: %s\n", GIB_Buffer_Get_Line_Num (str, GIB_Parse_ErrorPos()), GIB_Parse_ErrorMsg()
);
} }
void void
@ -153,9 +198,71 @@ GIB_Buffer_Dsarray_Get (struct cbuf_s *cbuf)
return vals->dstrs[vals->size-1]; return vals->dstrs[vals->size-1];
} }
static int
GIB_Buffer_Get_Line_Info (cbuf_t *cbuf, char **line)
{
const char *text;
unsigned int ofs, i, start, linenum;
// Do we have a copy of the original program this buffer comes from?
if (GIB_DATA(cbuf)->script) {
text = GIB_DATA(cbuf)->script->text;
for (ofs = GIB_DATA(cbuf)->ip->start, start = 0, i = 0, linenum = 1; i <= ofs; i++)
if (text[i] == '\n') {
start = i+1;
linenum++;
}
while (text[i] != '\n')
i++;
*line = malloc (i - start + 1);
memcpy (*line, text+start, i - start);
(*line)[i-start] = 0;
return linenum;
} else {
*line = strdup (GIB_DATA(cbuf)->ip->str);
return -1;
}
}
void
GIB_Buffer_Error (cbuf_t *cbuf, const char *type, const char *fmt, va_list args)
{
char *line;
int linenum;
dstring_t *message = dstring_newstr();
dvsprintf (message, fmt, args);
va_end (args);
Sys_Printf ( "---------------------\n"
"|GIB Execution Error|\n"
"---------------------\n"
"Type: %s\n",
type
);
if ((linenum = GIB_Buffer_Get_Line_Info (cbuf, &line)) != -1)
Sys_Printf ( "%s:%i: %s\n"
"-->%s\n",
GIB_DATA(cbuf)->script->file,
linenum,
message->str,
line
);
else
Sys_Printf ( "%s\n"
"-->%s\n",
message->str,
line
);
cbuf->state = CBUF_STATE_ERROR;
dstring_delete (message);
free (line);
}
cbuf_interpreter_t gib_interp = { cbuf_interpreter_t gib_interp = {
GIB_Buffer_Construct, GIB_Buffer_Construct,
GIB_Buffer_Destruct, GIB_Buffer_Destruct,
GIB_Buffer_Reset,
GIB_Buffer_Add, GIB_Buffer_Add,
GIB_Buffer_Insert, GIB_Buffer_Insert,
GIB_Execute, GIB_Execute,

View file

@ -134,6 +134,16 @@ GIB_Return (const char *str)
return 0; return 0;
} }
void
GIB_Error (const char *type, const char *fmt, ...)
{
va_list args;
va_start (args, fmt);
GIB_Buffer_Error (cbuf_active, type, fmt, args);
va_end (args);
}
/* /*
GIB Builtin functions GIB Builtin functions
@ -150,14 +160,14 @@ GIB_Function_f (void)
// Is the function program already tokenized? // Is the function program already tokenized?
if (GIB_Argm (2)->delim != '{') { if (GIB_Argm (2)->delim != '{') {
// Parse on the fly // Parse on the fly
if (!(program = GIB_Parse_Lines (GIB_Argv(2), TREE_NORMAL))) { if (!(program = GIB_Parse_Lines (GIB_Argv(2), 0, TREE_NORMAL))) {
// Error! // Error!
Cbuf_Error ("parse", "Parse error while defining function '%s'.", GIB_Argv(1)); GIB_Error ("parse", "Parse error while defining function '%s'.", GIB_Argv(1));
return; return;
} }
} else } else
program = GIB_Argm (2)->children; program = GIB_Argm (2)->children;
GIB_Function_Define (GIB_Argv(1), GIB_Argv(2), program, GIB_DATA(cbuf_active)->globals); GIB_Function_Define (GIB_Argv(1), GIB_Argv(2), program, GIB_DATA(cbuf_active)->script, GIB_DATA(cbuf_active)->globals);
} }
} }
@ -217,6 +227,15 @@ GIB_Domain_f (void)
GIB_DATA(cbuf_active)->globals = GIB_Domain_Get (GIB_Argv(1)); GIB_DATA(cbuf_active)->globals = GIB_Domain_Get (GIB_Argv(1));
} }
static void
GIB_Domain_Clear_f (void)
{
if (GIB_Argc() != 2)
GIB_USAGE ("domain");
else
Hash_FlushTable (GIB_Domain_Get (GIB_Argv(2)));
}
static void static void
GIB_Return_f (void) GIB_Return_f (void)
{ {
@ -259,7 +278,7 @@ static void
GIB_Break_f (void) GIB_Break_f (void)
{ {
if (!GIB_DATA(cbuf_active)->ip->jump) { if (!GIB_DATA(cbuf_active)->ip->jump) {
Cbuf_Error ("loop", "Break command attempted outside of a loop."); GIB_Error ("loop", "Break command attempted outside of a loop.");
return; return;
} }
if (!GIB_DATA(cbuf_active)->ip->jump->flags & TREE_COND) // In a for loop? if (!GIB_DATA(cbuf_active)->ip->jump->flags & TREE_COND) // In a for loop?
@ -278,7 +297,7 @@ static void
GIB_Continue_f (void) GIB_Continue_f (void)
{ {
if (!GIB_DATA(cbuf_active)->ip->jump) { if (!GIB_DATA(cbuf_active)->ip->jump) {
Cbuf_Error ("loop", "Continue command attempted outside of a loop."); GIB_Error ("loop", "Continue command attempted outside of a loop.");
return; return;
} }
if (GIB_DATA(cbuf_active)->ip->jump->flags & TREE_COND) { if (GIB_DATA(cbuf_active)->ip->jump->flags & TREE_COND) {
@ -319,13 +338,18 @@ GIB_Function_Export_f (void)
GIB_USAGE ("function1 [function2 function3 ...]"); GIB_USAGE ("function1 [function2 function3 ...]");
for (i = 1; i < GIB_Argc(); i++) { for (i = 1; i < GIB_Argc(); i++) {
if (!(f = GIB_Function_Find (GIB_Argv (i)))) if (!(f = GIB_Function_Find (GIB_Argv (i))))
Cbuf_Error ("function", "function::export: function '%s' not found", GIB_Argv (i)); GIB_Error ("function", "%s: function '%s' not found.", GIB_Argv(0), GIB_Argv (i));
else if (!f->exported) { else if (!f->exported) {
if (Cmd_Exists (f->name)) {
GIB_Error ("export", "%s: A console command with the name '%s' already exists.", GIB_Argv(0), GIB_Argv(i));
return;
} else {
Cmd_AddCommand (f->name, GIB_Runexported_f, "Exported GIB function."); Cmd_AddCommand (f->name, GIB_Runexported_f, "Exported GIB function.");
f->exported = true; f->exported = true;
} }
} }
} }
}
static void static void
GIB_Length_f (void) GIB_Length_f (void)
@ -374,24 +398,22 @@ GIB_Slice_f (void)
} }
} }
/*
static void static void
GIB_Find_f (void) GIB_Slice_Find_f (void)
{ {
dstring_t *ret; char *res;
char *haystack, *res;
if (GIB_Argc() != 3) { if (GIB_Argc() != 3) {
GIB_USAGE ("haystack needle"); GIB_USAGE ("haystack needle");
return; return;
} else if (!GIB_CanReturn ())
return;
else if ((res = strstr(GIB_Argv(1), GIB_Argv(2)))) {
dsprintf (GIB_Return (0), "%lu", (unsigned long int)(res - GIB_Argv(1)));
dsprintf (GIB_Return (0), "%lu", (unsigned long int)(res - GIB_Argv(1))+strlen (GIB_Argv(2)));
} }
haystack = GIB_Argv(1);
if ((res = strstr(haystack, GIB_Argv(2)))) {
if ((ret = GIB_Return (0)))
dsprintf (ret, "%lu", (unsigned long int)(res - haystack));
} else
GIB_Return ("-1");
} }
*/
static void static void
GIB_Split_f (void) GIB_Split_f (void)
@ -431,7 +453,7 @@ GIB_Regex_Match_f (void)
} }
if (!(reg = GIB_Regex_Compile (GIB_Argv(2), REG_EXTENDED | GIB_Regex_Translate_Options (GIB_Argv(3))))) if (!(reg = GIB_Regex_Compile (GIB_Argv(2), REG_EXTENDED | GIB_Regex_Translate_Options (GIB_Argv(3)))))
Cbuf_Error ("regex", "%s: %s", GIB_Argv(0), GIB_Regex_Error ()); GIB_Error ("regex", "%s: %s", GIB_Argv(0), GIB_Regex_Error ());
else if (regexec(reg, GIB_Argv(1), 0, 0, 0)) else if (regexec(reg, GIB_Argv(1), 0, 0, 0))
GIB_Return ("0"); GIB_Return ("0");
else else
@ -454,7 +476,7 @@ GIB_Regex_Replace_f (void)
len = strlen (GIB_Argv(4)); len = strlen (GIB_Argv(4));
if (!(reg = GIB_Regex_Compile (GIB_Argv(2), REG_EXTENDED | GIB_Regex_Translate_Options (GIB_Argv(3))))) if (!(reg = GIB_Regex_Compile (GIB_Argv(2), REG_EXTENDED | GIB_Regex_Translate_Options (GIB_Argv(3)))))
Cbuf_Error ("regex", "%s: %s", GIB_Argv(0), GIB_Regex_Error ()); GIB_Error ("regex", "%s: %s", GIB_Argv(0), GIB_Regex_Error ());
else if (strchr(GIB_Argv(3), 'g')) else if (strchr(GIB_Argv(3), 'g'))
while (!regexec(reg, GIB_Argv(1)+ofs, 10, match, ofs > 0 ? REG_NOTBOL : 0) && match[0].rm_eo) while (!regexec(reg, GIB_Argv(1)+ofs, 10, match, ofs > 0 ? REG_NOTBOL : 0) && match[0].rm_eo)
ofs += GIB_Regex_Apply_Match (match, GIB_Argd(1), ofs, GIB_Argv(4)); ofs += GIB_Regex_Apply_Match (match, GIB_Argd(1), ofs, GIB_Argv(4));
@ -468,22 +490,20 @@ GIB_Regex_Extract_f (void)
{ {
regex_t *reg; regex_t *reg;
regmatch_t *match; regmatch_t *match;
dstring_t *ret;
int i; int i;
char o; char o;
if (GIB_Argc() != 4) { if (GIB_Argc() != 4) {
GIB_USAGE ("string regex options"); GIB_USAGE ("string regex options");
return; return;
} } else if (!GIB_CanReturn ())
return;
match = calloc (32, sizeof(regmatch_t)); match = calloc (32, sizeof(regmatch_t));
if (!(reg = GIB_Regex_Compile (GIB_Argv(2), REG_EXTENDED | GIB_Regex_Translate_Options (GIB_Argv(3))))) if (!(reg = GIB_Regex_Compile (GIB_Argv(2), REG_EXTENDED | GIB_Regex_Translate_Options (GIB_Argv(3)))))
Cbuf_Error ("regex", "%s: %s", GIB_Argv(0), GIB_Regex_Error ()); GIB_Error ("regex", "%s: %s", GIB_Argv(0), GIB_Regex_Error ());
else if (!regexec(reg, GIB_Argv(1), 32, match, 0) && match[0].rm_eo) { else if (!regexec(reg, GIB_Argv(1), 32, match, 0) && match[0].rm_eo) {
if (!(ret = GIB_Return(0))) dsprintf (GIB_Return (0), "%lu", (unsigned long) match[0].rm_eo);
return;
dsprintf (ret, "%lu", (unsigned long) match[0].rm_eo);
for (i = 0; i < 32; i++) { for (i = 0; i < 32; i++) {
if (match[i].rm_so != -1) { if (match[i].rm_so != -1) {
o = GIB_Argv(1)[match[i].rm_eo]; o = GIB_Argv(1)[match[i].rm_eo];
@ -492,26 +512,24 @@ GIB_Regex_Extract_f (void)
GIB_Argv(1)[match[i].rm_eo] = o; GIB_Argv(1)[match[i].rm_eo] = o;
} }
} }
} else }
GIB_Return ("-1");
free (match); free (match);
} }
static void static void
GIB_Thread_Create_f (void) GIB_Thread_Create_f (void)
{ {
dstring_t *ret;
gib_function_t *f; gib_function_t *f;
if (GIB_Argc() < 2) if (GIB_Argc() < 2)
GIB_USAGE ("function [arg1 arg2 ...]"); GIB_USAGE ("function [arg1 arg2 ...]");
else if (!(f = GIB_Function_Find (GIB_Argv(1)))) else if (!(f = GIB_Function_Find (GIB_Argv(1))))
Cbuf_Error ("function", "thread::create: no function named '%s' exists.", GIB_Argv(1)); GIB_Error ("function", "%s: no function named '%s' exists.", GIB_Argv(0), GIB_Argv(1));
else { else {
gib_thread_t *thread = GIB_Thread_New (); gib_thread_t *thread = GIB_Thread_New ();
GIB_Function_Execute (thread->cbuf, f, cbuf_active->args->argv+1, cbuf_active->args->argc-1); GIB_Function_Execute (thread->cbuf, f, cbuf_active->args->argv+1, cbuf_active->args->argc-1);
GIB_Thread_Add (thread); GIB_Thread_Add (thread);
if ((ret = GIB_Return (0))) if (GIB_CanReturn ())
dsprintf (ret, "%lu", thread->id); dsprintf (GIB_Return(0), "%lu", thread->id);
} }
} }
@ -522,12 +540,30 @@ GIB_Thread_Kill_f (void)
GIB_USAGE ("id"); GIB_USAGE ("id");
else { else {
gib_thread_t *thread; gib_thread_t *thread;
cbuf_t *cur;
unsigned long int id = strtoul (GIB_Argv(1), 0, 10); unsigned long int id = strtoul (GIB_Argv(1), 0, 10);
thread = GIB_Thread_Find (id); thread = GIB_Thread_Find (id);
if (!thread) { if (!thread) {
Cbuf_Error ("thread", "thread.kill: thread %lu does not exist.", id); GIB_Error ("thread", "%s: thread %lu does not exist.", GIB_Argv(0), id);
return; return;
} }
thread->trash = true;
// Set error condition on the top of the stack so the thread will exit if currently running
for (cur = thread->cbuf; cur->down && cur->down->state != CBUF_STATE_JUNK; cur = cur->down);
cur->state = CBUF_STATE_ERROR;
GIB_DATA(cur)->done = true;
}
}
static void
GIB_Thread_List_f (void)
{
if (GIB_Argc() != 1)
GIB_USAGE ("");
else if (GIB_CanReturn()) {
gib_thread_t *cur;
for (cur = gib_threads; cur; cur = cur->next)
dsprintf (GIB_Return (0), "%lu", cur->id);
} }
} }
@ -538,9 +574,9 @@ GIB_Event_Register_f (void)
if (GIB_Argc() != 3) if (GIB_Argc() != 3)
GIB_USAGE ("event function"); GIB_USAGE ("event function");
else if (!(func = GIB_Function_Find (GIB_Argv(2))) && GIB_Argv(2)[0]) else if (!(func = GIB_Function_Find (GIB_Argv(2))) && GIB_Argv(2)[0])
Cbuf_Error ("function", "Function %s not found.", GIB_Argv(2)); GIB_Error ("function", "Function %s not found.", GIB_Argv(2));
else if (GIB_Event_Register (GIB_Argv(1), func)) else if (GIB_Event_Register (GIB_Argv(1), func))
Cbuf_Error ("event", "Event %s not found.", GIB_Argv(1)); GIB_Error ("event", "Event %s not found.", GIB_Argv(1));
} }
/* File access */ /* File access */
@ -586,13 +622,13 @@ GIB_File_Read_f (void)
return; return;
} }
if (!*GIB_Argv (1)) { if (!*GIB_Argv (1)) {
Cbuf_Error ("file", GIB_Error ("file",
"file::read: null filename provided"); "%s: null filename provided", GIB_Argv(0));
return; return;
} }
if (GIB_File_Transform_Path (GIB_Argd(1))) { if (GIB_File_Transform_Path (GIB_Argd(1))) {
Cbuf_Error ("access", GIB_Error ("access",
"file::read: access to %s denied", GIB_Argv(1)); "%s: access to %s denied", GIB_Argv(0), GIB_Argv(1));
return; return;
} }
if (!(ret = GIB_Return (0))) if (!(ret = GIB_Return (0)))
@ -608,8 +644,8 @@ GIB_File_Read_f (void)
Qclose (file); Qclose (file);
} }
if (!file) { if (!file) {
Cbuf_Error ("file", GIB_Error ("file",
"file::read: could not read %s: %s", path, strerror (errno)); "%s: could not read %s: %s", GIB_Argv(0), path, strerror (errno));
return; return;
} }
} }
@ -625,19 +661,19 @@ GIB_File_Write_f (void)
return; return;
} }
if (!*GIB_Argv(1)) { if (!*GIB_Argv(1)) {
Cbuf_Error ("file", GIB_Error ("file",
"file::write: null filename provided"); "%s: null filename provided", GIB_Argv(0));
return; return;
} }
if (GIB_File_Transform_Path (GIB_Argd(1))) { if (GIB_File_Transform_Path (GIB_Argd(1))) {
Cbuf_Error ("access", GIB_Error ("access",
"file::write: access to %s denied", GIB_Argv(1)); "%s: access to %s denied", GIB_Argv(0), GIB_Argv(1));
return; return;
} }
path = GIB_Argv(1); path = GIB_Argv(1);
if (!(file = Qopen (path, "w"))) { if (!(file = Qopen (path, "w"))) {
Cbuf_Error ("file", GIB_Error ("file",
"file::write: could not open %s for writing: %s", path, strerror (errno)); "%s: could not open %s for writing: %s", GIB_Argv(0), path, strerror (errno));
return; return;
} }
Qprintf (file, "%s", GIB_Argv (2)); Qprintf (file, "%s", GIB_Argv (2));
@ -657,8 +693,8 @@ GIB_File_Find_f (void)
return; return;
} }
if (GIB_File_Transform_Path (GIB_Argd(1))) { if (GIB_File_Transform_Path (GIB_Argd(1))) {
Cbuf_Error ("access", GIB_Error ("access",
"file::find: access to %s denied", GIB_Argv(1)); "%s: access to %s denied", GIB_Argv(0), GIB_Argv(1));
return; return;
} }
path = GIB_Argv(1); path = GIB_Argv(1);
@ -674,8 +710,8 @@ GIB_File_Find_f (void)
} }
directory = opendir (path); directory = opendir (path);
if (!directory) { if (!directory) {
Cbuf_Error ("file", GIB_Error ("file",
"file.find: could not open directory %s: %s", path, strerror (errno)); "%s: could not open directory %s: %s", GIB_Argv(0), path, strerror (errno));
return; return;
} }
while ((entry = readdir (directory))) while ((entry = readdir (directory)))
@ -694,21 +730,19 @@ GIB_File_Move_f (void)
return; return;
} }
if (GIB_File_Transform_Path (GIB_Argd(1))) { if (GIB_File_Transform_Path (GIB_Argd(1))) {
Cbuf_Error ("access", GIB_Error ("access",
"file::move: access to %s denied", GIB_Argv(1)); "%s: access to %s denied", GIB_Argv(0), GIB_Argv(1));
return; return;
} }
if (GIB_File_Transform_Path (GIB_Argd(2))) { if (GIB_File_Transform_Path (GIB_Argd(2))) {
Cbuf_Error ("access", GIB_Error ("access",
"file::move: access to %s denied", GIB_Argv(2)); "%s: access to %s denied", GIB_Argv(0), GIB_Argv(2));
return; return;
} }
path1 = GIB_Argv(1); path1 = GIB_Argv(1);
path2 = GIB_Argv(2); path2 = GIB_Argv(2);
if (Qrename (path1, path2)) if (Qrename (path1, path2))
Cbuf_Error ("file", GIB_Error ("file", "%s: could not move %s to %s: %s", GIB_Argv(0), path1, path2, strerror(errno));
"file::move: could not move %s to %s: %s",
path1, path2, strerror(errno));
} }
static void static void
@ -721,15 +755,13 @@ GIB_File_Delete_f (void)
return; return;
} }
if (GIB_File_Transform_Path (GIB_Argd(1))) { if (GIB_File_Transform_Path (GIB_Argd(1))) {
Cbuf_Error ("access", GIB_Error ("access",
"file::delete: access to %s denied", GIB_Argv(1)); "%s: access to %s denied", GIB_Argv(0), GIB_Argv(1));
return; return;
} }
path = GIB_Argv (1); path = GIB_Argv (1);
if (Qremove(path)) if (Qremove(path))
Cbuf_Error ("file", GIB_Error ("file", "%s: could not delete %s: %s", GIB_Argv(0), path, strerror(errno));
"file::delete: could not delete %s: %s",
path, strerror(errno));
} }
static void static void
@ -790,6 +822,7 @@ GIB_Builtin_Init (qboolean sandbox)
GIB_Builtin_Add ("local", GIB_Local_f); GIB_Builtin_Add ("local", GIB_Local_f);
GIB_Builtin_Add ("global", GIB_Global_f); GIB_Builtin_Add ("global", GIB_Global_f);
GIB_Builtin_Add ("domain", GIB_Domain_f); GIB_Builtin_Add ("domain", GIB_Domain_f);
GIB_Builtin_Add ("domain::clear", GIB_Domain_Clear_f);
GIB_Builtin_Add ("return", GIB_Return_f); GIB_Builtin_Add ("return", GIB_Return_f);
GIB_Builtin_Add ("for", GIB_For_f); GIB_Builtin_Add ("for", GIB_For_f);
GIB_Builtin_Add ("break", GIB_Break_f); GIB_Builtin_Add ("break", GIB_Break_f);
@ -797,12 +830,14 @@ GIB_Builtin_Init (qboolean sandbox)
GIB_Builtin_Add ("length", GIB_Length_f); GIB_Builtin_Add ("length", GIB_Length_f);
GIB_Builtin_Add ("equal", GIB_Equal_f); GIB_Builtin_Add ("equal", GIB_Equal_f);
GIB_Builtin_Add ("slice", GIB_Slice_f); GIB_Builtin_Add ("slice", GIB_Slice_f);
GIB_Builtin_Add ("slice::find", GIB_Slice_Find_f);
GIB_Builtin_Add ("split", GIB_Split_f); GIB_Builtin_Add ("split", GIB_Split_f);
GIB_Builtin_Add ("regex::match", GIB_Regex_Match_f); GIB_Builtin_Add ("regex::match", GIB_Regex_Match_f);
GIB_Builtin_Add ("regex::replace", GIB_Regex_Replace_f); GIB_Builtin_Add ("regex::replace", GIB_Regex_Replace_f);
GIB_Builtin_Add ("regex::extract", GIB_Regex_Extract_f); GIB_Builtin_Add ("regex::extract", GIB_Regex_Extract_f);
GIB_Builtin_Add ("thread::create", GIB_Thread_Create_f); GIB_Builtin_Add ("thread::create", GIB_Thread_Create_f);
GIB_Builtin_Add ("thread::kill", GIB_Thread_Kill_f); GIB_Builtin_Add ("thread::kill", GIB_Thread_Kill_f);
GIB_Builtin_Add ("thread::list", GIB_Thread_List_f);
GIB_Builtin_Add ("event::register", GIB_Event_Register_f); GIB_Builtin_Add ("event::register", GIB_Event_Register_f);
GIB_Builtin_Add ("file::read", GIB_File_Read_f); GIB_Builtin_Add ("file::read", GIB_File_Read_f);
GIB_Builtin_Add ("file::write", GIB_File_Write_f); GIB_Builtin_Add ("file::write", GIB_File_Write_f);

View file

@ -207,14 +207,12 @@ GIB_Execute (cbuf_t *cbuf)
else if ((b = GIB_Builtin_Find (cbuf->args->argv[0]->str))) { else if ((b = GIB_Builtin_Find (cbuf->args->argv[0]->str))) {
b->func (); b->func ();
} else if ((f = GIB_Function_Find (cbuf->args->argv[0]->str))) { } else if ((f = GIB_Function_Find (cbuf->args->argv[0]->str))) {
cbuf_t *new = Cbuf_New (&gib_interp); cbuf_t *new = Cbuf_PushStack (&gib_interp);
cbuf->down = new;
new->up = cbuf;
cbuf->state = CBUF_STATE_STACK;
GIB_Function_Execute (new, f, cbuf->args->argv, cbuf->args->argc); GIB_Function_Execute (new, f, cbuf->args->argv, cbuf->args->argc);
} else { } else {
GIB_Execute_Generate_Composite (cbuf); GIB_Execute_Generate_Composite (cbuf);
Cmd_Command (cbuf->args); if (Cmd_Command (cbuf->args))
GIB_Error ("command", "No builtin, function, or console command named '%s' was found.", cbuf->args->argv[0]->str);
} }
} }
if (!(g->ip = g->ip->next)) // No more commands if (!(g->ip = g->ip->next)) // No more commands
@ -222,8 +220,4 @@ GIB_Execute (cbuf_t *cbuf)
if (cbuf->state) // Let the stack walker figure out what to do if (cbuf->state) // Let the stack walker figure out what to do
return; return;
} }
g->done = false;
g->program->refs--;
GIB_Tree_Free_Recursive (g->program);
g->program = g->ip = 0;
} }

View file

@ -74,6 +74,7 @@ GIB_Function_Get_Key (void *ele, void *ptr)
{ {
return ((gib_function_t *)ele)->name; return ((gib_function_t *)ele)->name;
} }
static void static void
GIB_Function_Free (void *ele, void *ptr) GIB_Function_Free (void *ele, void *ptr)
{ {
@ -82,6 +83,11 @@ GIB_Function_Free (void *ele, void *ptr)
free ((void *)func->name); free ((void *)func->name);
if (func->program) if (func->program)
GIB_Tree_Free_Recursive (func->program); GIB_Tree_Free_Recursive (func->program);
if (func->script && !(--func->script->refs)) {
free ((void *)func->script->text);
free ((void *)func->script->file);
free (func->script);
}
free (func); free (func);
} }
@ -93,20 +99,25 @@ GIB_Function_Free (void *ele, void *ptr)
hash if needed. hash if needed.
*/ */
void void
GIB_Function_Define (const char *name, const char *text, gib_tree_t *program, hashtab_t *globals) GIB_Function_Define (const char *name, const char *text, gib_tree_t *program, gib_script_t *script, hashtab_t *globals)
{ {
gib_function_t *func; gib_function_t *func;
program->refs++; GIB_Tree_Ref (&program);
if (script)
script->refs++;
if (!gib_functions) if (!gib_functions)
gib_functions = Hash_NewTable (1024, GIB_Function_Get_Key, GIB_Function_Free, 0); gib_functions = Hash_NewTable (1024, GIB_Function_Get_Key, GIB_Function_Free, 0);
func = Hash_Find(gib_functions, name); func = Hash_Find(gib_functions, name);
if (func) { if (func) {
dstring_clearstr (func->text); dstring_clearstr (func->text);
func->program->refs--; GIB_Tree_Unref (&func->program);
GIB_Tree_Free_Recursive (func->program); if (func->script && !(--func->script->refs)) {
free ((void *)func->script->text);
free ((void *)func->script->file);
free (func->script);
}
} else { } else {
func = GIB_Function_New (name); func = GIB_Function_New (name);
Hash_Add (gib_functions, func); Hash_Add (gib_functions, func);
@ -114,6 +125,7 @@ GIB_Function_Define (const char *name, const char *text, gib_tree_t *program, ha
dstring_appendstr (func->text, text); dstring_appendstr (func->text, text);
func->program = program; func->program = program;
func->globals = globals; func->globals = globals;
func->script = script;
} }
/* /*
@ -162,8 +174,11 @@ GIB_Function_Prepare_Args (cbuf_t *cbuf, dstring_t **args, unsigned int argc)
void void
GIB_Function_Execute (cbuf_t *cbuf, gib_function_t *func, dstring_t **args, unsigned int argc) GIB_Function_Execute (cbuf_t *cbuf, gib_function_t *func, dstring_t **args, unsigned int argc)
{ {
func->program->refs++; GIB_Tree_Ref (&func->program);
if (func->script)
func->script->refs++;
GIB_Buffer_Set_Program (cbuf, func->program); GIB_Buffer_Set_Program (cbuf, func->program);
GIB_DATA(cbuf)->script = func->script;
GIB_DATA(cbuf)->globals = func->globals; GIB_DATA(cbuf)->globals = func->globals;
GIB_Function_Prepare_Args (cbuf, args, argc); GIB_Function_Prepare_Args (cbuf, args, argc);
} }

View file

@ -36,6 +36,8 @@ static __attribute__ ((unused)) const char rcsid[] =
"$Id$"; "$Id$";
#include <string.h> #include <string.h>
#include <stdlib.h>
#include "QF/qtypes.h" #include "QF/qtypes.h"
#include "QF/cbuf.h" #include "QF/cbuf.h"
#include "QF/quakefs.h" #include "QF/quakefs.h"
@ -71,14 +73,14 @@ GIB_Exec_Override_f (void) {
Sys_Printf ("execing %s\n", Cmd_Argv (1)); Sys_Printf ("execing %s\n", Cmd_Argv (1));
if (!strcmp (Cmd_Argv (1) + strlen (Cmd_Argv(1)) - 4, ".gib") || cbuf_active->interpreter == &gib_interp) { if (!strcmp (Cmd_Argv (1) + strlen (Cmd_Argv(1)) - 4, ".gib") || cbuf_active->interpreter == &gib_interp) {
// GIB script, put it in a new buffer on the stack // GIB script, put it in a new buffer on the stack
cbuf_t *sub = Cbuf_New (&gib_interp); cbuf_t *sub = Cbuf_PushStack (&gib_interp);
if (cbuf_active->down) GIB_DATA(sub)->script = malloc (sizeof (gib_script_t));
Cbuf_DeleteStack (cbuf_active->down); GIB_DATA(sub)->script->file = strdup (Cmd_Argv(1));
cbuf_active->down = sub; GIB_DATA(sub)->script->text = strdup (f);
sub->up = cbuf_active; GIB_DATA(sub)->script->refs = 1;
cbuf_active->state = CBUF_STATE_STACK;
Cbuf_AddText (sub, f); Cbuf_AddText (sub, f);
//GIB_Parse_Strip_Comments (sub); if (gib_parse_error && cbuf_active->interpreter == &gib_interp)
GIB_Error ("parse", "%s: Parse error while executing %s.", Cmd_Argv(0), Cmd_Argv(1));
} else } else
Cbuf_InsertText (cbuf_active, f); Cbuf_InsertText (cbuf_active, f);
Hunk_FreeToLowMark (mark); Hunk_FreeToLowMark (mark);

View file

@ -186,14 +186,36 @@ GIB_Parse_Match_Var (const char *str, unsigned int *i)
} }
qboolean gib_parse_error; qboolean gib_parse_error;
unsigned int gib_parse_error_pos;
const char *gib_parse_error_msg;
static void
GIB_Parse_Error (const char *msg, unsigned int pos)
{
gib_parse_error = true;
gib_parse_error_msg = msg;
gib_parse_error_pos = pos;
}
const char *
GIB_Parse_ErrorMsg (void)
{
return gib_parse_error_msg;
}
unsigned int
GIB_Parse_ErrorPos (void)
{
return gib_parse_error_pos;
}
// FIXME: Concatenation in stupid circumstances should generate errors // FIXME: Concatenation in stupid circumstances should generate errors
static gib_tree_t * static gib_tree_t *
GIB_Parse_Tokens (const char *program, unsigned int *i, unsigned int flags, gib_tree_t **embedded) GIB_Parse_Tokens (const char *program, unsigned int *i, unsigned int pofs, gib_tree_flags_t flags, gib_tree_t **embedded)
{ {
char c, delim, *str; char c, delim, *str;
unsigned int tstart; unsigned int tstart, start;
gib_tree_t *nodes = 0, *cur, *new, *embs = 0, *tmp; gib_tree_t *nodes = 0, *cur, *new, *embs = 0, *tmp;
gib_tree_t **node = &nodes; gib_tree_t **node = &nodes;
qboolean cat = false; qboolean cat = false;
@ -214,7 +236,8 @@ GIB_Parse_Tokens (const char *program, unsigned int *i, unsigned int flags, gib_
if (!program[*i] || program[*i] == '\n' || program[*i] == ';') if (!program[*i] || program[*i] == '\n' || program[*i] == ';')
break; break;
// Save our start position // Save our start position
tstart = *i + 1; start = *i;
tstart = start + 1;
delim = program[*i]; delim = program[*i];
switch (delim) { switch (delim) {
case '{': case '{':
@ -250,8 +273,10 @@ GIB_Parse_Tokens (const char *program, unsigned int *i, unsigned int flags, gib_
} }
} }
} }
c = 0;
cur = *node = GIB_Tree_New (flags); cur = *node = GIB_Tree_New (flags);
cur->start = start + pofs;
cur->end = *i + pofs;
cur->delim = delim; cur->delim = delim;
str = calloc (*i - tstart + 1, sizeof(char)); str = calloc (*i - tstart + 1, sizeof(char));
memcpy (str, program+tstart, *i - tstart); memcpy (str, program+tstart, *i - tstart);
@ -260,12 +285,12 @@ GIB_Parse_Tokens (const char *program, unsigned int *i, unsigned int flags, gib_
// string would differ from the parsed program. // string would differ from the parsed program.
if (cur->delim == '{' && !cat) { if (cur->delim == '{' && !cat) {
// Try to parse sub-program // Try to parse sub-program
if (!(new = GIB_Parse_Lines (str, flags))) if (!(new = GIB_Parse_Lines (str, tstart+pofs, flags)))
goto ERROR; goto ERROR;
cur->children = new; cur->children = new;
// Check for embedded commands/variables // Check for embedded commands/variables
} else if (cur->delim == ' ' || cur->delim == '(') { } else if (cur->delim == ' ' || cur->delim == '(') {
if (!(cur->children = GIB_Parse_Embedded (str, flags, &new))) { if (!(cur->children = GIB_Parse_Embedded (str, tstart+pofs, flags, &new))) {
// There could be no embedded elements, so check for a real error // There could be no embedded elements, so check for a real error
if (gib_parse_error) if (gib_parse_error)
goto ERROR; goto ERROR;
@ -305,9 +330,10 @@ DONE:
*embedded = embs; *embedded = embs;
return nodes; return nodes;
ERROR: ERROR:
if (c)
GIB_Parse_Error (va("Could not find match for '%c'.", c), *i+pofs);
if (nodes) if (nodes)
GIB_Tree_Free_Recursive (nodes); GIB_Tree_Free_Recursive (nodes);
gib_parse_error = true;
return 0; return 0;
} }
@ -318,8 +344,14 @@ GIB_Parse_Semantic_Preprocess (gib_tree_t *line)
unsigned int flags = line->flags; unsigned int flags = line->flags;
while (!strcmp (line->children->str, "if") || !strcmp (line->children->str, "ifnot")) { while (!strcmp (line->children->str, "if") || !strcmp (line->children->str, "ifnot")) {
// Sanity checking // Sanity checking
if (!line->children->next || !line->children->next->next || !line->children->next->next->children || line->flags & TREE_EMBED) { if (!line->children->next || !line->children->next->next) {
gib_parse_error = true; 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_EMBED) {
GIB_Parse_Error ("'if' statements may not be used in embedded commands.", line->start);
return line; return line;
} }
// Set conditional flag // Set conditional flag
@ -342,7 +374,7 @@ GIB_Parse_Semantic_Preprocess (gib_tree_t *line)
if (p->children->next->next->next && !strcmp (p->children->next->next->next->str, "else")) { if (p->children->next->next->next && !strcmp (p->children->next->next->next->str, "else")) {
// Sanity checking // Sanity checking
if (!p->children->next->next->next->next) { if (!p->children->next->next->next->next) {
gib_parse_error = true; GIB_Parse_Error ("'if' statement contains 'else' but no secondary program block or command.", line->start);
return line; return line;
} }
// Is "else" followed by a subprogram? // Is "else" followed by a subprogram?
@ -372,12 +404,14 @@ GIB_Parse_Semantic_Preprocess (gib_tree_t *line)
// If we have a while loop, handle that // If we have a while loop, handle that
if (!strcmp (line->children->str, "while")) { if (!strcmp (line->children->str, "while")) {
// Sanity checks // Sanity checks
if (!line->children->next || if (!line->children->next || !line->children->next->next) {
!line->children->next->next || GIB_Parse_Error ("Not enough arguments to 'while' statement.", line->start);
line->children->next->next->delim != '{' || return line;
!line->children->next->next->children || } else if (!line->children->next->next->children || line->children->next->next->delim != '{') {
line->flags & TREE_EMBED) { GIB_Parse_Error ("Program block in 'while' statement not enclosed in braces or invalid.", line->start);
gib_parse_error = true; return line;
} else if (line->flags & TREE_EMBED) {
GIB_Parse_Error ("'while' statements may not be used in embedded commands.", line->start);
return line; return line;
} }
// Set conditional flag // Set conditional flag
@ -400,19 +434,20 @@ GIB_Parse_Semantic_Preprocess (gib_tree_t *line)
gib_tree_t *tmp; gib_tree_t *tmp;
// Sanity checks // 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) { 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 = true; GIB_Parse_Error ("Malformed 'for' statement.", line->start);
return line; return line;
} }
// Find last token in line (contains program block) // Find last token in line (contains program block)
for (tmp = line->children->next->next->next->next; tmp->next; tmp = tmp->next); for (tmp = line->children->next->next->next->next; tmp->next; tmp = tmp->next);
// More sanity // More sanity
if (tmp->delim != '{' || !tmp->children) { if (tmp->delim != '{' || !tmp->children) {
gib_parse_error = true; GIB_Parse_Error ("Program block in 'for' statement not enclosed in braces or invalid.", line->start);
return line; return line;
} }
p = line; p = line;
// Move subprogram inline // Move subprogram inline
line->next = tmp->children; line->next = tmp->children;
tmp->children = 0;
// Find end of subprogram, set jump point back to top of loop as we go // Find end of subprogram, set jump point back to top of loop as we go
for (; line->next; line = line->next) for (; line->next; line = line->next)
if (!line->jump) if (!line->jump)
@ -427,7 +462,7 @@ GIB_Parse_Semantic_Preprocess (gib_tree_t *line)
} }
gib_tree_t * gib_tree_t *
GIB_Parse_Lines (const char *program, unsigned int flags) GIB_Parse_Lines (const char *program, unsigned int pofs, gib_tree_flags_t flags)
{ {
unsigned int i = 0, lstart; unsigned int i = 0, lstart;
gib_tree_t *lines = 0, *cur, *tokens, **line = &lines, *embs; gib_tree_t *lines = 0, *cur, *tokens, **line = &lines, *embs;
@ -440,13 +475,15 @@ GIB_Parse_Lines (const char *program, unsigned int flags)
break; break;
lstart = i; lstart = i;
// If we parse something useful... // If we parse something useful...
if ((tokens = GIB_Parse_Tokens (program, &i, flags, &embs))) { if ((tokens = GIB_Parse_Tokens (program, &i, pofs, flags, &embs))) {
// Link it in // Link it in
cur = GIB_Tree_New (flags); cur = GIB_Tree_New (flags);
cur->delim = '\n'; cur->delim = '\n';
str = calloc (i - lstart + 1, sizeof(char)); str = calloc (i - lstart + 1, sizeof(char));
memcpy (str, program+lstart, i - lstart); memcpy (str, program+lstart, i - lstart);
cur->str = str; cur->str = str;
cur->start = lstart + pofs;
cur->end = i + pofs;
cur->children = tokens; cur->children = tokens;
// Line contains embedded commands? // Line contains embedded commands?
if (embs) { if (embs) {
@ -470,7 +507,7 @@ ERROR:
} }
gib_tree_t * gib_tree_t *
GIB_Parse_Embedded (const char *program, unsigned int flags, gib_tree_t **embedded) GIB_Parse_Embedded (const char *program, unsigned int pofs, gib_tree_flags_t flags, gib_tree_t **embedded)
{ {
unsigned int i, n, t; unsigned int i, n, t;
char c, d, *str; char c, d, *str;
@ -500,12 +537,12 @@ GIB_Parse_Embedded (const char *program, unsigned int flags, gib_tree_t **embedd
str = calloc (i - n + 1, sizeof (char)); str = calloc (i - n + 1, sizeof (char));
memcpy (str, program+n, i - n); memcpy (str, program+n, i - n);
cur->str = str; cur->str = str;
cur->start = start + pofs;
t = 0; cur->end = end + pofs;
if (!(tokens = GIB_Parse_Tokens (cur->str, &t, flags, &emb))) {
c = 0; c = 0;
t = 0;
if (!(tokens = GIB_Parse_Tokens (cur->str, &t, start + pofs, flags, &emb)))
goto ERROR; goto ERROR;
}
cur->children = tokens; cur->children = tokens;
GIB_Parse_Semantic_Preprocess (cur)->next = *embedded; GIB_Parse_Semantic_Preprocess (cur)->next = *embedded;
if (gib_parse_error) if (gib_parse_error)
@ -561,7 +598,8 @@ GIB_Parse_Embedded (const char *program, unsigned int flags, gib_tree_t **embedd
} }
return lines; return lines;
ERROR: ERROR:
gib_parse_error = true; if (c)
GIB_Parse_Error (va ("Could not find match for '%c'.", c), i + pofs);
if (lines) if (lines)
GIB_Tree_Free_Recursive (lines); GIB_Tree_Free_Recursive (lines);
return 0; return 0;

View file

@ -47,6 +47,7 @@ static __attribute__ ((unused)) const char rcsid[] =
#include "QF/gib_parse.h" #include "QF/gib_parse.h"
#include "QF/gib_vars.h" #include "QF/gib_vars.h"
#include "QF/gib_process.h" #include "QF/gib_process.h"
#include "QF/gib_builtin.h"
#include "exp.h" #include "exp.h"
@ -63,7 +64,7 @@ GIB_Process_Variable (dstring_t *token, unsigned int *i)
(*i)++; (*i)++;
if (token->str[*i] == '{') { if (token->str[*i] == '{') {
if ((c = GIB_Parse_Match_Brace (token->str, i))) { if ((c = GIB_Parse_Match_Brace (token->str, i))) {
Cbuf_Error ("Parse", "Could not find match for %c.", c); GIB_Error ("Parse", "Could not find match for %c.", c);
return -1; return -1;
} }
n += 2; n += 2;
@ -71,9 +72,10 @@ GIB_Process_Variable (dstring_t *token, unsigned int *i)
} else { } else {
for (; isalnum((byte) token->str[*i]) || token->str[*i] == '_'; (*i)++); for (; isalnum((byte) token->str[*i]) || token->str[*i] == '_'; (*i)++);
if (token->str[*i] == '[') { if (token->str[*i] == '[') {
if ((c = GIB_Parse_Match_Index (token->str, i))) if ((c = GIB_Parse_Match_Index (token->str, i))) {
GIB_Error ("Parse", "Could not find match for %c.", c);
return -1; return -1;
else } else
(*i)++; (*i)++;
} }
n++; n++;
@ -119,7 +121,7 @@ GIB_Process_Math (struct dstring_s *token, unsigned int i)
value = EXP_Evaluate (token->str+i); value = EXP_Evaluate (token->str+i);
if (EXP_ERROR) { if (EXP_ERROR) {
Cbuf_Error ("math", "Expression \"%s\" caused an error:\n%s", token->str, EXP_GetErrorMsg()); GIB_Error ("math", "Expression \"%s\" caused an error:\n%s", token->str, EXP_GetErrorMsg());
return -1; return -1;
} else { } else {
token->str[i] = 0; token->str[i] = 0;

View file

@ -115,12 +115,11 @@ GIB_Thread_Execute (void)
for (cur = gib_threads; cur; cur = tmp) { for (cur = gib_threads; cur; cur = tmp) {
tmp = cur->next; tmp = cur->next;
if (GIB_DATA(cur->cbuf)->program) if (cur->trash) {
Cbuf_Execute_Stack (cur->cbuf);
else {
GIB_Thread_Remove (cur); GIB_Thread_Remove (cur);
GIB_Thread_Delete (cur); GIB_Thread_Delete (cur);
} } else
Cbuf_Execute_Stack (cur->cbuf);
} }
} }

View file

@ -38,11 +38,12 @@ static __attribute__ ((unused)) const char rcsid[] =
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "QF/sys.h"
#include "QF/qtypes.h" #include "QF/qtypes.h"
#include "QF/gib_tree.h" #include "QF/gib_tree.h"
gib_tree_t * gib_tree_t *
GIB_Tree_New (unsigned int flags) GIB_Tree_New (gib_tree_flags_t flags)
{ {
gib_tree_t *new = calloc (1, sizeof (gib_tree_t)); gib_tree_t *new = calloc (1, sizeof (gib_tree_t));
new->flags = flags; new->flags = flags;
@ -60,13 +61,30 @@ GIB_Tree_Free_Recursive (gib_tree_t *tree)
return; return;
for (; tree; tree = n) { for (; tree; tree = n) {
n = tree->next; n = tree->next;
if (tree->children) { if (tree->children)
// Parent is about to bite the dust, meaning one less reference // Parent is about to bite the dust, meaning one less reference
tree->children->refs--; GIB_Tree_Unref (&tree->children);
GIB_Tree_Free_Recursive (tree->children);
}
if (tree->str) if (tree->str)
free((void *) tree->str); free((void *) tree->str);
free(tree); free(tree);
} }
} }
void
GIB_Tree_Ref (gib_tree_t **tp)
{
(*tp)->refs++;
Sys_DPrintf ("Ref: %p %u\n", *tp, (*tp)->refs);
}
void
GIB_Tree_Unref (gib_tree_t **tp)
{
Sys_DPrintf ("Unref: %p %u\n", *tp, (*tp)->refs-1);
if (!(--(*tp)->refs)) {
GIB_Tree_Free_Recursive (*tp);
*tp = 0;
}
}

View file

@ -127,13 +127,28 @@ Cbuf_DeleteStack (cbuf_t *stack)
} }
void void
Cbuf_PushStack (cbuf_t *new) Cbuf_Reset (cbuf_t *cbuf)
{ {
if (cbuf_active->down) cbuf->resumetime = 0.0;
Cbuf_DeleteStack (cbuf_active->down); cbuf->args->argc = 0;
if (cbuf->interpreter->reset)
cbuf->interpreter->reset (cbuf);
}
cbuf_t *
Cbuf_PushStack (cbuf_interpreter_t *interp)
{
cbuf_t *new;
if (cbuf_active->down) {
new = cbuf_active->down;
Cbuf_Reset (new);
new->state = CBUF_STATE_NORMAL;
} else
new = Cbuf_New (interp);
cbuf_active->down = new; cbuf_active->down = new;
new->up = cbuf_active; new->up = cbuf_active;
cbuf_active->state = CBUF_STATE_STACK; cbuf_active->state = CBUF_STATE_STACK;
return new;
} }
void void
@ -167,33 +182,27 @@ Cbuf_Execute_Stack (cbuf_t *cbuf)
else else
return; return;
} }
for (sp = cbuf; sp->down; sp = sp->down); for (sp = cbuf; sp->down && sp->down->state != CBUF_STATE_JUNK; sp = sp->down);
while (sp) { while (sp) {
if (sp->down) {
Cbuf_Delete (sp->down);
sp->down = 0;
}
Cbuf_Execute (sp); Cbuf_Execute (sp);
if (sp->state) { if (sp->state) {
if (sp->state == CBUF_STATE_STACK) { if (sp->state == CBUF_STATE_STACK) {
sp = sp->down; sp = sp->down;
continue; continue;
} else if (sp->state == CBUF_STATE_ERROR) } else if (sp->state == CBUF_STATE_ERROR)
goto ERROR; break;
else else
return; return;
} }
sp->state = CBUF_STATE_JUNK;
sp = sp->up; sp = sp->up;
} }
return;
ERROR:
if (cbuf->down) { if (cbuf->down) {
Cbuf_DeleteStack (cbuf->down); Cbuf_DeleteStack (cbuf->down);
cbuf->down = 0; cbuf->down = 0;
} }
// Tear it down and build it back up Cbuf_Reset (cbuf);
cbuf->interpreter->destruct (cbuf);
cbuf->interpreter->construct (cbuf);
} }
void void
@ -202,24 +211,3 @@ Cbuf_Execute_Sets (cbuf_t *cbuf)
cbuf->interpreter->execute_sets (cbuf); cbuf->interpreter->execute_sets (cbuf);
} }
void
Cbuf_Error (const char *class, const char *fmt, ...)
{
dstring_t *message = dstring_newstr();
va_list args;
va_start (args, fmt);
dvsprintf (message, fmt, args);
va_end (args);
Sys_Printf (
"-----------------------------------\n"
"|Error in command buffer execution|\n"
"-----------------------------------\n"
"Type: %s\n\n"
"%s\n\n",
class,
message->str
);
cbuf_active->state = CBUF_STATE_ERROR;
dstring_delete (message);
}

View file

@ -106,7 +106,7 @@ Cmd_Args (int start)
return cmd_args->args[start]; return cmd_args->args[start];
} }
void int
Cmd_Command (cbuf_args_t *args) Cmd_Command (cbuf_args_t *args)
{ {
cmd_function_t *cmd; cmd_function_t *cmd;
@ -115,7 +115,7 @@ Cmd_Command (cbuf_args_t *args)
//cmd_source = src; //cmd_source = src;
if (!args->argc) if (!args->argc)
return; // no tokens return 0; // no tokens
// check functions // check functions
cmd = (cmd_function_t *) Hash_Find (cmd_hash, args->argv[0]->str); cmd = (cmd_function_t *) Hash_Find (cmd_hash, args->argv[0]->str);
@ -123,16 +123,16 @@ Cmd_Command (cbuf_args_t *args)
if (cmd->function) { if (cmd->function) {
cmd->function (); cmd->function ();
} }
return; return 0;
} }
// check cvars // check cvars
if (Cvar_Command ()) if (Cvar_Command ())
return; return 0;
if (cbuf_active->strict) if (cbuf_active->strict)
Cbuf_Error ("command", "Command '%s' not found.", args->argv[0]->str); return -1;
else if (cmd_warncmd->int_val || developer->int_val) else if (cmd_warncmd->int_val || developer->int_val)
Sys_Printf ("Unknown command \"%s\"\n", Cmd_Argv (0)); Sys_Printf ("Unknown command \"%s\"\n", Cmd_Argv (0));
return 0;
} }
/* Registers a command and handler function */ /* Registers a command and handler function */

View file

@ -68,6 +68,13 @@ COM_destruct (cbuf_t *cbuf)
free(cbuf->data); free(cbuf->data);
} }
static void
COM_reset (cbuf_t *cbuf)
{
dstring_clearstr (DATA(cbuf)->buf);
dstring_clearstr (DATA(cbuf)->line);
}
static void static void
COM_add (cbuf_t *cbuf, const char *str) COM_add (cbuf_t *cbuf, const char *str)
{ {
@ -232,6 +239,7 @@ COM_execute_sets (cbuf_t *cbuf)
cbuf_interpreter_t id_interp = { cbuf_interpreter_t id_interp = {
COM_construct, COM_construct,
COM_destruct, COM_destruct,
COM_reset,
COM_add, COM_add,
COM_insert, COM_insert,
COM_execute, COM_execute,

View file

@ -681,10 +681,7 @@ Key_GIB_Bind_Get_f (void)
int t, k; int t, k;
if (GIB_Argc() != 2) { if (GIB_Argc() != 2) {
Cbuf_Error ("syntax", GIB_USAGE ("key");
"bind::get: invalid syntax\n"
"usage: bind::get key"
);
return; return;
} }
@ -693,12 +690,12 @@ Key_GIB_Bind_Get_f (void)
key = OK_TranslateKeyName (GIB_Argv (1)); key = OK_TranslateKeyName (GIB_Argv (1));
if ((t = Key_StringToIMTnum (imt)) == -1) { if ((t = Key_StringToIMTnum (imt)) == -1) {
Cbuf_Error ("bind", "bind::get: invalid imt %s", imt); GIB_Error ("bind", "bind::get: invalid imt %s", imt);
return; return;
} }
if ((k = Key_StringToKeynum (key)) == -1) { if ((k = Key_StringToKeynum (key)) == -1) {
Cbuf_Error ("bind", "bind::get: invalid key %s", key); GIB_Error ("bind", "bind::get: invalid key %s", key);
return; return;
} }

View file

@ -409,9 +409,7 @@ Locs_Loc_Get (void)
location_t *location; location_t *location;
if (GIB_Argc() != 1) if (GIB_Argc() != 1)
Cbuf_Error ("syntax", GIB_USAGE ("");
"loc::get: invalid syntax\n"
"usage: loc::get");
else { else {
location = locs_find (cl.simorg); location = locs_find (cl.simorg);
GIB_Return (location ? location->name : "unknown"); GIB_Return (location ? location->name : "unknown");

View file

@ -55,6 +55,10 @@ Carne_Execute_Script (const char *path, cbuf_args_t *args)
if (f[0] == '#') if (f[0] == '#')
for (; f[i] != '\n' && f[i+1]; i++); for (; f[i] != '\n' && f[i+1]; i++);
Cbuf_AddText (mbuf, f+i); Cbuf_AddText (mbuf, f+i);
GIB_DATA(mbuf)->script = malloc (sizeof (gib_script_t));
GIB_DATA(mbuf)->script->file = strdup (path);
GIB_DATA(mbuf)->script->text = strdup (f);
GIB_DATA(mbuf)->script->refs = 1;
free (f); free (f);
} }
Qclose (file); Qclose (file);
@ -63,7 +67,10 @@ Carne_Execute_Script (const char *path, cbuf_args_t *args)
return 1; return 1;
} }
//GIB_Parse_Strip_Comments (mbuf); if (gib_parse_error)
return 1;
GIB_Function_Prepare_Args (mbuf, args->argv, args->argc); GIB_Function_Prepare_Args (mbuf, args->argv, args->argc);
@ -90,6 +97,7 @@ Carne_Execute_Stdin (void)
while (fgets(linebuf, sizeof(linebuf)-1, stdin)) { while (fgets(linebuf, sizeof(linebuf)-1, stdin)) {
GIB_Thread_Execute (); GIB_Thread_Execute ();
Cbuf_AddText (cbuf, linebuf); Cbuf_AddText (cbuf, linebuf);
if (!gib_parse_error)
Cbuf_Execute_Stack (cbuf); Cbuf_Execute_Stack (cbuf);
if (carne_done) if (carne_done)
break; break;