quakeforge/libs/gib/gib_builtin.c
Bill Currie 7970525ef4 [util] Make va thread-safe
It now takes a context pointer (opaque data) that holds the buffers it
uses for the temporary strings. If the context pointer is null, a static
context is used (making those uses of va NOT thread-safe). Most calls to
va use the static context, but all such calls have been formatted
consistently so they are easy to find when it comes time to do a full
audit.
2021-01-31 16:05:48 +09:00

1093 lines
24 KiB
C

/*
#FILENAME#
#DESCRIPTION#
Copyright (C) 2002 #AUTHOR#
Author: #AUTHOR#
Date: #DATE#
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <dirent.h>
#include <fnmatch.h>
#include <errno.h>
#include "QF/cvar.h"
#include "QF/quakefs.h"
#include "QF/zone.h"
#include "QF/va.h"
#include "QF/sys.h"
#include "QF/cmd.h"
#include "QF/cbuf.h"
#include "QF/hash.h"
#include "QF/llist.h"
#include "QF/dstring.h"
#include "QF/gib.h"
#include "regex.h"
#include "gib_buffer.h"
#include "gib_parse.h"
#include "gib_function.h"
#include "gib_vars.h"
#include "gib_regex.h"
#include "gib_thread.h"
#include "gib_handle.h"
#include "gib_builtin.h"
#include "gib_classes.h"
static char _gib_null_string[] = "";
VISIBLE char * const gib_null_string = _gib_null_string;
hashtab_t *gib_builtins;
/*
Hashtable callbacks
*/
static const char *
GIB_Builtin_Get_Key (const void *ele, void *ptr)
{
return ((gib_builtin_t *) ele)->name;
}
static void
GIB_Builtin_Free (void *ele, void *ptr)
{
gib_builtin_t *b;
b = (gib_builtin_t *) ele;
free ((void *)b->name);
free (b);
}
/*
GIB_Builtin_Add
Registers a new builtin GIB command.
*/
VISIBLE void
GIB_Builtin_Add (const char *name, void (*func) (void))
{
gib_builtin_t *new;
if (!gib_builtins)
gib_builtins =
Hash_NewTable (1024, GIB_Builtin_Get_Key, GIB_Builtin_Free, 0, 0);
new = calloc (1, sizeof (gib_builtin_t));
new->func = func;
new->name = strdup (name);
Hash_Add (gib_builtins, new);
}
VISIBLE void
GIB_Builtin_Remove (const char *name)
{
gib_builtin_t *del;
if ((del = Hash_Del (gib_builtins, name)))
Hash_Free (gib_builtins, del);
}
VISIBLE qboolean
GIB_Builtin_Exists (const char *name)
{
return Hash_Find (gib_builtins, name) ? true : false;
}
/*
GIB_Builtin_Find
Looks up the builtin name in the builtin hash,
returning a pointer to the struct on success,
zero otherwise.
*/
VISIBLE gib_builtin_t *
GIB_Builtin_Find (const char *name)
{
if (!gib_builtins)
return 0;
return (gib_builtin_t *) Hash_Find (gib_builtins, name);
}
VISIBLE dstring_t *
GIB_Return (const char *str)
{
dstring_t *dstr;
if (GIB_DATA (cbuf_active)->waitret) {
dstr = GIB_Buffer_Dsarray_Get (cbuf_active);
dstring_clearstr (dstr);
if (!str)
return dstr;
else
dstring_appendstr (dstr, str);
}
return 0;
}
VISIBLE 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
See GIB docs for information.
*/
static void
GIB_Function_f (void)
{
gib_tree_t *program;
gib_function_t *func;
int i;
int argc = GIB_Argc ();
if (argc < 3) {
GIB_USAGE ("name [arg1 arg2 ...] program");
} else {
// Is the function program already tokenized?
if (GIB_Argm (argc-1)->delim != '{') {
// Parse on the fly
if (!(program = GIB_Parse_Lines (GIB_Argv
(argc-1), 0))) {
// Error!
GIB_Error ("ParseError", "Parse error while defining function '%s'.",
GIB_Argv (1));
return;
}
} else
program = GIB_Argm (argc-1)->children;
func = GIB_Function_Define (GIB_Argv (1), GIB_Argv (argc-1), program,
GIB_DATA (cbuf_active)->script,
GIB_DATA (cbuf_active)->globals);
llist_flush (func->arglist);
for (i = 2; i < argc-1; i++)
llist_append (func->arglist, strdup (GIB_Argv(i)));
func->minargs = argc-2;
}
}
static void
GIB_Function_Get_f (void)
{
if (GIB_Argc () != 2) {
GIB_USAGE ("name");
} else {
gib_function_t *f;
if ((f = GIB_Function_Find (GIB_Argv (1))))
GIB_Return (f->text->str);
else
GIB_Return ("");
}
}
static void
GIB_Local_f (void)
{
gib_var_t *var;
unsigned int index;
int i;
static hashtab_t *zero = 0;
if (GIB_Argc () < 2) {
GIB_USAGE ("var [= value1 value2 ...] || var [var2 var3 ...]");
} else if (!strcmp (GIB_Argv(2), "=")) {
var = GIB_Var_Get_Complex (&GIB_DATA (cbuf_active)->locals, &zero,
GIB_Argv (1), &index, true);
if (GIB_Argc () >= 3)
GIB_Var_Assign (var, index, cbuf_active->args->argv + 3,
GIB_Argc () - 3, GIB_Argv (1)[strlen (GIB_Argv(1)) - 1] != ']');
if (GIB_CanReturn ())
for (i = 3; i < GIB_Argc(); i++)
GIB_Return (GIB_Argv(i));
} else for (i = 1; i < GIB_Argc(); i++)
GIB_Var_Get_Complex (&GIB_DATA (cbuf_active)->locals, &zero,
GIB_Argv (i), &index, true);
}
static void
GIB_Shared_f (void)
{
gib_var_t *var;
unsigned int index;
int i;
static hashtab_t *zero = 0;
if (GIB_Argc () < 2) {
GIB_USAGE ("var [= value1 value2 ...] || var [var2 var3 ...]");
} else if (!strcmp (GIB_Argv(2), "=")) {
var = GIB_Var_Get_Complex (&GIB_DATA (cbuf_active)->globals, &zero,
GIB_Argv (1), &index, true);
if (GIB_Argc () >= 3)
GIB_Var_Assign (var, index, cbuf_active->args->argv + 3,
GIB_Argc () - 3, GIB_Argv (1)[strlen (GIB_Argv(1)) - 1] != ']');
if (GIB_CanReturn ())
for (i = 3; i < GIB_Argc(); i++)
GIB_Return (GIB_Argv(i));
} else for (i = 1; i < GIB_Argc(); i++)
GIB_Var_Get_Complex (&GIB_DATA (cbuf_active)->globals, &zero,
GIB_Argv (i), &index, true);
}
static void
GIB_Delete_f (void)
{
gib_var_t *var;
unsigned int index;
int i;
hashtab_t *source;
char *c;
if (GIB_Argc () < 2) {
GIB_USAGE ("var [var2 var2 ...]");
} else for (i = 1; i < GIB_Argc(); i++) {
if ((c = strrchr (GIB_Argv(i), '.'))) {
*(c++) = 0;
if (!(var = GIB_Var_Get_Complex (&GIB_DATA (cbuf_active)->locals,
&GIB_DATA(cbuf_active)->globals,
GIB_Argv (i), &index, false)))
continue;
source = var->array[index].leaves;
} else {
c = GIB_Argv(i);
source = GIB_DATA(cbuf_active)->globals;
}
Hash_Free (source, Hash_Del (source, c));
}
}
static void
GIB_Domain_f (void)
{
if (GIB_Argc () != 2)
GIB_USAGE ("domain");
else
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 gib_tree_t fakeip = {0,0,0,0,0,0,0,0};
static void
GIB_Return_f (void)
{
cbuf_t *sp = cbuf_active->up;
GIB_DATA (cbuf_active)->ip = &fakeip;
if (GIB_DATA (cbuf_active)->reply.obj) {
gib_buffer_data_t *g = GIB_DATA (cbuf_active);
const char **argv = malloc (sizeof (char *) * GIB_Argc() -1);
int i;
for (i = 1; i < GIB_Argc(); i++)
argv[i-1] = GIB_Argv(i);
GIB_Reply (g->reply.obj, g->reply.mesg, GIB_Argc()-1, argv);
free ((void*)argv);
g->dnotify = NULL;
} else if (GIB_Argc () > 1 && sp && sp->interpreter == &gib_interp
&& GIB_DATA (sp)->waitret) {
int i;
dstring_t *dstr;
for (i = 1; i < GIB_Argc (); i++) {
dstr = GIB_Buffer_Dsarray_Get (sp);
dstring_clearstr (dstr);
dstring_appendstr (dstr, GIB_Argv (i));
}
}
}
static void
GIB_For_f (void)
{
dstring_t *dstr;
int i;
GIB_Buffer_Push_Sstack (cbuf_active);
dstr = GIB_Buffer_Dsarray_Get (cbuf_active);
dstring_clearstr (dstr);
dstring_appendstr (dstr, GIB_Argv (1));
for (i = GIB_Argc () - 2; i > 2; i--) {
dstr = GIB_Buffer_Dsarray_Get (cbuf_active);
dstring_appendstr (dstr, GIB_Argv (i));
}
}
// Note: this is a standard console command, not a GIB builtin
static void
GIB_Runexported_f (void)
{
gib_function_t *f;
const char **args;
if (!(f = GIB_Function_Find (Cmd_Argv (0)))) {
Sys_Printf ("Error: No function found for exported command \"%s\".\n"
"This is most likely a bug, please report it to"
"The QuakeForge developers.", Cmd_Argv (0));
} else {
cbuf_t *sub = Cbuf_PushStack (&gib_interp);
int i;
args = malloc (sizeof (char *) * Cmd_Argc());
for (i = 0; i < Cmd_Argc(); i++)
args[i] = Cmd_Argv(i);
GIB_Function_Execute (sub, f, args, Cmd_Argc());
free ((void*)args);
}
}
static void
GIB_Function_Export_f (void)
{
gib_function_t *f;
int i;
if (GIB_Argc () < 2)
GIB_USAGE ("function1 [function2 function3 ...]");
for (i = 1; i < GIB_Argc (); i++) {
if (!(f = GIB_Function_Find (GIB_Argv (i))))
GIB_Error ("UnknownFunctionError", "%s: function '%s' not found.", GIB_Argv (0),
GIB_Argv (i));
else if (!f->exported) {
if (Cmd_Exists (f->name)) {
GIB_Error ("NameConflictError",
"%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;
}
}
}
}
static void
GIB_Length_f (void)
{
dstring_t *ret;
if (GIB_Argc () != 2)
GIB_USAGE ("string");
else if ((ret = GIB_Return (0)))
dsprintf (ret, "%i", (int) strlen (GIB_Argv (1)));
}
static void
GIB_Equal_f (void)
{
if (GIB_Argc () != 3)
GIB_USAGE ("string1 string2");
else if (strcmp (GIB_Argv (1), GIB_Argv (2)))
GIB_Return ("0");
else
GIB_Return ("1");
}
static void
GIB_Count_f (void)
{
if (GIB_CanReturn())
dsprintf (GIB_Return(0), "%u", GIB_Argc() - 1);
}
static void
GIB_Contains_f (void)
{
int i;
if (GIB_Argc () < 2)
GIB_USAGE ("needle [straw1 straw2 ...]");
else if (GIB_CanReturn ())
for (i = 2; i < GIB_Argc(); i++)
if (!strcmp(GIB_Argv(1), GIB_Argv(i))) {
GIB_Return("1");
return;
}
GIB_Return ("0");
}
static void
GIB_Slice_f (void)
{
dstring_t *ret;
int start, end, len;
if (GIB_Argc () < 3 || GIB_Argc () > 4) {
GIB_USAGE ("string start [end]");
} else {
len = strlen (GIB_Argv (1));
start = atoi (GIB_Argv (2));
end = *GIB_Argv (3) ? atoi (GIB_Argv (3)) : len;
if (end < 0)
end += len;
else if (end > len)
end = len;
if (start < 0) {
start += len;
if (start < 0)
start = 0;
} else if (start >= len || start >= end)
return;
if ((ret = GIB_Return (0)))
dstring_appendsubstr (ret, GIB_Argv (1) + start, end - start);
}
}
static void
GIB_Slice_Find_f (void)
{
char *res;
if (GIB_Argc () != 3) {
GIB_USAGE ("haystack needle");
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))));
}
}
static void
GIB_Split_f (void)
{
char *end, *start;
const char *ifs;
if (GIB_Argc () < 2 || GIB_Argc () > 3) {
GIB_USAGE ("string [fs]");
return;
}
ifs = GIB_Argc () == 3 ? GIB_Argv (2) : " \t\r\n";
end = GIB_Argv (1);
while (*end) {
for (; strchr (ifs, *end); end++)
if (!*end)
return;
start = end;
while (!strchr (ifs, *end))
end++;
if (*end)
*(end++) = 0;
GIB_Return (start);
}
}
static void
GIB_Chomp_f (void)
{
char *str;
const char *junk;
unsigned int i;
if (GIB_Argc () < 2 || GIB_Argc () > 3) {
GIB_USAGE ("string [junk]");
return;
}
str = GIB_Argv (1);
if (GIB_Argc () == 2)
junk = " \t\n\r";
else
junk = GIB_Argv (2);
for (; *str && strchr (junk, *str); str++);
for (i = strlen(str) - 1; i && strchr (junk, str[i]); i--);
str[i+1] = 0;
GIB_Return (str);
}
static void
GIB_Regex_Match_f (void)
{
regex_t *reg;
if (GIB_Argc () != 4) {
GIB_USAGE ("string regex options");
return;
}
if (!(reg = GIB_Regex_Compile (GIB_Argv (2), REG_EXTENDED |
GIB_Regex_Translate_Options (GIB_Argv (3)))))
GIB_Error ("RegexError", "%s: %s", GIB_Argv (0), GIB_Regex_Error ());
else if (regexec (reg, GIB_Argv (1), 0, 0, GIB_Regex_Translate_Runtime_Options (GIB_Argv (3))))
GIB_Return ("0");
else
GIB_Return ("1");
}
static void
GIB_Regex_Replace_f (void)
{
regex_t *reg;
int ofs;
regmatch_t match[10];
if (GIB_Argc () != 5) {
GIB_USAGE ("string regex options replacement");
return;
}
ofs = 0;
if (!
(reg =
GIB_Regex_Compile (GIB_Argv (2),
REG_EXTENDED |
GIB_Regex_Translate_Options (GIB_Argv (3)))))
GIB_Error ("RegexError", "%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));
else if (!regexec (reg, GIB_Argv (1), 10, match, GIB_Regex_Translate_Runtime_Options (GIB_Argv (3))) && match[0].rm_eo)
GIB_Regex_Apply_Match (match, GIB_Argd (1), 0, GIB_Argv (4));
GIB_Return (GIB_Argv (1));
}
static void
GIB_Regex_Extract_f (void)
{
regex_t *reg;
regmatch_t *match;
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)))))
GIB_Error ("RegexError", "%s: %s", GIB_Argv (0), GIB_Regex_Error ());
else if (!regexec (reg, GIB_Argv (1), 32, match, GIB_Regex_Translate_Runtime_Options (GIB_Argv (3))) && 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];
GIB_Argv (1)[match[i].rm_eo] = 0;
GIB_Return (GIB_Argv (1) + match[i].rm_so);
GIB_Argv (1)[match[i].rm_eo] = o;
}
}
}
free (match);
}
static void
GIB_Text_White_f (void)
{
if (GIB_Argc () != 2)
GIB_USAGE ("text");
else if (GIB_CanReturn ()) {
unsigned int i;
dstring_t *dstr;
char *str;
dstr = GIB_Return (0);
dstring_appendstr (dstr, GIB_Argv(1));
str = dstr->str;
for (i = 0; i < dstr->size-1; i++)
str[i] = str[i] & ~0x80;
}
}
static void
GIB_Text_Brown_f (void)
{
if (GIB_Argc () != 2)
GIB_USAGE ("text");
else if (GIB_CanReturn ()) {
unsigned int i;
dstring_t *dstr;
char *str;
dstr = GIB_Return (0);
dstring_appendstr (dstr, GIB_Argv(1));
str = dstr->str;
for (i = 0; i < dstr->size-1; i++)
str[i] = str[i] | 0x80;
}
}
/*
static void
GIB_Text_To_Gold_f (void)
{
if (GIB_Argc () != 2)
GIB_USAGE ("text");
else if (GIB_CanReturn ()) {
dstring_t *dstr;
char *str;
dstr = GIB_Return (0);
dstring_copystr (dstr, GIB_Argv(1));
for (str = dstr->str; *str; str++) {
switch (*str) {
*/
static void
GIB_Text_To_Decimal_f (void)
{
if (GIB_Argc () != 2)
GIB_USAGE ("text");
else if (GIB_CanReturn ()) {
char *str;
for (str = GIB_Argv(1); *str; str++)
dsprintf (GIB_Return (0), "%i", (int) *str);
}
}
static void
GIB_Text_From_Decimal_f (void)
{
if (GIB_Argc () < 2)
GIB_USAGE ("num1 [...]");
else if (GIB_CanReturn ()) {
int i;
dstring_t *dstr;
char *str;
dstr = GIB_Return (0);
dstr->size = GIB_Argc();
dstring_adjust (dstr);
str = dstr->str;
for (i = 1; i < GIB_Argc(); i++, str++)
*str = (char) atoi (GIB_Argv(i));
*str = 0;
}
}
static void
GIB_Event_Register_f (void)
{
gib_function_t *func;
if (GIB_Argc () != 3)
GIB_USAGE ("event function");
else if (!(func = GIB_Function_Find (GIB_Argv (2))) && GIB_Argv (2)[0])
GIB_Error ("UnknownFunctionError", "Function %s not found.", GIB_Argv (2));
else if (GIB_Event_Register (GIB_Argv (1), func))
GIB_Error ("UnknownEventError", "Event %s not found.", GIB_Argv (1));
}
/* File access */
static int (*GIB_File_Transform_Path) (dstring_t * path) = NULL;
static int
GIB_File_Transform_Path_Null (dstring_t * path)
{
char *s;
// Convert backslash to forward slash
for (s = strchr (path->str, '\\'); s; s = strchr (s, '\\'))
*s = '/';
return 0;
}
static int
GIB_File_Transform_Path_Secure (dstring_t * path)
{
char *s;
for (s = strchr (path->str, '\\'); s; s = strchr (s, '\\'))
*s = '/';
if (path->str[0] != '/')
dstring_insertstr (path, 0, "/");
dstring_insertstr (path, 0, qfs_gamedir->dir.def);
dstring_insertstr (path, 0, "/");
dstring_insertstr (path, 0, qfs_userpath);
return 0;
}
static void
GIB_File_Read_f (void)
{
QFile *file;
char *path;
int len;
dstring_t *ret;
if (GIB_Argc () != 2) {
GIB_USAGE ("file");
return;
}
if (!*GIB_Argv (1)) {
GIB_Error ("FileAccessError", "%s: null filename provided", GIB_Argv (0));
return;
}
if (!(ret = GIB_Return (0)))
return;
path = GIB_Argv (1);
file = QFS_FOpenFile (path);
if (file) {
len = Qfilesize (file);
ret->size = len + 1;
dstring_adjust (ret);
Qread (file, ret->str, len);
ret->str[len] = 0;
Qclose (file);
} else {
GIB_Error ("FileAccessError",
"%s: could not read %s: %s", GIB_Argv (0), path,
strerror (errno));
return;
}
}
static void
GIB_File_Write_f (void)
{
char *path;
if (GIB_Argc () != 3) {
GIB_USAGE ("file data");
return;
}
if (!*GIB_Argv (1)) {
GIB_Error ("InvalidArgumentError", "%s: null filename provided", GIB_Argv (0));
return;
}
path = GIB_Argv (1);
QFS_WriteFile (va (0, "%s/%s", qfs_gamedir->dir.def, path),
GIB_Argv(2), GIB_Argd(2)->size-1);
}
static void
GIB_File_Find_f (void)
{
DIR *directory;
struct dirent *entry;
const char *path, *glob = 0;
char *s;
if (GIB_Argc () != 2) {
GIB_USAGE ("glob");
return;
}
if (GIB_File_Transform_Path (GIB_Argd (1))) {
GIB_Error ("FileAccessError",
"%s: access to %s denied", GIB_Argv (0), GIB_Argv (1));
return;
}
path = GIB_Argv (1);
s = strrchr (path, '/');
if (!s) { // No slash in path
glob = path; // The glob is the entire argument
path = "."; // The path is the current directory
} else if (s == path) // Unix filesystem root (carne only)
path = "/";
else {
*s = 0; // Split the string at the final slash
glob = s + 1;
}
directory = opendir (path);
if (!directory)
return;
while ((entry = readdir (directory)))
if (strcmp (entry->d_name, ".") && strcmp (entry->d_name, "..")
&& !fnmatch (glob, entry->d_name, 0))
GIB_Return (entry->d_name);
closedir (directory);
}
static void
GIB_File_Move_f (void)
{
char *path1, *path2;
if (GIB_Argc () != 3) {
GIB_USAGE ("from_file to_file");
return;
}
if (GIB_File_Transform_Path (GIB_Argd (1))) {
GIB_Error ("FileAccessError",
"%s: access to %s denied", GIB_Argv (0), GIB_Argv (1));
return;
}
if (GIB_File_Transform_Path (GIB_Argd (2))) {
GIB_Error ("FileAccessError",
"%s: access to %s denied", GIB_Argv (0), GIB_Argv (2));
return;
}
path1 = GIB_Argv (1);
path2 = GIB_Argv (2);
if (QFS_Rename (path1, path2))
GIB_Error ("FileAccessError", "%s: could not move %s to %s: %s", GIB_Argv (0),
path1, path2, strerror (errno));
}
static void
GIB_File_Delete_f (void)
{
char *path;
if (GIB_Argc () != 2) {
GIB_USAGE ("file");
return;
}
if (GIB_File_Transform_Path (GIB_Argd (1))) {
GIB_Error ("FileAccessError",
"%s: access to %s denied", GIB_Argv (0), GIB_Argv (1));
return;
}
path = GIB_Argv (1);
if (QFS_Remove (path))
GIB_Error ("FileAccessError", "%s: could not delete %s: %s", GIB_Argv (0), path,
strerror (errno));
}
static void
GIB_Range_f (void)
{
double i, inc, start, limit;
dstring_t *dstr;
if (GIB_Argc () < 3 || GIB_Argc () > 4) {
GIB_USAGE ("lower upper [step]");
return;
}
limit = atof (GIB_Argv (2));
start = atof (GIB_Argv (1));
if (GIB_Argc () == 4) {
if ((inc = atof (GIB_Argv (3))) == 0.0)
return;
} else
inc = limit < start ? -1.0 : 1.0;
for (i = atof (GIB_Argv (1)); inc < 0 ? i >= limit : i <= limit; i += inc) {
if (!(dstr = GIB_Return (0)))
return;
dsprintf (dstr, "%.10g", i);
}
}
static void
GIB_Print_f (void)
{
if (GIB_Argc () != 2) {
GIB_USAGE ("text");
return;
}
Sys_Printf ("%s", GIB_Argv (1));
}
static void
GIB_Class_f (void)
{
if (GIB_Object_Get (GIB_Argv(1))) {
GIB_Error ("ClassRedefinitionError",
"Class '%s' already exists", GIB_Argv(1));
} else if (GIB_Argc () == 5)
GIB_Classes_Build_Scripted (GIB_Argv(1), GIB_Argv(3),
GIB_Argm (4)->children,
GIB_DATA(cbuf_active)->script);
else
GIB_Classes_Build_Scripted (GIB_Argv(1), "Object",
GIB_Argm (2)->children,
GIB_DATA(cbuf_active)->script);
}
static void
GIB_Emit_f (void)
{
if (GIB_Argc () < 2) {
GIB_USAGE ("signal [arg1 arg2 ...]");
return;
} else if (!GIB_DATA(cbuf_active)->reply.obj) {
GIB_Error ("InvalidContextError", "Cannot emit signal in this context.");
return;
} else {
int i;
const char **argv = malloc (GIB_Argc () - 1);
for (i = 1; i < GIB_Argc (); i ++)
argv[i-1] = GIB_Argv (1);
GIB_Object_Signal_Emit (GIB_DATA(cbuf_active)->reply.obj,
GIB_Argc () - 1, argv);
free ((void*)argv);
}
}
static void
GIB_Exists_f (void)
{
if (GIB_Object_Get (GIB_Argv (1)))
GIB_Return ("1");
else
GIB_Return ("0");
}
static void
GIB_Error_f (void)
{
if (GIB_Argc() < 3) {
GIB_USAGE ("error_type explanation");
return;
} else
GIB_Error (GIB_Argv(1), "%s", GIB_Argv(2));
}
/*
static void
GIB_New_f (void)
{
GIB_Object_t *classobj;
if (GIB_Argc() < 2) {
GIB_USAGE ("classname");
} else if (
!(class = GIB_Object_Get(GIB_Argv(1)))
|| classobj->class->classobj != classobj) {
GIB_Error ("UnknownClassError", "Class '%s' does not exist",
GIB_Argv(1));
} else {
GIB_Send (classobj,
*/
static void
GIB_bp1_f (void)
{
}
static void
GIB_bp2_f (void)
{
}
static void
GIB_bp3_f (void)
{
}
static void
GIB_bp4_f (void)
{
}
void
GIB_Builtin_Init (qboolean sandbox)
{
if (sandbox)
GIB_File_Transform_Path = GIB_File_Transform_Path_Secure;
else
GIB_File_Transform_Path = GIB_File_Transform_Path_Null;
GIB_Builtin_Add ("function", GIB_Function_f);
GIB_Builtin_Add ("function::get", GIB_Function_Get_f);
GIB_Builtin_Add ("function::export", GIB_Function_Export_f);
GIB_Builtin_Add ("local", GIB_Local_f);
GIB_Builtin_Add ("shared", GIB_Shared_f);
GIB_Builtin_Add ("global", GIB_Shared_f);
GIB_Builtin_Add ("delete", GIB_Delete_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 ("length", GIB_Length_f);
GIB_Builtin_Add ("equal", GIB_Equal_f);
GIB_Builtin_Add ("count", GIB_Count_f);
GIB_Builtin_Add ("contains", GIB_Contains_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 ("chomp", GIB_Chomp_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 ("text::toWhite", GIB_Text_White_f);
GIB_Builtin_Add ("text::toBrown", GIB_Text_Brown_f);
GIB_Builtin_Add ("text::toDecimal", GIB_Text_To_Decimal_f);
GIB_Builtin_Add ("text::fromDecimal", GIB_Text_From_Decimal_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);
GIB_Builtin_Add ("file::find", GIB_File_Find_f);
GIB_Builtin_Add ("file::move", GIB_File_Move_f);
GIB_Builtin_Add ("file::delete", GIB_File_Delete_f);
GIB_Builtin_Add ("range", GIB_Range_f);
GIB_Builtin_Add ("print", GIB_Print_f);
GIB_Builtin_Add ("class", GIB_Class_f);
GIB_Builtin_Add ("emit", GIB_Emit_f);
GIB_Builtin_Add ("exists", GIB_Exists_f);
GIB_Builtin_Add ("error", GIB_Error_f);
GIB_Builtin_Add ("bp1", GIB_bp1_f);
GIB_Builtin_Add ("bp2", GIB_bp2_f);
GIB_Builtin_Add ("bp3", GIB_bp3_f);
GIB_Builtin_Add ("bp4", GIB_bp4_f);
}