mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-26 06:10:56 +00:00
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:
parent
2cb4c7836d
commit
3c522a83bc
24 changed files with 456 additions and 217 deletions
|
@ -55,7 +55,8 @@ typedef struct cbuf_s {
|
|||
CBUF_STATE_NORMAL = 0, // Normal condition
|
||||
CBUF_STATE_WAIT, // Buffer is stalled until next frame
|
||||
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;
|
||||
|
||||
qboolean strict; // Should we tolerate unknown commands?
|
||||
|
@ -67,6 +68,7 @@ typedef struct cbuf_s {
|
|||
typedef struct cbuf_interpreter_s {
|
||||
void (*construct) (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 (*insert) (struct cbuf_s *cbuf, const char *str);
|
||||
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_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_InsertText (cbuf_t *cbuf, const char *text);
|
||||
void Cbuf_Execute (cbuf_t *cbuf);
|
||||
void Cbuf_Execute_Stack (cbuf_t *cbuf);
|
||||
void Cbuf_Execute_Sets (cbuf_t *cbuf);
|
||||
void Cbuf_Error (const char *class, const char *fmt, ...);
|
||||
|
||||
#endif//__QF_cbuf_h
|
||||
|
|
|
@ -57,7 +57,7 @@ int Cmd_Argc (void);
|
|||
const char *Cmd_Argv (int arg);
|
||||
const char *Cmd_Args (int start);
|
||||
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);
|
||||
struct cbuf_s;
|
||||
void Cmd_StuffCmds (struct cbuf_s *cbuf);
|
||||
|
|
|
@ -29,6 +29,9 @@
|
|||
$Id$
|
||||
*/
|
||||
|
||||
#ifndef __gib_buffer_h
|
||||
#define __gib_buffer_h
|
||||
|
||||
#include "QF/cbuf.h"
|
||||
#include "QF/gib_tree.h"
|
||||
#include "QF/dstring.h"
|
||||
|
@ -36,7 +39,13 @@
|
|||
#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 {
|
||||
struct gib_script_s *script;
|
||||
struct gib_tree_s *program, *ip;
|
||||
struct dstring_s *arg_composite;
|
||||
qboolean done, waitret;
|
||||
|
@ -51,13 +60,18 @@ typedef struct gib_buffer_data_s {
|
|||
struct hashtab_s *globals; // Current domain
|
||||
} gib_buffer_data_t;
|
||||
|
||||
|
||||
void GIB_Buffer_Construct (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_Add (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_Pop_Sstack (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;
|
||||
|
||||
#endif // __gib_buffer_h
|
||||
|
|
|
@ -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_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);
|
||||
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));
|
||||
gib_builtin_t *GIB_Builtin_Find (const char *name);
|
||||
void GIB_Builtin_Init (qboolean sandbox);
|
||||
|
|
|
@ -35,16 +35,18 @@
|
|||
#include "QF/dstring.h"
|
||||
#include "QF/hash.h"
|
||||
#include "QF/gib_tree.h"
|
||||
#include "QF/gib_buffer.h"
|
||||
|
||||
typedef struct gib_function_s {
|
||||
const char *name;
|
||||
struct gib_script_s *script;
|
||||
struct dstring_s *text;
|
||||
struct gib_tree_s *program;
|
||||
struct hashtab_s *globals;
|
||||
qboolean exported;
|
||||
} 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);
|
||||
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);
|
||||
|
|
|
@ -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_Var (const char *str, unsigned int *i);
|
||||
|
||||
gib_tree_t *GIB_Parse_Lines (const char *program, unsigned int flags);
|
||||
gib_tree_t *GIB_Parse_Embedded (const char *program, unsigned int flags, gib_tree_t **embedded);
|
||||
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 pofs, gib_tree_flags_t flags, gib_tree_t **embedded);
|
||||
|
||||
extern qboolean gib_parse_error;
|
||||
const char *GIB_Parse_ErrorMsg (void);
|
||||
unsigned int GIB_Parse_ErrorPos (void);
|
||||
|
|
|
@ -38,6 +38,7 @@ typedef struct gib_thread_s {
|
|||
unsigned long int id;
|
||||
struct cbuf_s *cbuf;
|
||||
struct gib_thread_s *prev, *next;
|
||||
qboolean trash;
|
||||
} gib_thread_t;
|
||||
|
||||
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_Init (void);
|
||||
|
||||
extern gib_thread_t *gib_threads;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -33,23 +33,30 @@
|
|||
#define __GIB_TREE_H
|
||||
|
||||
#define TREE_NORMAL 0 // Normal node
|
||||
// Flags for tokens
|
||||
#define TREE_CONCAT 1 // Concatenate to previous
|
||||
#define TREE_EMBED 2 // Embedded command (expect return value)
|
||||
#define TREE_P_EMBED 4 // Embedded stuff needs to be processed
|
||||
#define TREE_ASPLIT 8 // Token is the name of an array that should be split
|
||||
#define TREE_FUNC 16 // Node is the first in a function
|
||||
#define TREE_COND 32 // Conditional jump (if or while command)
|
||||
#define TREE_NOT 64
|
||||
#define TREE_END 128 // Node ends a loop or conditional
|
||||
#define TREE_FORNEXT 256 // For loop is starting again
|
||||
#define TREE_P_EMBED 2 // Embedded stuff needs to be processed
|
||||
#define TREE_ASPLIT 4 // Token is the name of an array that should be split
|
||||
// Flags for lines
|
||||
#define TREE_COND 1 // Conditional jump (if or while command)
|
||||
#define TREE_NOT 2 // Invert condition
|
||||
#define TREE_END 4 // Node ends a loop or conditional
|
||||
#define TREE_FORNEXT 8 // 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 {
|
||||
const char *str;
|
||||
char delim;
|
||||
unsigned int start, end, refs;
|
||||
gib_tree_flags_t flags;
|
||||
struct gib_tree_s *children, *next, *jump;
|
||||
unsigned int flags, start, end, refs;
|
||||
} 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_Ref (gib_tree_t **tp);
|
||||
void GIB_Tree_Unref (gib_tree_t **tp);
|
||||
|
||||
#endif /* __GIB_TREE_H */
|
||||
|
|
|
@ -345,12 +345,9 @@ static void
|
|||
C_GIB_Print_Center_f (void)
|
||||
{
|
||||
if (GIB_Argc () != 2) {
|
||||
Cbuf_Error ("syntax",
|
||||
"print::center: invalid syntax\n"
|
||||
"usage: print::center text");
|
||||
return;
|
||||
}
|
||||
SCR_CenterPrint (GIB_Argv(1));
|
||||
GIB_USAGE ("text");
|
||||
} else
|
||||
SCR_CenterPrint (GIB_Argv(1));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -37,7 +37,9 @@ static __attribute__ ((unused)) const char rcsid[] =
|
|||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "QF/sys.h"
|
||||
#include "QF/dstring.h"
|
||||
#include "QF/cbuf.h"
|
||||
#include "QF/hash.h"
|
||||
|
@ -65,9 +67,12 @@ GIB_Buffer_Destruct (struct cbuf_s *cbuf)
|
|||
dstring_delete (g->arg_composite);
|
||||
if (g->locals)
|
||||
Hash_DelTable (g->locals);
|
||||
if (g->program) {
|
||||
g->program->refs--;
|
||||
GIB_Tree_Free_Recursive (g->program);
|
||||
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);
|
||||
}
|
||||
for (i = 0; i < g->stack.size; i++) {
|
||||
for (j = 0; j < g->stack.values[i].realsize; j++)
|
||||
|
@ -80,12 +85,43 @@ GIB_Buffer_Destruct (struct cbuf_s *cbuf)
|
|||
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
|
||||
GIB_Buffer_Set_Program (cbuf_t *cbuf, gib_tree_t *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
|
||||
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;
|
||||
} else
|
||||
save = &g->program;
|
||||
*save = GIB_Parse_Lines (str, TREE_NORMAL);
|
||||
if (gib_parse_error)
|
||||
Cbuf_Error ("parse", "Parse error in program!");
|
||||
if (!(*save = GIB_Parse_Lines (str, 0, TREE_NORMAL)))
|
||||
Sys_Printf (
|
||||
"-----------------\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
|
||||
|
@ -108,17 +149,21 @@ GIB_Buffer_Insert (cbuf_t *cbuf, const char *str)
|
|||
gib_buffer_data_t *g = GIB_DATA (cbuf);
|
||||
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);
|
||||
//if (g->ip) { // This buffer is already running!
|
||||
|
||||
if (g->program)
|
||||
g->program->refs--;
|
||||
GIB_Tree_Unref (&g->program);
|
||||
cur->next = g->program;
|
||||
g->program = lines;
|
||||
}
|
||||
if (gib_parse_error)
|
||||
Cbuf_Error ("parse", "Parse error in program!");
|
||||
} else
|
||||
Sys_Printf (
|
||||
"-----------------\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
|
||||
|
@ -153,9 +198,71 @@ GIB_Buffer_Dsarray_Get (struct cbuf_s *cbuf)
|
|||
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 = {
|
||||
GIB_Buffer_Construct,
|
||||
GIB_Buffer_Destruct,
|
||||
GIB_Buffer_Reset,
|
||||
GIB_Buffer_Add,
|
||||
GIB_Buffer_Insert,
|
||||
GIB_Execute,
|
||||
|
|
|
@ -134,6 +134,16 @@ GIB_Return (const char *str)
|
|||
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
|
||||
|
||||
|
@ -150,14 +160,14 @@ GIB_Function_f (void)
|
|||
// Is the function program already tokenized?
|
||||
if (GIB_Argm (2)->delim != '{') {
|
||||
// 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!
|
||||
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;
|
||||
}
|
||||
} else
|
||||
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));
|
||||
}
|
||||
|
||||
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
|
||||
GIB_Return_f (void)
|
||||
{
|
||||
|
@ -259,7 +278,7 @@ static void
|
|||
GIB_Break_f (void)
|
||||
{
|
||||
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;
|
||||
}
|
||||
if (!GIB_DATA(cbuf_active)->ip->jump->flags & TREE_COND) // In a for loop?
|
||||
|
@ -278,7 +297,7 @@ static void
|
|||
GIB_Continue_f (void)
|
||||
{
|
||||
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;
|
||||
}
|
||||
if (GIB_DATA(cbuf_active)->ip->jump->flags & TREE_COND) {
|
||||
|
@ -319,10 +338,15 @@ GIB_Function_Export_f (void)
|
|||
GIB_USAGE ("function1 [function2 function3 ...]");
|
||||
for (i = 1; i < GIB_Argc(); 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) {
|
||||
Cmd_AddCommand (f->name, GIB_Runexported_f, "Exported GIB function.");
|
||||
f->exported = true;
|
||||
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.");
|
||||
f->exported = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -374,24 +398,22 @@ GIB_Slice_f (void)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
static void
|
||||
GIB_Find_f (void)
|
||||
GIB_Slice_Find_f (void)
|
||||
{
|
||||
dstring_t *ret;
|
||||
char *haystack, *res;
|
||||
char *res;
|
||||
if (GIB_Argc() != 3) {
|
||||
GIB_USAGE ("haystack needle");
|
||||
return;
|
||||
}
|
||||
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");
|
||||
} 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)));
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
static 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)))))
|
||||
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))
|
||||
GIB_Return ("0");
|
||||
else
|
||||
|
@ -454,7 +476,7 @@ GIB_Regex_Replace_f (void)
|
|||
len = strlen (GIB_Argv(4));
|
||||
|
||||
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'))
|
||||
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));
|
||||
|
@ -468,22 +490,20 @@ GIB_Regex_Extract_f (void)
|
|||
{
|
||||
regex_t *reg;
|
||||
regmatch_t *match;
|
||||
dstring_t *ret;
|
||||
int i;
|
||||
char o;
|
||||
|
||||
if (GIB_Argc() != 4) {
|
||||
GIB_USAGE ("string regex options");
|
||||
return;
|
||||
}
|
||||
} else if (!GIB_CanReturn ())
|
||||
return;
|
||||
match = calloc (32, sizeof(regmatch_t));
|
||||
|
||||
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) {
|
||||
if (!(ret = GIB_Return(0)))
|
||||
return;
|
||||
dsprintf (ret, "%lu", (unsigned long) match[0].rm_eo);
|
||||
dsprintf (GIB_Return (0), "%lu", (unsigned long) match[0].rm_eo);
|
||||
for (i = 0; i < 32; i++) {
|
||||
if (match[i].rm_so != -1) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
} else
|
||||
GIB_Return ("-1");
|
||||
}
|
||||
free (match);
|
||||
}
|
||||
|
||||
static void
|
||||
GIB_Thread_Create_f (void)
|
||||
{
|
||||
dstring_t *ret;
|
||||
gib_function_t *f;
|
||||
if (GIB_Argc() < 2)
|
||||
GIB_USAGE ("function [arg1 arg2 ...]");
|
||||
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 {
|
||||
gib_thread_t *thread = GIB_Thread_New ();
|
||||
GIB_Function_Execute (thread->cbuf, f, cbuf_active->args->argv+1, cbuf_active->args->argc-1);
|
||||
GIB_Thread_Add (thread);
|
||||
if ((ret = GIB_Return (0)))
|
||||
dsprintf (ret, "%lu", thread->id);
|
||||
if (GIB_CanReturn ())
|
||||
dsprintf (GIB_Return(0), "%lu", thread->id);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -522,12 +540,30 @@ GIB_Thread_Kill_f (void)
|
|||
GIB_USAGE ("id");
|
||||
else {
|
||||
gib_thread_t *thread;
|
||||
cbuf_t *cur;
|
||||
unsigned long int id = strtoul (GIB_Argv(1), 0, 10);
|
||||
thread = GIB_Thread_Find (id);
|
||||
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;
|
||||
}
|
||||
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)
|
||||
GIB_USAGE ("event function");
|
||||
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))
|
||||
Cbuf_Error ("event", "Event %s not found.", GIB_Argv(1));
|
||||
GIB_Error ("event", "Event %s not found.", GIB_Argv(1));
|
||||
}
|
||||
|
||||
/* File access */
|
||||
|
@ -586,13 +622,13 @@ GIB_File_Read_f (void)
|
|||
return;
|
||||
}
|
||||
if (!*GIB_Argv (1)) {
|
||||
Cbuf_Error ("file",
|
||||
"file::read: null filename provided");
|
||||
GIB_Error ("file",
|
||||
"%s: null filename provided", GIB_Argv(0));
|
||||
return;
|
||||
}
|
||||
if (GIB_File_Transform_Path (GIB_Argd(1))) {
|
||||
Cbuf_Error ("access",
|
||||
"file::read: access to %s denied", GIB_Argv(1));
|
||||
GIB_Error ("access",
|
||||
"%s: access to %s denied", GIB_Argv(0), GIB_Argv(1));
|
||||
return;
|
||||
}
|
||||
if (!(ret = GIB_Return (0)))
|
||||
|
@ -608,8 +644,8 @@ GIB_File_Read_f (void)
|
|||
Qclose (file);
|
||||
}
|
||||
if (!file) {
|
||||
Cbuf_Error ("file",
|
||||
"file::read: could not read %s: %s", path, strerror (errno));
|
||||
GIB_Error ("file",
|
||||
"%s: could not read %s: %s", GIB_Argv(0), path, strerror (errno));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -625,19 +661,19 @@ GIB_File_Write_f (void)
|
|||
return;
|
||||
}
|
||||
if (!*GIB_Argv(1)) {
|
||||
Cbuf_Error ("file",
|
||||
"file::write: null filename provided");
|
||||
GIB_Error ("file",
|
||||
"%s: null filename provided", GIB_Argv(0));
|
||||
return;
|
||||
}
|
||||
if (GIB_File_Transform_Path (GIB_Argd(1))) {
|
||||
Cbuf_Error ("access",
|
||||
"file::write: access to %s denied", GIB_Argv(1));
|
||||
GIB_Error ("access",
|
||||
"%s: access to %s denied", GIB_Argv(0), GIB_Argv(1));
|
||||
return;
|
||||
}
|
||||
path = GIB_Argv(1);
|
||||
if (!(file = Qopen (path, "w"))) {
|
||||
Cbuf_Error ("file",
|
||||
"file::write: could not open %s for writing: %s", path, strerror (errno));
|
||||
GIB_Error ("file",
|
||||
"%s: could not open %s for writing: %s", GIB_Argv(0), path, strerror (errno));
|
||||
return;
|
||||
}
|
||||
Qprintf (file, "%s", GIB_Argv (2));
|
||||
|
@ -657,8 +693,8 @@ GIB_File_Find_f (void)
|
|||
return;
|
||||
}
|
||||
if (GIB_File_Transform_Path (GIB_Argd(1))) {
|
||||
Cbuf_Error ("access",
|
||||
"file::find: access to %s denied", GIB_Argv(1));
|
||||
GIB_Error ("access",
|
||||
"%s: access to %s denied", GIB_Argv(0), GIB_Argv(1));
|
||||
return;
|
||||
}
|
||||
path = GIB_Argv(1);
|
||||
|
@ -674,8 +710,8 @@ GIB_File_Find_f (void)
|
|||
}
|
||||
directory = opendir (path);
|
||||
if (!directory) {
|
||||
Cbuf_Error ("file",
|
||||
"file.find: could not open directory %s: %s", path, strerror (errno));
|
||||
GIB_Error ("file",
|
||||
"%s: could not open directory %s: %s", GIB_Argv(0), path, strerror (errno));
|
||||
return;
|
||||
}
|
||||
while ((entry = readdir (directory)))
|
||||
|
@ -694,21 +730,19 @@ GIB_File_Move_f (void)
|
|||
return;
|
||||
}
|
||||
if (GIB_File_Transform_Path (GIB_Argd(1))) {
|
||||
Cbuf_Error ("access",
|
||||
"file::move: access to %s denied", GIB_Argv(1));
|
||||
GIB_Error ("access",
|
||||
"%s: access to %s denied", GIB_Argv(0), GIB_Argv(1));
|
||||
return;
|
||||
}
|
||||
if (GIB_File_Transform_Path (GIB_Argd(2))) {
|
||||
Cbuf_Error ("access",
|
||||
"file::move: access to %s denied", GIB_Argv(2));
|
||||
GIB_Error ("access",
|
||||
"%s: access to %s denied", GIB_Argv(0), GIB_Argv(2));
|
||||
return;
|
||||
}
|
||||
path1 = GIB_Argv(1);
|
||||
path2 = GIB_Argv(2);
|
||||
if (Qrename (path1, path2))
|
||||
Cbuf_Error ("file",
|
||||
"file::move: could not move %s to %s: %s",
|
||||
path1, path2, strerror(errno));
|
||||
GIB_Error ("file", "%s: could not move %s to %s: %s", GIB_Argv(0), path1, path2, strerror(errno));
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -721,15 +755,13 @@ GIB_File_Delete_f (void)
|
|||
return;
|
||||
}
|
||||
if (GIB_File_Transform_Path (GIB_Argd(1))) {
|
||||
Cbuf_Error ("access",
|
||||
"file::delete: access to %s denied", GIB_Argv(1));
|
||||
GIB_Error ("access",
|
||||
"%s: access to %s denied", GIB_Argv(0), GIB_Argv(1));
|
||||
return;
|
||||
}
|
||||
path = GIB_Argv (1);
|
||||
if (Qremove(path))
|
||||
Cbuf_Error ("file",
|
||||
"file::delete: could not delete %s: %s",
|
||||
path, strerror(errno));
|
||||
GIB_Error ("file", "%s: could not delete %s: %s", GIB_Argv(0), path, strerror(errno));
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -790,6 +822,7 @@ GIB_Builtin_Init (qboolean sandbox)
|
|||
GIB_Builtin_Add ("local", GIB_Local_f);
|
||||
GIB_Builtin_Add ("global", GIB_Global_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 ("for", GIB_For_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 ("equal", GIB_Equal_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 ("regex::match", GIB_Regex_Match_f);
|
||||
GIB_Builtin_Add ("regex::replace", GIB_Regex_Replace_f);
|
||||
GIB_Builtin_Add ("regex::extract", GIB_Regex_Extract_f);
|
||||
GIB_Builtin_Add ("thread::create", GIB_Thread_Create_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 ("file::read", GIB_File_Read_f);
|
||||
GIB_Builtin_Add ("file::write", GIB_File_Write_f);
|
||||
|
|
|
@ -207,23 +207,17 @@ GIB_Execute (cbuf_t *cbuf)
|
|||
else if ((b = GIB_Builtin_Find (cbuf->args->argv[0]->str))) {
|
||||
b->func ();
|
||||
} else if ((f = GIB_Function_Find (cbuf->args->argv[0]->str))) {
|
||||
cbuf_t *new = Cbuf_New (&gib_interp);
|
||||
cbuf->down = new;
|
||||
new->up = cbuf;
|
||||
cbuf->state = CBUF_STATE_STACK;
|
||||
cbuf_t *new = Cbuf_PushStack (&gib_interp);
|
||||
GIB_Function_Execute (new, f, cbuf->args->argv, cbuf->args->argc);
|
||||
} else {
|
||||
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
|
||||
g->done = true;
|
||||
g->done = true;
|
||||
if (cbuf->state) // Let the stack walker figure out what to do
|
||||
return;
|
||||
}
|
||||
g->done = false;
|
||||
g->program->refs--;
|
||||
GIB_Tree_Free_Recursive (g->program);
|
||||
g->program = g->ip = 0;
|
||||
}
|
||||
|
|
|
@ -74,6 +74,7 @@ GIB_Function_Get_Key (void *ele, void *ptr)
|
|||
{
|
||||
return ((gib_function_t *)ele)->name;
|
||||
}
|
||||
|
||||
static void
|
||||
GIB_Function_Free (void *ele, void *ptr)
|
||||
{
|
||||
|
@ -82,6 +83,11 @@ GIB_Function_Free (void *ele, void *ptr)
|
|||
free ((void *)func->name);
|
||||
if (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);
|
||||
}
|
||||
|
||||
|
@ -93,20 +99,25 @@ GIB_Function_Free (void *ele, void *ptr)
|
|||
hash if needed.
|
||||
*/
|
||||
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;
|
||||
|
||||
program->refs++;
|
||||
|
||||
GIB_Tree_Ref (&program);
|
||||
if (script)
|
||||
script->refs++;
|
||||
if (!gib_functions)
|
||||
gib_functions = Hash_NewTable (1024, GIB_Function_Get_Key, GIB_Function_Free, 0);
|
||||
|
||||
func = Hash_Find(gib_functions, name);
|
||||
if (func) {
|
||||
dstring_clearstr (func->text);
|
||||
func->program->refs--;
|
||||
GIB_Tree_Free_Recursive (func->program);
|
||||
GIB_Tree_Unref (&func->program);
|
||||
if (func->script && !(--func->script->refs)) {
|
||||
free ((void *)func->script->text);
|
||||
free ((void *)func->script->file);
|
||||
free (func->script);
|
||||
}
|
||||
} else {
|
||||
func = GIB_Function_New (name);
|
||||
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);
|
||||
func->program = program;
|
||||
func->globals = globals;
|
||||
func->script = script;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -162,8 +174,11 @@ 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)
|
||||
{
|
||||
func->program->refs++;
|
||||
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 (cbuf, args, argc);
|
||||
}
|
||||
|
|
|
@ -36,6 +36,8 @@ static __attribute__ ((unused)) const char rcsid[] =
|
|||
"$Id$";
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "QF/qtypes.h"
|
||||
#include "QF/cbuf.h"
|
||||
#include "QF/quakefs.h"
|
||||
|
@ -71,14 +73,14 @@ GIB_Exec_Override_f (void) {
|
|||
Sys_Printf ("execing %s\n", Cmd_Argv (1));
|
||||
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
|
||||
cbuf_t *sub = Cbuf_New (&gib_interp);
|
||||
if (cbuf_active->down)
|
||||
Cbuf_DeleteStack (cbuf_active->down);
|
||||
cbuf_active->down = sub;
|
||||
sub->up = cbuf_active;
|
||||
cbuf_active->state = CBUF_STATE_STACK;
|
||||
cbuf_t *sub = Cbuf_PushStack (&gib_interp);
|
||||
GIB_DATA(sub)->script = malloc (sizeof (gib_script_t));
|
||||
GIB_DATA(sub)->script->file = strdup (Cmd_Argv(1));
|
||||
GIB_DATA(sub)->script->text = strdup (f);
|
||||
GIB_DATA(sub)->script->refs = 1;
|
||||
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
|
||||
Cbuf_InsertText (cbuf_active, f);
|
||||
Hunk_FreeToLowMark (mark);
|
||||
|
|
|
@ -186,14 +186,36 @@ GIB_Parse_Match_Var (const char *str, unsigned int *i)
|
|||
}
|
||||
|
||||
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
|
||||
|
||||
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;
|
||||
unsigned int tstart;
|
||||
unsigned int tstart, start;
|
||||
gib_tree_t *nodes = 0, *cur, *new, *embs = 0, *tmp;
|
||||
gib_tree_t **node = &nodes;
|
||||
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] == ';')
|
||||
break;
|
||||
// Save our start position
|
||||
tstart = *i + 1;
|
||||
start = *i;
|
||||
tstart = start + 1;
|
||||
delim = program[*i];
|
||||
switch (delim) {
|
||||
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->start = start + pofs;
|
||||
cur->end = *i + pofs;
|
||||
cur->delim = delim;
|
||||
str = calloc (*i - tstart + 1, sizeof(char));
|
||||
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.
|
||||
if (cur->delim == '{' && !cat) {
|
||||
// Try to parse sub-program
|
||||
if (!(new = GIB_Parse_Lines (str, flags)))
|
||||
if (!(new = GIB_Parse_Lines (str, tstart+pofs, flags)))
|
||||
goto ERROR;
|
||||
cur->children = new;
|
||||
// Check for embedded commands/variables
|
||||
} 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
|
||||
if (gib_parse_error)
|
||||
goto ERROR;
|
||||
|
@ -305,9 +330,10 @@ 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_Free_Recursive (nodes);
|
||||
gib_parse_error = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -318,8 +344,14 @@ GIB_Parse_Semantic_Preprocess (gib_tree_t *line)
|
|||
unsigned int flags = line->flags;
|
||||
while (!strcmp (line->children->str, "if") || !strcmp (line->children->str, "ifnot")) {
|
||||
// Sanity checking
|
||||
if (!line->children->next || !line->children->next->next || !line->children->next->next->children || line->flags & TREE_EMBED) {
|
||||
gib_parse_error = true;
|
||||
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_EMBED) {
|
||||
GIB_Parse_Error ("'if' statements may not be used in embedded commands.", line->start);
|
||||
return line;
|
||||
}
|
||||
// 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")) {
|
||||
// Sanity checking
|
||||
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;
|
||||
}
|
||||
// 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 (!strcmp (line->children->str, "while")) {
|
||||
// Sanity checks
|
||||
if (!line->children->next ||
|
||||
!line->children->next->next ||
|
||||
line->children->next->next->delim != '{' ||
|
||||
!line->children->next->next->children ||
|
||||
line->flags & TREE_EMBED) {
|
||||
gib_parse_error = true;
|
||||
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_EMBED) {
|
||||
GIB_Parse_Error ("'while' statements may not be used in embedded commands.", line->start);
|
||||
return line;
|
||||
}
|
||||
// Set conditional flag
|
||||
|
@ -400,19 +434,20 @@ GIB_Parse_Semantic_Preprocess (gib_tree_t *line)
|
|||
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 = true;
|
||||
GIB_Parse_Error ("Malformed 'for' statement.", 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 = true;
|
||||
GIB_Parse_Error ("Program block in 'for' statement not enclosed in braces or invalid.", line->start);
|
||||
return line;
|
||||
}
|
||||
p = line;
|
||||
// Move subprogram inline
|
||||
line->next = tmp->children;
|
||||
tmp->children = 0;
|
||||
// Find end of subprogram, set jump point back to top of loop as we go
|
||||
for (; line->next; line = line->next)
|
||||
if (!line->jump)
|
||||
|
@ -427,7 +462,7 @@ GIB_Parse_Semantic_Preprocess (gib_tree_t *line)
|
|||
}
|
||||
|
||||
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;
|
||||
gib_tree_t *lines = 0, *cur, *tokens, **line = &lines, *embs;
|
||||
|
@ -440,13 +475,15 @@ GIB_Parse_Lines (const char *program, unsigned int flags)
|
|||
break;
|
||||
lstart = i;
|
||||
// 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
|
||||
cur = GIB_Tree_New (flags);
|
||||
cur->delim = '\n';
|
||||
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) {
|
||||
|
@ -470,7 +507,7 @@ ERROR:
|
|||
}
|
||||
|
||||
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;
|
||||
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));
|
||||
memcpy (str, program+n, i - n);
|
||||
cur->str = str;
|
||||
|
||||
cur->start = start + pofs;
|
||||
cur->end = end + pofs;
|
||||
c = 0;
|
||||
t = 0;
|
||||
if (!(tokens = GIB_Parse_Tokens (cur->str, &t, flags, &emb))) {
|
||||
c = 0;
|
||||
if (!(tokens = GIB_Parse_Tokens (cur->str, &t, start + pofs, flags, &emb)))
|
||||
goto ERROR;
|
||||
}
|
||||
cur->children = tokens;
|
||||
GIB_Parse_Semantic_Preprocess (cur)->next = *embedded;
|
||||
if (gib_parse_error)
|
||||
|
@ -561,7 +598,8 @@ GIB_Parse_Embedded (const char *program, unsigned int flags, gib_tree_t **embedd
|
|||
}
|
||||
return lines;
|
||||
ERROR:
|
||||
gib_parse_error = true;
|
||||
if (c)
|
||||
GIB_Parse_Error (va ("Could not find match for '%c'.", c), i + pofs);
|
||||
if (lines)
|
||||
GIB_Tree_Free_Recursive (lines);
|
||||
return 0;
|
||||
|
|
|
@ -47,6 +47,7 @@ static __attribute__ ((unused)) const char rcsid[] =
|
|||
#include "QF/gib_parse.h"
|
||||
#include "QF/gib_vars.h"
|
||||
#include "QF/gib_process.h"
|
||||
#include "QF/gib_builtin.h"
|
||||
|
||||
#include "exp.h"
|
||||
|
||||
|
@ -63,7 +64,7 @@ GIB_Process_Variable (dstring_t *token, unsigned int *i)
|
|||
(*i)++;
|
||||
if (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;
|
||||
}
|
||||
n += 2;
|
||||
|
@ -71,9 +72,10 @@ GIB_Process_Variable (dstring_t *token, unsigned int *i)
|
|||
} else {
|
||||
for (; isalnum((byte) token->str[*i]) || token->str[*i] == '_'; (*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;
|
||||
else
|
||||
} else
|
||||
(*i)++;
|
||||
}
|
||||
n++;
|
||||
|
@ -119,7 +121,7 @@ GIB_Process_Math (struct dstring_s *token, unsigned int i)
|
|||
|
||||
value = EXP_Evaluate (token->str+i);
|
||||
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;
|
||||
} else {
|
||||
token->str[i] = 0;
|
||||
|
|
|
@ -115,12 +115,11 @@ GIB_Thread_Execute (void)
|
|||
|
||||
for (cur = gib_threads; cur; cur = tmp) {
|
||||
tmp = cur->next;
|
||||
if (GIB_DATA(cur->cbuf)->program)
|
||||
Cbuf_Execute_Stack (cur->cbuf);
|
||||
else {
|
||||
if (cur->trash) {
|
||||
GIB_Thread_Remove (cur);
|
||||
GIB_Thread_Delete (cur);
|
||||
}
|
||||
} else
|
||||
Cbuf_Execute_Stack (cur->cbuf);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -38,11 +38,12 @@ static __attribute__ ((unused)) const char rcsid[] =
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "QF/sys.h"
|
||||
#include "QF/qtypes.h"
|
||||
#include "QF/gib_tree.h"
|
||||
|
||||
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));
|
||||
new->flags = flags;
|
||||
|
@ -60,13 +61,30 @@ GIB_Tree_Free_Recursive (gib_tree_t *tree)
|
|||
return;
|
||||
for (; tree; tree = n) {
|
||||
n = tree->next;
|
||||
if (tree->children) {
|
||||
if (tree->children)
|
||||
// Parent is about to bite the dust, meaning one less reference
|
||||
tree->children->refs--;
|
||||
GIB_Tree_Free_Recursive (tree->children);
|
||||
}
|
||||
GIB_Tree_Unref (&tree->children);
|
||||
if (tree->str)
|
||||
free((void *) tree->str);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -127,13 +127,28 @@ Cbuf_DeleteStack (cbuf_t *stack)
|
|||
}
|
||||
|
||||
void
|
||||
Cbuf_PushStack (cbuf_t *new)
|
||||
Cbuf_Reset (cbuf_t *cbuf)
|
||||
{
|
||||
if (cbuf_active->down)
|
||||
Cbuf_DeleteStack (cbuf_active->down);
|
||||
cbuf->resumetime = 0.0;
|
||||
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;
|
||||
new->up = cbuf_active;
|
||||
cbuf_active->state = CBUF_STATE_STACK;
|
||||
return new;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -167,33 +182,27 @@ Cbuf_Execute_Stack (cbuf_t *cbuf)
|
|||
else
|
||||
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) {
|
||||
if (sp->down) {
|
||||
Cbuf_Delete (sp->down);
|
||||
sp->down = 0;
|
||||
}
|
||||
Cbuf_Execute (sp);
|
||||
if (sp->state) {
|
||||
if (sp->state == CBUF_STATE_STACK) {
|
||||
sp = sp->down;
|
||||
continue;
|
||||
} else if (sp->state == CBUF_STATE_ERROR)
|
||||
goto ERROR;
|
||||
break;
|
||||
else
|
||||
return;
|
||||
}
|
||||
}
|
||||
sp->state = CBUF_STATE_JUNK;
|
||||
sp = sp->up;
|
||||
}
|
||||
return;
|
||||
ERROR:
|
||||
|
||||
if (cbuf->down) {
|
||||
Cbuf_DeleteStack (cbuf->down);
|
||||
cbuf->down = 0;
|
||||
}
|
||||
// Tear it down and build it back up
|
||||
cbuf->interpreter->destruct (cbuf);
|
||||
cbuf->interpreter->construct (cbuf);
|
||||
Cbuf_Reset (cbuf);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -202,24 +211,3 @@ Cbuf_Execute_Sets (cbuf_t *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);
|
||||
}
|
||||
|
|
|
@ -106,7 +106,7 @@ Cmd_Args (int start)
|
|||
return cmd_args->args[start];
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
Cmd_Command (cbuf_args_t *args)
|
||||
{
|
||||
cmd_function_t *cmd;
|
||||
|
@ -115,7 +115,7 @@ Cmd_Command (cbuf_args_t *args)
|
|||
//cmd_source = src;
|
||||
|
||||
if (!args->argc)
|
||||
return; // no tokens
|
||||
return 0; // no tokens
|
||||
|
||||
// check functions
|
||||
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) {
|
||||
cmd->function ();
|
||||
}
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
// check cvars
|
||||
if (Cvar_Command ())
|
||||
return;
|
||||
|
||||
return 0;
|
||||
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)
|
||||
Sys_Printf ("Unknown command \"%s\"\n", Cmd_Argv (0));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Registers a command and handler function */
|
||||
|
|
|
@ -68,6 +68,13 @@ COM_destruct (cbuf_t *cbuf)
|
|||
free(cbuf->data);
|
||||
}
|
||||
|
||||
static void
|
||||
COM_reset (cbuf_t *cbuf)
|
||||
{
|
||||
dstring_clearstr (DATA(cbuf)->buf);
|
||||
dstring_clearstr (DATA(cbuf)->line);
|
||||
}
|
||||
|
||||
static void
|
||||
COM_add (cbuf_t *cbuf, const char *str)
|
||||
{
|
||||
|
@ -232,6 +239,7 @@ COM_execute_sets (cbuf_t *cbuf)
|
|||
cbuf_interpreter_t id_interp = {
|
||||
COM_construct,
|
||||
COM_destruct,
|
||||
COM_reset,
|
||||
COM_add,
|
||||
COM_insert,
|
||||
COM_execute,
|
||||
|
|
|
@ -681,10 +681,7 @@ Key_GIB_Bind_Get_f (void)
|
|||
int t, k;
|
||||
|
||||
if (GIB_Argc() != 2) {
|
||||
Cbuf_Error ("syntax",
|
||||
"bind::get: invalid syntax\n"
|
||||
"usage: bind::get key"
|
||||
);
|
||||
GIB_USAGE ("key");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -693,12 +690,12 @@ Key_GIB_Bind_Get_f (void)
|
|||
key = OK_TranslateKeyName (GIB_Argv (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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -409,9 +409,7 @@ Locs_Loc_Get (void)
|
|||
location_t *location;
|
||||
|
||||
if (GIB_Argc() != 1)
|
||||
Cbuf_Error ("syntax",
|
||||
"loc::get: invalid syntax\n"
|
||||
"usage: loc::get");
|
||||
GIB_USAGE ("");
|
||||
else {
|
||||
location = locs_find (cl.simorg);
|
||||
GIB_Return (location ? location->name : "unknown");
|
||||
|
|
|
@ -55,6 +55,10 @@ Carne_Execute_Script (const char *path, cbuf_args_t *args)
|
|||
if (f[0] == '#')
|
||||
for (; f[i] != '\n' && f[i+1]; 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);
|
||||
}
|
||||
Qclose (file);
|
||||
|
@ -63,8 +67,11 @@ Carne_Execute_Script (const char *path, cbuf_args_t *args)
|
|||
return 1;
|
||||
}
|
||||
|
||||
//GIB_Parse_Strip_Comments (mbuf);
|
||||
|
||||
if (gib_parse_error)
|
||||
return 1;
|
||||
|
||||
|
||||
|
||||
GIB_Function_Prepare_Args (mbuf, args->argv, args->argc);
|
||||
|
||||
// Main loop
|
||||
|
@ -90,7 +97,8 @@ Carne_Execute_Stdin (void)
|
|||
while (fgets(linebuf, sizeof(linebuf)-1, stdin)) {
|
||||
GIB_Thread_Execute ();
|
||||
Cbuf_AddText (cbuf, linebuf);
|
||||
Cbuf_Execute_Stack (cbuf);
|
||||
if (!gib_parse_error)
|
||||
Cbuf_Execute_Stack (cbuf);
|
||||
if (carne_done)
|
||||
break;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue