mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-12-18 08:33:37 +00:00
876eaa467c
The player global branch variable is now updated with useful information and the location.get builtin is available to return the current location of the player based on loc files. Fixed a bug with zooming out in zoom.gib.
397 lines
9.2 KiB
C
397 lines
9.2 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
|
|
|
|
*/
|
|
|
|
static const char rcsid[] =
|
|
"$Id$";
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include "config.h"
|
|
#endif
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "QF/va.h"
|
|
#include "QF/sys.h"
|
|
#include "QF/cmd.h"
|
|
#include "QF/cbuf.h"
|
|
#include "QF/hash.h"
|
|
#include "QF/dstring.h"
|
|
#include "QF/gib_parse.h"
|
|
#include "QF/gib_builtin.h"
|
|
#include "QF/gib_buffer.h"
|
|
#include "QF/gib_function.h"
|
|
#include "QF/gib_vars.h"
|
|
|
|
hashtab_t *gib_builtins;
|
|
|
|
/*
|
|
Hashtable callbacks
|
|
*/
|
|
const char *
|
|
GIB_Builtin_Get_Key (void *ele, void *ptr)
|
|
{
|
|
return ((gib_builtin_t *)ele)->name->str;
|
|
}
|
|
void
|
|
GIB_Builtin_Free (void *ele, void *ptr)
|
|
{
|
|
gib_builtin_t *b;
|
|
b = (gib_builtin_t *) ele;
|
|
dstring_delete (b->name);
|
|
free (b);
|
|
}
|
|
|
|
/*
|
|
GIB_Builtin_Add
|
|
|
|
Registers a new builtin GIB command.
|
|
*/
|
|
void
|
|
GIB_Builtin_Add (const char *name, void (*func) (void), enum gib_builtin_type_e type)
|
|
{
|
|
gib_builtin_t *new;
|
|
|
|
if (!gib_builtins)
|
|
gib_builtins = Hash_NewTable (1024, GIB_Builtin_Get_Key, GIB_Builtin_Free, 0);
|
|
|
|
new = calloc (1, sizeof (gib_builtin_t));
|
|
new->func = func;
|
|
new->name = dstring_newstr();
|
|
new->type = type;
|
|
dstring_appendstr (new->name, name);
|
|
Hash_Add (gib_builtins, new);
|
|
}
|
|
|
|
/*
|
|
GIB_Builtin_Find
|
|
|
|
Looks up the builtin name in the builtin hash,
|
|
returning a pointer to the struct on success,
|
|
zero otherwise.
|
|
*/
|
|
gib_builtin_t *
|
|
GIB_Builtin_Find (const char *name)
|
|
{
|
|
if (!gib_builtins)
|
|
return 0;
|
|
return (gib_builtin_t *) Hash_Find (gib_builtins, name);
|
|
}
|
|
|
|
/*
|
|
GIB_Argc
|
|
|
|
Returns the number of arguments available
|
|
in the current buffer.
|
|
*/
|
|
unsigned int
|
|
GIB_Argc (void)
|
|
{
|
|
return cbuf_active->args->argc;
|
|
}
|
|
|
|
/*
|
|
Returns a specific argument in the current
|
|
buffer.
|
|
*/
|
|
const char *
|
|
GIB_Argv (unsigned int arg)
|
|
{
|
|
if (arg < cbuf_active->args->argc)
|
|
return cbuf_active->args->argv[arg]->str;
|
|
else
|
|
return "";
|
|
}
|
|
|
|
/*
|
|
GIB_Args
|
|
|
|
Returns a pointer to the composite command
|
|
line starting at token arg.
|
|
*/
|
|
const char *
|
|
GIB_Args (unsigned int arg)
|
|
{
|
|
if (arg < cbuf_active->args->argc)
|
|
return cbuf_active->args->args[arg];
|
|
else
|
|
return "";
|
|
}
|
|
|
|
/*
|
|
GIB_Arg_Strip_Delim
|
|
|
|
Strips any wrapping characters off of the
|
|
specified argument. Useful for GIB_BUILTIN_NOPROCESS
|
|
or GIB_BUILTIN_FIRSTONLY builtins.
|
|
*/
|
|
void
|
|
GIB_Arg_Strip_Delim (unsigned int arg)
|
|
{
|
|
char *p = cbuf_active->args->argv[arg]->str;
|
|
if (*p == '{' || *p == '\"') {
|
|
dstring_snip (cbuf_active->args->argv[arg], 0, 1);
|
|
p[strlen(p)-1] = 0;
|
|
}
|
|
}
|
|
|
|
void
|
|
GIB_Return (const char *str)
|
|
{
|
|
if (GIB_DATA(cbuf_active)->type != GIB_BUFFER_PROXY)
|
|
return;
|
|
dstring_clearstr (GIB_DATA(cbuf_active->up)->ret.retval);
|
|
dstring_appendstr (GIB_DATA(cbuf_active->up)->ret.retval, str);
|
|
GIB_DATA(cbuf_active->up)->ret.available = true;
|
|
}
|
|
|
|
/*
|
|
GIB Builtin functions
|
|
|
|
See GIB docs for information.
|
|
*/
|
|
void
|
|
GIB_Function_f (void)
|
|
{
|
|
if (GIB_Argc () != 3)
|
|
Cbuf_Error ("syntax",
|
|
"function: invalid syntax\n"
|
|
"usage: function function_name {program}");
|
|
else
|
|
GIB_Function_Define (GIB_Argv(1), GIB_Argv(2));
|
|
}
|
|
|
|
void
|
|
GIB_FunctionDotGet_f (void)
|
|
{
|
|
if (GIB_Argc () != 2)
|
|
Cbuf_Error ("syntax",
|
|
"function.get: invalid syntax\n"
|
|
"usage: function.get function_name");
|
|
else {
|
|
gib_function_t *f;
|
|
if ((f = GIB_Function_Find (GIB_Argv (1))))
|
|
GIB_Return (f->program->str);
|
|
else
|
|
GIB_Return ("");
|
|
}
|
|
}
|
|
|
|
void
|
|
GIB_Local_f (void)
|
|
{
|
|
if (GIB_Argc () != 2)
|
|
Cbuf_Error ("syntax",
|
|
"lset: invalid syntax\n"
|
|
"usage: local variable");
|
|
else
|
|
GIB_Var_Set_Local (cbuf_active, GIB_Argv(1), "");
|
|
}
|
|
|
|
void
|
|
GIB_Global_f (void)
|
|
{
|
|
if (GIB_Argc () != 2)
|
|
Cbuf_Error ("syntax",
|
|
"global: invalid syntax\n"
|
|
"usage: global variable");
|
|
else {
|
|
char *a = strdup (GIB_Argv(1));
|
|
GIB_Var_Set_Global (a, "");
|
|
free(a);
|
|
}
|
|
}
|
|
|
|
void
|
|
GIB_Return_f (void)
|
|
{
|
|
cbuf_t *sp;
|
|
|
|
if (GIB_Argc () > 2)
|
|
Cbuf_Error ("syntax",
|
|
"return: invalid syntax\n"
|
|
"usage: return <value>");
|
|
else {
|
|
sp = cbuf_active;
|
|
while (sp->interpreter == &gib_interp && GIB_DATA(sp)->type == GIB_BUFFER_LOOP) { // Get out of loops
|
|
GIB_DATA(sp)->type = GIB_BUFFER_PROXY;
|
|
dstring_clearstr (sp->buf);
|
|
dstring_clearstr (sp->line);
|
|
sp = sp->up;
|
|
}
|
|
dstring_clearstr (sp->buf);
|
|
dstring_clearstr (sp->line);
|
|
if (GIB_Argc () == 1)
|
|
return;
|
|
if (!sp->up || // Nothing above us on the stack
|
|
GIB_DATA(sp->up)->type != GIB_BUFFER_PROXY || // No proxy buffer created
|
|
!sp->up->up || // Nothing above proxy buffer on the stack
|
|
sp->up->up->interpreter != &gib_interp || // Not a GIB buffer
|
|
!GIB_DATA(sp->up->up)->ret.waiting) // Buffer doesn't want a return value
|
|
Sys_Printf("Warning: unwanted return value discarded.\n"); // Not a serious error
|
|
else {
|
|
dstring_clearstr (GIB_DATA(sp->up->up)->ret.retval);
|
|
dstring_appendstr (GIB_DATA(sp->up->up)->ret.retval, GIB_Argv(1));
|
|
GIB_DATA(sp->up->up)->ret.available = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
GIB_If_f (void)
|
|
{
|
|
int condition;
|
|
if ((!strcmp (GIB_Argv (3), "else") && GIB_Argc() >= 5) || // if condition {program} else ...
|
|
(GIB_Argc() == 3)) { // if condition {program}
|
|
condition = atoi(GIB_Argv(1));
|
|
if (!strcmp (GIB_Argv(0), "ifnot"))
|
|
condition = !condition;
|
|
if (condition) {
|
|
GIB_Arg_Strip_Delim (2);
|
|
Cbuf_InsertText (cbuf_active, GIB_Argv(2));
|
|
} else if (GIB_Argc() == 5) {
|
|
GIB_Arg_Strip_Delim (4);
|
|
Cbuf_InsertText (cbuf_active, GIB_Argv(4));
|
|
} else if (GIB_Argc() > 5)
|
|
Cbuf_InsertText (cbuf_active, GIB_Args (4));
|
|
} else
|
|
Cbuf_Error ("syntax",
|
|
"if: invalid syntax\n"
|
|
"usage: if condition {program} [else ...]"
|
|
);
|
|
}
|
|
|
|
void
|
|
GIB_While_f (void)
|
|
{
|
|
if (GIB_Argc() != 3) {
|
|
Cbuf_Error ("syntax",
|
|
"while: invalid syntax\n"
|
|
"usage: while condition {program}"
|
|
);
|
|
} else {
|
|
cbuf_t *sub = Cbuf_New (&gib_interp);
|
|
GIB_DATA(sub)->type = GIB_BUFFER_LOOP;
|
|
GIB_DATA(sub)->locals = GIB_DATA(cbuf_active)->locals;
|
|
GIB_DATA(sub)->loop_program = dstring_newstr ();
|
|
if (cbuf_active->down)
|
|
Cbuf_DeleteStack (cbuf_active->down);
|
|
cbuf_active->down = sub;
|
|
sub->up = cbuf_active;
|
|
GIB_Arg_Strip_Delim (2);
|
|
dstring_appendstr (GIB_DATA(sub)->loop_program, va("ifnot %s break\n%s", GIB_Argv (1), GIB_Argv (2)));
|
|
Cbuf_AddText (sub, GIB_DATA(sub)->loop_program->str);
|
|
cbuf_active->state = CBUF_STATE_STACK;
|
|
}
|
|
}
|
|
|
|
void
|
|
GIB_Break_f (void)
|
|
{
|
|
if (GIB_DATA(cbuf_active)->type != GIB_BUFFER_LOOP)
|
|
Cbuf_Error ("syntax",
|
|
"break attempted outside of a loop"
|
|
);
|
|
else {
|
|
GIB_DATA(cbuf_active)->type = GIB_BUFFER_PROXY; // If we set it to normal locals will get freed
|
|
dstring_clearstr (cbuf_active->buf);
|
|
}
|
|
}
|
|
|
|
void
|
|
GIB_Runexported_f (void)
|
|
{
|
|
gib_function_t *f;
|
|
|
|
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
|
|
GIB_Function_Execute (f);
|
|
}
|
|
|
|
void
|
|
GIB_Export_f (void)
|
|
{
|
|
gib_function_t *f;
|
|
|
|
if (GIB_Argc() != 2)
|
|
Cbuf_Error ("syntax",
|
|
"export: invalid syntax\n"
|
|
"usage: export function");
|
|
else if (!(f = GIB_Function_Find (GIB_Argv (1))))
|
|
Cbuf_Error ("existance", "export: function '%s' not found", GIB_Argv (1));
|
|
else if (!f->exported) {
|
|
Cmd_AddCommand (f->name->str, GIB_Runexported_f, "Exported GIB function.");
|
|
f->exported = true;
|
|
}
|
|
}
|
|
|
|
void
|
|
GIB_String_Length_f (void)
|
|
{
|
|
if (GIB_Argc() != 2)
|
|
Cbuf_Error ("syntax",
|
|
"string.length: invalid syntax\n"
|
|
"usage: string.length string");
|
|
else
|
|
GIB_Return (va("%i", strlen(GIB_Argv(1))));
|
|
}
|
|
|
|
void
|
|
GIB_String_Equal_f (void)
|
|
{
|
|
if (GIB_Argc() != 3)
|
|
Cbuf_Error ("syntax",
|
|
"string.length: invalid syntax\n"
|
|
"usage: string.equal string1 string2");
|
|
else
|
|
GIB_Return (va("%i", !strcmp(GIB_Argv(1), GIB_Argv(2))));
|
|
}
|
|
|
|
void
|
|
GIB_Builtin_Init (void)
|
|
{
|
|
gib_globals = Hash_NewTable (512, GIB_Var_Get_Key, GIB_Var_Free, 0);
|
|
|
|
GIB_Builtin_Add ("function", GIB_Function_f, GIB_BUILTIN_NORMAL);
|
|
GIB_Builtin_Add ("function.get", GIB_FunctionDotGet_f, GIB_BUILTIN_NORMAL);
|
|
GIB_Builtin_Add ("export", GIB_Export_f, GIB_BUILTIN_NORMAL);
|
|
GIB_Builtin_Add ("local", GIB_Local_f, GIB_BUILTIN_NORMAL);
|
|
GIB_Builtin_Add ("global", GIB_Global_f, GIB_BUILTIN_NORMAL);
|
|
GIB_Builtin_Add ("return", GIB_Return_f, GIB_BUILTIN_NORMAL);
|
|
GIB_Builtin_Add ("if", GIB_If_f, GIB_BUILTIN_FIRSTONLY);
|
|
GIB_Builtin_Add ("ifnot", GIB_If_f, GIB_BUILTIN_FIRSTONLY);
|
|
GIB_Builtin_Add ("while", GIB_While_f, GIB_BUILTIN_NOPROCESS);
|
|
GIB_Builtin_Add ("break", GIB_Break_f, GIB_BUILTIN_NORMAL);
|
|
GIB_Builtin_Add ("string.length", GIB_String_Length_f, GIB_BUILTIN_NORMAL);
|
|
GIB_Builtin_Add ("string.equal", GIB_String_Equal_f, GIB_BUILTIN_NORMAL);
|
|
}
|