1 /*
2 	#FILENAME#
3 
4 	#DESCRIPTION#
5 
6 	Copyright (C) 2002 #AUTHOR#
7 
8 	Author: #AUTHOR#
9 	Date: #DATE#
10 
11 	This program is free software; you can redistribute it and/or
12 	modify it under the terms of the GNU General Public License
13 	as published by the Free Software Foundation; either version 2
14 	of the License, or (at your option) any later version.
15 
16 	This program is distributed in the hope that it will be useful,
17 	but WITHOUT ANY WARRANTY; without even the implied warranty of
18 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 
20 	See the GNU General Public License for more details.
21 
22 	You should have received a copy of the GNU General Public License
23 	along with this program; if not, write to:
24 
25 		Free Software Foundation, Inc.
26 		59 Temple Place - Suite 330
27 		Boston, MA  02111-1307, USA
28 
29 */
30 
31 #ifdef HAVE_CONFIG_H
32 # include "config.h"
33 #endif
34 
35 #include <ctype.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <sys/types.h>
39 #include <dirent.h>
40 #include <fnmatch.h>
41 #include <errno.h>
42 
43 #include "QF/cvar.h"
44 #include "QF/quakefs.h"
45 #include "QF/zone.h"
46 #include "QF/va.h"
47 #include "QF/sys.h"
48 #include "QF/cmd.h"
49 #include "QF/cbuf.h"
50 #include "QF/hash.h"
51 #include "QF/llist.h"
52 #include "QF/dstring.h"
53 #include "QF/gib.h"
54 
55 #include "regex.h"
56 #include "gib_buffer.h"
57 #include "gib_parse.h"
58 #include "gib_function.h"
59 #include "gib_vars.h"
60 #include "gib_regex.h"
61 #include "gib_thread.h"
62 #include "gib_handle.h"
63 #include "gib_builtin.h"
64 #include "gib_classes.h"
65 
66 static char _gib_null_string[] = "";
67 VISIBLE char * const gib_null_string = _gib_null_string;
68 
69 hashtab_t  *gib_builtins;
70 
71 /*
72 	Hashtable callbacks
73 */
74 static const char *
GIB_Builtin_Get_Key(const void * ele,void * ptr)75 GIB_Builtin_Get_Key (const void *ele, void *ptr)
76 {
77 	return ((gib_builtin_t *) ele)->name;
78 }
79 static void
GIB_Builtin_Free(void * ele,void * ptr)80 GIB_Builtin_Free (void *ele, void *ptr)
81 {
82 	gib_builtin_t *b;
83 
84 	b = (gib_builtin_t *) ele;
85 	free ((void *)b->name);
86 	free (b);
87 }
88 
89 /*
90 	GIB_Builtin_Add
91 
92 	Registers a new builtin GIB command.
93 */
94 
95 VISIBLE void
GIB_Builtin_Add(const char * name,void (* func)(void))96 GIB_Builtin_Add (const char *name, void (*func) (void))
97 {
98 	gib_builtin_t *new;
99 
100 	if (!gib_builtins)
101 		gib_builtins =
102 			Hash_NewTable (1024, GIB_Builtin_Get_Key, GIB_Builtin_Free, 0);
103 
104 	new = calloc (1, sizeof (gib_builtin_t));
105 	new->func = func;
106 	new->name = strdup (name);
107 	Hash_Add (gib_builtins, new);
108 }
109 
110 VISIBLE void
GIB_Builtin_Remove(const char * name)111 GIB_Builtin_Remove (const char *name)
112 {
113 	gib_builtin_t *del;
114 
115 	if ((del = Hash_Del (gib_builtins, name)))
116 		Hash_Free (gib_builtins, del);
117 }
118 
119 VISIBLE qboolean
GIB_Builtin_Exists(const char * name)120 GIB_Builtin_Exists (const char *name)
121 {
122 	return Hash_Find (gib_builtins, name) ? true : false;
123 }
124 
125 /*
126 	GIB_Builtin_Find
127 
128 	Looks up the builtin name in the builtin hash,
129 	returning a pointer to the struct on success,
130 	zero otherwise.
131 */
132 VISIBLE gib_builtin_t *
GIB_Builtin_Find(const char * name)133 GIB_Builtin_Find (const char *name)
134 {
135 	if (!gib_builtins)
136 		return 0;
137 	return (gib_builtin_t *) Hash_Find (gib_builtins, name);
138 }
139 
140 VISIBLE dstring_t *
GIB_Return(const char * str)141 GIB_Return (const char *str)
142 {
143 	dstring_t  *dstr;
144 
145 	if (GIB_DATA (cbuf_active)->waitret) {
146 		dstr = GIB_Buffer_Dsarray_Get (cbuf_active);
147 		dstring_clearstr (dstr);
148 		if (!str)
149 			return dstr;
150 		else
151 			dstring_appendstr (dstr, str);
152 	}
153 	return 0;
154 }
155 
156 VISIBLE void
GIB_Error(const char * type,const char * fmt,...)157 GIB_Error (const char *type, const char *fmt, ...)
158 {
159 	va_list     args;
160 
161 	va_start (args, fmt);
162 	GIB_Buffer_Error (cbuf_active, type, fmt, args);
163 	va_end (args);
164 }
165 
166 /*
167 	GIB Builtin functions
168 
169 	See GIB docs for information.
170 */
171 static void
GIB_Function_f(void)172 GIB_Function_f (void)
173 {
174 	gib_tree_t *program;
175 	gib_function_t *func;
176 	int i;
177 	int argc = GIB_Argc ();
178 
179 	if (argc < 3) {
180 		GIB_USAGE ("name [arg1 arg2 ...] program");
181 	} else {
182 		// Is the function program already tokenized?
183 		if (GIB_Argm (argc-1)->delim != '{') {
184 			// Parse on the fly
185 			if (!(program = GIB_Parse_Lines (GIB_Argv
186 							(argc-1), 0))) {
187 				// Error!
188 				GIB_Error ("ParseError", "Parse error while defining function '%s'.",
189 						   GIB_Argv (1));
190 				return;
191 			}
192 		} else
193 			program = GIB_Argm (argc-1)->children;
194 		func = GIB_Function_Define (GIB_Argv (1), GIB_Argv (argc-1), program,
195 							 GIB_DATA (cbuf_active)->script,
196 							 GIB_DATA (cbuf_active)->globals);
197 		llist_flush (func->arglist);
198 		for (i = 2; i < argc-1; i++)
199 			llist_append (func->arglist, strdup (GIB_Argv(i)));
200 		func->minargs = argc-2;
201 	}
202 }
203 
204 static void
GIB_Function_Get_f(void)205 GIB_Function_Get_f (void)
206 {
207 	if (GIB_Argc () != 2) {
208 		GIB_USAGE ("name");
209 	} else {
210 		gib_function_t *f;
211 
212 		if ((f = GIB_Function_Find (GIB_Argv (1))))
213 			GIB_Return (f->text->str);
214 		else
215 			GIB_Return ("");
216 	}
217 }
218 
219 static void
GIB_Local_f(void)220 GIB_Local_f (void)
221 {
222 	gib_var_t  *var;
223 	unsigned int index;
224 	int i;
225 	static hashtab_t  *zero = 0;
226 
227 	if (GIB_Argc () < 2) {
228 		GIB_USAGE ("var [= value1 value2 ...] || var [var2 var3 ...]");
229 	} else if (!strcmp (GIB_Argv(2), "=")) {
230 		var = GIB_Var_Get_Complex (&GIB_DATA (cbuf_active)->locals, &zero,
231 								 GIB_Argv (1), &index, true);
232 		if (GIB_Argc () >= 3)
233 			GIB_Var_Assign (var, index, cbuf_active->args->argv + 3,
234 							GIB_Argc () - 3, GIB_Argv (1)[strlen (GIB_Argv(1)) - 1] != ']');
235 		if (GIB_CanReturn ())
236 			for (i = 3; i < GIB_Argc(); i++)
237 				GIB_Return (GIB_Argv(i));
238 	} else for (i = 1; i < GIB_Argc(); i++)
239 		var = GIB_Var_Get_Complex (&GIB_DATA (cbuf_active)->locals, &zero,
240 								 GIB_Argv (i), &index, true);
241 }
242 
243 
244 static void
GIB_Shared_f(void)245 GIB_Shared_f (void)
246 {
247 	gib_var_t  *var;
248 	unsigned int index;
249 	int i;
250 	static hashtab_t  *zero = 0;
251 
252 	if (GIB_Argc () < 2) {
253 		GIB_USAGE ("var [= value1 value2 ...] || var [var2 var3 ...]");
254 	} else if (!strcmp (GIB_Argv(2), "=")) {
255 		var = GIB_Var_Get_Complex (&GIB_DATA (cbuf_active)->globals, &zero,
256 								 GIB_Argv (1), &index, true);
257 		if (GIB_Argc () >= 3)
258 			GIB_Var_Assign (var, index, cbuf_active->args->argv + 3,
259 							GIB_Argc () - 3, GIB_Argv (1)[strlen (GIB_Argv(1)) - 1] != ']');
260 		if (GIB_CanReturn ())
261 			for (i = 3; i < GIB_Argc(); i++)
262 				GIB_Return (GIB_Argv(i));
263 	} else for (i = 1; i < GIB_Argc(); i++)
264 		var = GIB_Var_Get_Complex (&GIB_DATA (cbuf_active)->globals, &zero,
265 								 GIB_Argv (i), &index, true);
266 }
267 
268 static void
GIB_Delete_f(void)269 GIB_Delete_f (void)
270 {
271 	gib_var_t *var;
272 	unsigned int index;
273 	int i;
274 	hashtab_t *source;
275 	char *c;
276 
277 	if (GIB_Argc () < 2) {
278 		GIB_USAGE ("var [var2 var2 ...]");
279 	} else for (i = 1; i < GIB_Argc(); i++) {
280 		if ((c = strrchr (GIB_Argv(i), '.'))) {
281 			*(c++) = 0;
282 			if (!(var = GIB_Var_Get_Complex (&GIB_DATA (cbuf_active)->locals,
283 								&GIB_DATA(cbuf_active)->globals,
284 								 GIB_Argv (i), &index, false)))
285 				continue;
286 			source = var->array[index].leaves;
287 		} else {
288 			c = GIB_Argv(i);
289 			source = GIB_DATA(cbuf_active)->globals;
290 		}
291 		Hash_Free (source, Hash_Del (source, c));
292 	}
293 }
294 
295 static void
GIB_Domain_f(void)296 GIB_Domain_f (void)
297 {
298 	if (GIB_Argc () != 2)
299 		GIB_USAGE ("domain");
300 	else
301 		GIB_DATA (cbuf_active)->globals = GIB_Domain_Get (GIB_Argv (1));
302 }
303 
304 static void
GIB_Domain_Clear_f(void)305 GIB_Domain_Clear_f (void)
306 {
307 	if (GIB_Argc () != 2)
308 		GIB_USAGE ("domain");
309 	else
310 		Hash_FlushTable (GIB_Domain_Get (GIB_Argv (2)));
311 }
312 
313 static gib_tree_t fakeip = {0,0,0,0,0,0,0,0};
314 
315 static void
GIB_Return_f(void)316 GIB_Return_f (void)
317 {
318 	cbuf_t     *sp = cbuf_active->up;
319 
320 	GIB_DATA (cbuf_active)->ip = &fakeip;
321 
322 	if (GIB_DATA (cbuf_active)->reply.obj) {
323 		gib_buffer_data_t *g = GIB_DATA (cbuf_active);
324 		const char **argv = malloc (sizeof (char *) * GIB_Argc() -1);
325 		int i;
326 
327 		for (i = 1; i < GIB_Argc(); i++)
328 			argv[i-1] = GIB_Argv(i);
329 
330 		GIB_Reply (g->reply.obj, g->reply.mesg, GIB_Argc()-1, argv);
331 		free ((void*)argv);
332 		g->dnotify = NULL;
333 	} else if (GIB_Argc () > 1 && sp && sp->interpreter == &gib_interp
334 		&& GIB_DATA (sp)->waitret) {
335 		int i;
336 		dstring_t  *dstr;
337 
338 		for (i = 1; i < GIB_Argc (); i++) {
339 			dstr = GIB_Buffer_Dsarray_Get (sp);
340 			dstring_clearstr (dstr);
341 			dstring_appendstr (dstr, GIB_Argv (i));
342 		}
343 	}
344 }
345 
346 static void
GIB_For_f(void)347 GIB_For_f (void)
348 {
349 	dstring_t  *dstr;
350 	int i;
351 
352 	GIB_Buffer_Push_Sstack (cbuf_active);
353 	dstr = GIB_Buffer_Dsarray_Get (cbuf_active);
354 	dstring_clearstr (dstr);
355 	dstring_appendstr (dstr, GIB_Argv (1));
356 	for (i = GIB_Argc () - 2; i > 2; i--) {
357 		dstr = GIB_Buffer_Dsarray_Get (cbuf_active);
358 		dstring_appendstr (dstr, GIB_Argv (i));
359 	}
360 }
361 
362 // Note: this is a standard console command, not a GIB builtin
363 static void
GIB_Runexported_f(void)364 GIB_Runexported_f (void)
365 {
366 	gib_function_t *f;
367 	const char **args;
368 
369 	if (!(f = GIB_Function_Find (Cmd_Argv (0)))) {
370 		Sys_Printf ("Error:  No function found for exported command \"%s\".\n"
371 					"This is most likely a bug, please report it to"
372 					"The QuakeForge developers.", Cmd_Argv (0));
373 	} else {
374 		cbuf_t     *sub = Cbuf_PushStack (&gib_interp);
375 		int i;
376 
377 		args = malloc (sizeof (char *) * Cmd_Argc());
378 		for (i = 0; i < Cmd_Argc(); i++)
379 			args[i] = Cmd_Argv(i);
380 		GIB_Function_Execute (sub, f, args, Cmd_Argc());
381 		free ((void*)args);
382 	}
383 }
384 
385 static void
GIB_Function_Export_f(void)386 GIB_Function_Export_f (void)
387 {
388 	gib_function_t *f;
389 	int         i;
390 
391 	if (GIB_Argc () < 2)
392 		GIB_USAGE ("function1 [function2 function3 ...]");
393 	for (i = 1; i < GIB_Argc (); i++) {
394 		if (!(f = GIB_Function_Find (GIB_Argv (i))))
395 			GIB_Error ("UnknownFunctionError", "%s: function '%s' not found.", GIB_Argv (0),
396 					   GIB_Argv (i));
397 		else if (!f->exported) {
398 			if (Cmd_Exists (f->name)) {
399 				GIB_Error ("NameConflictError",
400 						   "%s: A console command with the name '%s' already exists.",
401 						   GIB_Argv (0), GIB_Argv (i));
402 				return;
403 			} else {
404 				Cmd_AddCommand (f->name, GIB_Runexported_f,
405 								"Exported GIB function.");
406 				f->exported = true;
407 			}
408 		}
409 	}
410 }
411 
412 static void
GIB_Length_f(void)413 GIB_Length_f (void)
414 {
415 	dstring_t  *ret;
416 
417 	if (GIB_Argc () != 2)
418 		GIB_USAGE ("string");
419 	else if ((ret = GIB_Return (0)))
420 		dsprintf (ret, "%i", (int) strlen (GIB_Argv (1)));
421 }
422 
423 static void
GIB_Equal_f(void)424 GIB_Equal_f (void)
425 {
426 	if (GIB_Argc () != 3)
427 		GIB_USAGE ("string1 string2");
428 	else if (strcmp (GIB_Argv (1), GIB_Argv (2)))
429 		GIB_Return ("0");
430 	else
431 		GIB_Return ("1");
432 }
433 
434 static void
GIB_Count_f(void)435 GIB_Count_f (void)
436 {
437 	if (GIB_CanReturn())
438 		dsprintf (GIB_Return(0), "%u", GIB_Argc() - 1);
439 }
440 
441 
442 static void
GIB_Contains_f(void)443 GIB_Contains_f (void)
444 {
445 	int i;
446 	if (GIB_Argc () < 2)
447 		GIB_USAGE ("needle [straw1 straw2 ...]");
448 	else if (GIB_CanReturn ())
449 		for (i = 2; i < GIB_Argc(); i++)
450 			if (!strcmp(GIB_Argv(1), GIB_Argv(i))) {
451 				GIB_Return("1");
452 				return;
453 			}
454 	GIB_Return ("0");
455 }
456 
457 static void
GIB_Slice_f(void)458 GIB_Slice_f (void)
459 {
460 	dstring_t  *ret;
461 	int         start, end, len;
462 
463 	if (GIB_Argc () < 3 || GIB_Argc () > 4) {
464 		GIB_USAGE ("string start [end]");
465 	} else {
466 		len = strlen (GIB_Argv (1));
467 		start = atoi (GIB_Argv (2));
468 		end = *GIB_Argv (3) ? atoi (GIB_Argv (3)) : len;
469 		if (end < 0)
470 			end += len;
471 		else if (end > len)
472 			end = len;
473 		if (start < 0) {
474 			start += len;
475 			if (start < 0)
476 				start = 0;
477 		} else if (start >= len || start >= end)
478 			return;
479 		if ((ret = GIB_Return (0)))
480 			dstring_appendsubstr (ret, GIB_Argv (1) + start, end - start);
481 	}
482 }
483 
484 
485 static void
GIB_Slice_Find_f(void)486 GIB_Slice_Find_f (void)
487 {
488 	char       *res;
489 
490 	if (GIB_Argc () != 3) {
491 		GIB_USAGE ("haystack needle");
492 		return;
493 	} else if (!GIB_CanReturn ()) {
494 		return;
495 	} else if ((res = strstr (GIB_Argv (1), GIB_Argv (2)))) {
496 		dsprintf (GIB_Return (0), "%lu",
497 				  (unsigned long int) (res - GIB_Argv (1)));
498 		dsprintf (GIB_Return (0), "%lu",
499 				  (unsigned long int) (res - GIB_Argv (1) +
500 									   strlen (GIB_Argv (2))));
501 	}
502 }
503 
504 
505 static void
GIB_Split_f(void)506 GIB_Split_f (void)
507 {
508 	char       *end, *start;
509 	const char *ifs;
510 
511 	if (GIB_Argc () < 2 || GIB_Argc () > 3) {
512 		GIB_USAGE ("string [fs]");
513 		return;
514 	}
515 
516 	ifs = GIB_Argc () == 3 ? GIB_Argv (2) : " \t\r\n";
517 
518 	end = GIB_Argv (1);
519 	while (*end) {
520 		for (; strchr (ifs, *end); end++)
521 			if (!*end)
522 				return;
523 		start = end;
524 		while (!strchr (ifs, *end))
525 			end++;
526 		if (*end)
527 			*(end++) = 0;
528 		GIB_Return (start);
529 	}
530 }
531 
532 static void
GIB_Chomp_f(void)533 GIB_Chomp_f (void)
534 {
535 	char *str;
536 	const char *junk;
537 	unsigned int i;
538 
539 	if (GIB_Argc () < 2 || GIB_Argc () > 3) {
540 		GIB_USAGE ("string [junk]");
541 		return;
542 	}
543 
544 	str = GIB_Argv (1);
545 	if (GIB_Argc () == 2)
546 		junk = " \t\n\r";
547 	else
548 		junk = GIB_Argv (2);
549 
550 	for (; *str && strchr (junk, *str); str++);
551 	for (i = strlen(str) - 1; i && strchr (junk, str[i]); i--);
552 	str[i+1] = 0;
553 	GIB_Return (str);
554 }
555 
556 static void
GIB_Regex_Match_f(void)557 GIB_Regex_Match_f (void)
558 {
559 	regex_t    *reg;
560 
561 	if (GIB_Argc () != 4) {
562 		GIB_USAGE ("string regex options");
563 		return;
564 	}
565 
566 	if (!(reg =  GIB_Regex_Compile (GIB_Argv (2), REG_EXTENDED |
567 					GIB_Regex_Translate_Options (GIB_Argv (3)))))
568 		GIB_Error ("RegexError", "%s: %s", GIB_Argv (0), GIB_Regex_Error ());
569 	else if (regexec (reg, GIB_Argv (1), 0, 0, GIB_Regex_Translate_Runtime_Options (GIB_Argv (3))))
570 		GIB_Return ("0");
571 	else
572 		GIB_Return ("1");
573 }
574 
575 static void
GIB_Regex_Replace_f(void)576 GIB_Regex_Replace_f (void)
577 {
578 	regex_t    *reg;
579 	int         ofs;
580 	regmatch_t  match[10];
581 
582 	if (GIB_Argc () != 5) {
583 		GIB_USAGE ("string regex options replacement");
584 		return;
585 	}
586 
587 	ofs = 0;
588 
589 	if (!
590 		(reg =
591 		 GIB_Regex_Compile (GIB_Argv (2),
592 							REG_EXTENDED |
593 							GIB_Regex_Translate_Options (GIB_Argv (3)))))
594 		GIB_Error ("RegexError", "%s: %s", GIB_Argv (0), GIB_Regex_Error ());
595 	else if (strchr (GIB_Argv (3), 'g'))
596 		while (!regexec
597 			   (reg, GIB_Argv (1) + ofs, 10, match, ofs > 0 ? REG_NOTBOL : 0)
598 			   && match[0].rm_eo)
599 			ofs +=
600 				GIB_Regex_Apply_Match (match, GIB_Argd (1), ofs, GIB_Argv (4));
601 	else if (!regexec (reg, GIB_Argv (1), 10, match, GIB_Regex_Translate_Runtime_Options (GIB_Argv (3))) && match[0].rm_eo)
602 		GIB_Regex_Apply_Match (match, GIB_Argd (1), 0, GIB_Argv (4));
603 	GIB_Return (GIB_Argv (1));
604 }
605 
606 static void
GIB_Regex_Extract_f(void)607 GIB_Regex_Extract_f (void)
608 {
609 	regex_t    *reg;
610 	regmatch_t *match;
611 	int         i;
612 	char        o;
613 
614 	if (GIB_Argc () != 4) {
615 		GIB_USAGE ("string regex options");
616 		return;
617 	} else if (!GIB_CanReturn ())
618 		return;
619 	match = calloc (32, sizeof (regmatch_t));
620 
621 	if (!
622 		(reg =
623 		 GIB_Regex_Compile (GIB_Argv (2),
624 							REG_EXTENDED |
625 							GIB_Regex_Translate_Options (GIB_Argv (3)))))
626 		GIB_Error ("RegexError", "%s: %s", GIB_Argv (0), GIB_Regex_Error ());
627 	else if (!regexec (reg, GIB_Argv (1), 32, match, GIB_Regex_Translate_Runtime_Options (GIB_Argv (3))) && match[0].rm_eo) {
628 		dsprintf (GIB_Return (0), "%lu", (unsigned long) match[0].rm_eo);
629 		for (i = 0; i < 32; i++) {
630 			if (match[i].rm_so != -1) {
631 				o = GIB_Argv (1)[match[i].rm_eo];
632 				GIB_Argv (1)[match[i].rm_eo] = 0;
633 				GIB_Return (GIB_Argv (1) + match[i].rm_so);
634 				GIB_Argv (1)[match[i].rm_eo] = o;
635 			}
636 		}
637 	}
638 	free (match);
639 }
640 
641 static void
GIB_Text_White_f(void)642 GIB_Text_White_f (void)
643 {
644 	if (GIB_Argc () != 2)
645 		GIB_USAGE ("text");
646 	else if (GIB_CanReturn ()) {
647 		unsigned int i;
648 		dstring_t *dstr;
649 		char *str;
650 
651 		dstr = GIB_Return (0);
652 		dstring_appendstr (dstr, GIB_Argv(1));
653 		str = dstr->str;
654 
655 		for (i = 0; i < dstr->size-1; i++)
656 			str[i] = str[i] & ~0x80;
657 	}
658 }
659 
660 static void
GIB_Text_Brown_f(void)661 GIB_Text_Brown_f (void)
662 {
663 	if (GIB_Argc () != 2)
664 		GIB_USAGE ("text");
665 	else if (GIB_CanReturn ()) {
666 		unsigned int i;
667 		dstring_t *dstr;
668 		char *str;
669 
670 		dstr = GIB_Return (0);
671 		dstring_appendstr (dstr, GIB_Argv(1));
672 		str = dstr->str;
673 
674 		for (i = 0; i < dstr->size-1; i++)
675 			str[i] = str[i] | 0x80;
676 	}
677 }
678 
679 /*
680 static void
681 GIB_Text_To_Gold_f (void)
682 {
683 	if (GIB_Argc () != 2)
684 		GIB_USAGE ("text");
685 	else if (GIB_CanReturn ()) {
686 		dstring_t *dstr;
687 		char *str;
688 
689 		dstr = GIB_Return (0);
690 		dstring_copystr (dstr, GIB_Argv(1));
691 
692 		for (str = dstr->str; *str; str++) {
693 			switch (*str) {
694 */
695 
696 static void
GIB_Text_To_Decimal_f(void)697 GIB_Text_To_Decimal_f (void)
698 {
699 	if (GIB_Argc () != 2)
700 		GIB_USAGE ("text");
701 	else if (GIB_CanReturn ()) {
702 		char *str;
703 
704 		for (str = GIB_Argv(1); *str; str++)
705 			dsprintf (GIB_Return (0), "%i", (int) *str);
706 	}
707 }
708 
709 static void
GIB_Text_From_Decimal_f(void)710 GIB_Text_From_Decimal_f (void)
711 {
712 	if (GIB_Argc () < 2)
713 		GIB_USAGE ("num1 [...]");
714 	else if (GIB_CanReturn ()) {
715 		int i;
716 		dstring_t *dstr;
717 		char *str;
718 
719 		dstr = GIB_Return (0);
720 		dstr->size = GIB_Argc();
721 		dstring_adjust (dstr);
722 
723 		str = dstr->str;
724 
725 		for (i = 1; i < GIB_Argc(); i++, str++)
726 			*str = (char) atoi (GIB_Argv(i));
727 		*str = 0;
728 	}
729 }
730 
731 static void
GIB_Event_Register_f(void)732 GIB_Event_Register_f (void)
733 {
734 	gib_function_t *func;
735 
736 	if (GIB_Argc () != 3)
737 		GIB_USAGE ("event function");
738 	else if (!(func = GIB_Function_Find (GIB_Argv (2))) && GIB_Argv (2)[0])
739 		GIB_Error ("UnknownFunctionError", "Function %s not found.", GIB_Argv (2));
740 	else if (GIB_Event_Register (GIB_Argv (1), func))
741 		GIB_Error ("UnknownEventError", "Event %s not found.", GIB_Argv (1));
742 }
743 
744 /* File access */
745 
746 static int   (*GIB_File_Transform_Path) (dstring_t * path) = NULL;
747 
748 static int
GIB_File_Transform_Path_Null(dstring_t * path)749 GIB_File_Transform_Path_Null (dstring_t * path)
750 {
751 	char       *s;
752 
753 	// Convert backslash to forward slash
754 	for (s = strchr (path->str, '\\'); s; s = strchr (s, '\\'))
755 		*s = '/';
756 	return 0;
757 }
758 
759 static int
GIB_File_Transform_Path_Secure(dstring_t * path)760 GIB_File_Transform_Path_Secure (dstring_t * path)
761 {
762 	char       *s;
763 
764 	for (s = strchr (path->str, '\\'); s; s = strchr (s, '\\'))
765 		*s = '/';
766 
767 	if (path->str[0] != '/')
768 		dstring_insertstr (path, 0, "/");
769 	dstring_insertstr (path, 0, qfs_gamedir->dir.def);
770 	dstring_insertstr (path, 0, "/");
771 	dstring_insertstr (path, 0, qfs_userpath);
772 	return 0;
773 }
774 
775 static void
GIB_File_Read_f(void)776 GIB_File_Read_f (void)
777 {
778 	QFile      *file;
779 	char       *path;
780 	int         len;
781 	dstring_t  *ret;
782 
783 	if (GIB_Argc () != 2) {
784 		GIB_USAGE ("file");
785 		return;
786 	}
787 	if (!*GIB_Argv (1)) {
788 		GIB_Error ("FileAccessError", "%s: null filename provided", GIB_Argv (0));
789 		return;
790 	}
791 
792 	if (!(ret = GIB_Return (0)))
793 		return;
794 	path = GIB_Argv (1);
795 	QFS_FOpenFile (path, &file);
796 	if (file) {
797 		len = Qfilesize (file);
798 		ret->size = len + 1;
799 		dstring_adjust (ret);
800 		Qread (file, ret->str, len);
801 		ret->str[len] = 0;
802 		Qclose (file);
803 	} else {
804 		GIB_Error ("FileAccessError",
805 				   "%s: could not read %s: %s", GIB_Argv (0), path,
806 				   strerror (errno));
807 		return;
808 	}
809 }
810 
811 static void
GIB_File_Write_f(void)812 GIB_File_Write_f (void)
813 {
814 	char       *path;
815 
816 	if (GIB_Argc () != 3) {
817 		GIB_USAGE ("file data");
818 		return;
819 	}
820 	if (!*GIB_Argv (1)) {
821 		GIB_Error ("InvalidArgumentError", "%s: null filename provided", GIB_Argv (0));
822 		return;
823 	}
824 
825 	path = GIB_Argv (1);
826 	QFS_WriteFile (va ("%s/%s", qfs_gamedir->dir.def, path),
827 				   GIB_Argv(2), GIB_Argd(2)->size-1);
828 }
829 
830 static void
GIB_File_Find_f(void)831 GIB_File_Find_f (void)
832 {
833 	DIR        *directory;
834 	struct dirent *entry;
835 	const char *path, *glob = 0;
836 	char       *s;
837 
838 	if (GIB_Argc () != 2) {
839 		GIB_USAGE ("glob");
840 		return;
841 	}
842 	if (GIB_File_Transform_Path (GIB_Argd (1))) {
843 		GIB_Error ("FileAccessError",
844 				   "%s: access to %s denied", GIB_Argv (0), GIB_Argv (1));
845 		return;
846 	}
847 	path = GIB_Argv (1);
848 	s = strrchr (path, '/');
849 	if (!s) {							// No slash in path
850 		glob = path;					// The glob is the entire argument
851 		path = ".";						// The path is the current directory
852 	} else if (s == path)				// Unix filesystem root (carne only)
853 		path = "/";
854 	else {
855 		*s = 0;							// Split the string at the final slash
856 		glob = s + 1;
857 	}
858 	directory = opendir (path);
859 	if (!directory)
860 		return;
861 	while ((entry = readdir (directory)))
862 		if (strcmp (entry->d_name, ".") && strcmp (entry->d_name, "..")
863 			&& !fnmatch (glob, entry->d_name, 0))
864 			GIB_Return (entry->d_name);
865 	closedir (directory);
866 }
867 
868 static void
GIB_File_Move_f(void)869 GIB_File_Move_f (void)
870 {
871 	char       *path1, *path2;
872 
873 	if (GIB_Argc () != 3) {
874 		GIB_USAGE ("from_file to_file");
875 		return;
876 	}
877 	if (GIB_File_Transform_Path (GIB_Argd (1))) {
878 		GIB_Error ("FileAccessError",
879 				   "%s: access to %s denied", GIB_Argv (0), GIB_Argv (1));
880 		return;
881 	}
882 	if (GIB_File_Transform_Path (GIB_Argd (2))) {
883 		GIB_Error ("FileAccessError",
884 				   "%s: access to %s denied", GIB_Argv (0), GIB_Argv (2));
885 		return;
886 	}
887 	path1 = GIB_Argv (1);
888 	path2 = GIB_Argv (2);
889 	if (QFS_Rename (path1, path2))
890 		GIB_Error ("FileAccessError", "%s: could not move %s to %s: %s", GIB_Argv (0),
891 				   path1, path2, strerror (errno));
892 }
893 
894 static void
GIB_File_Delete_f(void)895 GIB_File_Delete_f (void)
896 {
897 	char       *path;
898 
899 	if (GIB_Argc () != 2) {
900 		GIB_USAGE ("file");
901 		return;
902 	}
903 	if (GIB_File_Transform_Path (GIB_Argd (1))) {
904 		GIB_Error ("FileAccessError",
905 				   "%s: access to %s denied", GIB_Argv (0), GIB_Argv (1));
906 		return;
907 	}
908 	path = GIB_Argv (1);
909 	if (QFS_Remove (path))
910 		GIB_Error ("FileAccessError", "%s: could not delete %s: %s", GIB_Argv (0), path,
911 				   strerror (errno));
912 }
913 
914 static void
GIB_Range_f(void)915 GIB_Range_f (void)
916 {
917 	double      i, inc, start, limit;
918 	dstring_t  *dstr;
919 
920 	if (GIB_Argc () < 3 || GIB_Argc () > 4) {
921 		GIB_USAGE ("lower upper [step]");
922 		return;
923 	}
924 	limit = atof (GIB_Argv (2));
925 	start = atof (GIB_Argv (1));
926 	if (GIB_Argc () == 4) {
927 		if ((inc = atof (GIB_Argv (3))) == 0.0)
928 			return;
929 	} else
930 		inc = limit < start ? -1.0 : 1.0;
931 	for (i = atof (GIB_Argv (1)); inc < 0 ? i >= limit : i <= limit; i += inc) {
932 		if (!(dstr = GIB_Return (0)))
933 			return;
934 		dsprintf (dstr, "%.10g", i);
935 	}
936 }
937 
938 static void
GIB_Print_f(void)939 GIB_Print_f (void)
940 {
941 	if (GIB_Argc () != 2) {
942 		GIB_USAGE ("text");
943 		return;
944 	}
945 	Sys_Printf ("%s", GIB_Argv (1));
946 }
947 
948 static void
GIB_Class_f(void)949 GIB_Class_f (void)
950 {
951 	if (GIB_Object_Get (GIB_Argv(1))) {
952 		GIB_Error ("ClassRedefinitionError",
953 				"Class '%s' already exists", GIB_Argv(1));
954 	} else if (GIB_Argc () == 5)
955 		GIB_Classes_Build_Scripted (GIB_Argv(1), GIB_Argv(3),
956 				GIB_Argm (4)->children,
957 				GIB_DATA(cbuf_active)->script);
958 	else
959 		GIB_Classes_Build_Scripted (GIB_Argv(1), "Object",
960 				GIB_Argm (2)->children,
961 				GIB_DATA(cbuf_active)->script);
962 }
963 
964 static void
GIB_Emit_f(void)965 GIB_Emit_f (void)
966 {
967 	if (GIB_Argc () < 2) {
968 		GIB_USAGE ("signal [arg1 arg2 ...]");
969 		return;
970 	} else if (!GIB_DATA(cbuf_active)->reply.obj) {
971 		GIB_Error ("InvalidContextError", "Cannot emit signal in this context.");
972 		return;
973 	} else {
974 		int i;
975 		const char **argv = malloc (GIB_Argc () - 1);
976 
977 		for (i = 1; i < GIB_Argc (); i ++)
978 			argv[i-1] = GIB_Argv (1);
979 
980 		GIB_Object_Signal_Emit (GIB_DATA(cbuf_active)->reply.obj,
981 				GIB_Argc () - 1, argv);
982 
983 		free ((void*)argv);
984 	}
985 }
986 
987 static void
GIB_Exists_f(void)988 GIB_Exists_f (void)
989 {
990 	if (GIB_Object_Get (GIB_Argv (1)))
991 		GIB_Return ("1");
992 	else
993 		GIB_Return ("0");
994 }
995 
996 static void
GIB_Error_f(void)997 GIB_Error_f (void)
998 {
999 	if (GIB_Argc() < 3) {
1000 		GIB_USAGE ("error_type explanation");
1001 		return;
1002 	} else
1003 		GIB_Error (GIB_Argv(1), "%s", GIB_Argv(2));
1004 }
1005 
1006 /*
1007 static void
1008 GIB_New_f (void)
1009 {
1010 	GIB_Object_t *classobj;
1011 	if (GIB_Argc() < 2) {
1012 		GIB_USAGE ("classname");
1013 	} else if (
1014 			   !(class = GIB_Object_Get(GIB_Argv(1)))
1015 			|| classobj->class->classobj != classobj) {
1016 		GIB_Error ("UnknownClassError", "Class '%s' does not exist",
1017 				GIB_Argv(1));
1018 	} else {
1019 		GIB_Send (classobj,
1020 */
1021 
1022 static void
GIB_bp1_f(void)1023 GIB_bp1_f (void)
1024 {
1025 }
1026 
1027 static void
GIB_bp2_f(void)1028 GIB_bp2_f (void)
1029 {
1030 }
1031 
1032 static void
GIB_bp3_f(void)1033 GIB_bp3_f (void)
1034 {
1035 }
1036 
1037 static void
GIB_bp4_f(void)1038 GIB_bp4_f (void)
1039 {
1040 }
1041 
1042 void
GIB_Builtin_Init(qboolean sandbox)1043 GIB_Builtin_Init (qboolean sandbox)
1044 {
1045 
1046 	if (sandbox)
1047 		GIB_File_Transform_Path = GIB_File_Transform_Path_Secure;
1048 	else
1049 		GIB_File_Transform_Path = GIB_File_Transform_Path_Null;
1050 
1051 	GIB_Builtin_Add ("function", GIB_Function_f);
1052 	GIB_Builtin_Add ("function::get", GIB_Function_Get_f);
1053 	GIB_Builtin_Add ("function::export", GIB_Function_Export_f);
1054 	GIB_Builtin_Add ("local", GIB_Local_f);
1055 	GIB_Builtin_Add ("shared", GIB_Shared_f);
1056 	GIB_Builtin_Add ("global", GIB_Shared_f);
1057 	GIB_Builtin_Add ("delete", GIB_Delete_f);
1058 	GIB_Builtin_Add ("domain", GIB_Domain_f);
1059 	GIB_Builtin_Add ("domain::clear", GIB_Domain_Clear_f);
1060 	GIB_Builtin_Add ("return", GIB_Return_f);
1061 	GIB_Builtin_Add ("for", GIB_For_f);
1062 	GIB_Builtin_Add ("length", GIB_Length_f);
1063 	GIB_Builtin_Add ("equal", GIB_Equal_f);
1064 	GIB_Builtin_Add ("count", GIB_Count_f);
1065 	GIB_Builtin_Add ("contains", GIB_Contains_f);
1066 	GIB_Builtin_Add ("slice", GIB_Slice_f);
1067 	GIB_Builtin_Add ("slice::find", GIB_Slice_Find_f);
1068 	GIB_Builtin_Add ("split", GIB_Split_f);
1069 	GIB_Builtin_Add ("chomp", GIB_Chomp_f);
1070 	GIB_Builtin_Add ("regex::match", GIB_Regex_Match_f);
1071 	GIB_Builtin_Add ("regex::replace", GIB_Regex_Replace_f);
1072 	GIB_Builtin_Add ("regex::extract", GIB_Regex_Extract_f);
1073 	GIB_Builtin_Add ("text::toWhite", GIB_Text_White_f);
1074 	GIB_Builtin_Add ("text::toBrown", GIB_Text_Brown_f);
1075 	GIB_Builtin_Add ("text::toDecimal", GIB_Text_To_Decimal_f);
1076 	GIB_Builtin_Add ("text::fromDecimal", GIB_Text_From_Decimal_f);
1077 	GIB_Builtin_Add ("event::register", GIB_Event_Register_f);
1078 	GIB_Builtin_Add ("file::read", GIB_File_Read_f);
1079 	GIB_Builtin_Add ("file::write", GIB_File_Write_f);
1080 	GIB_Builtin_Add ("file::find", GIB_File_Find_f);
1081 	GIB_Builtin_Add ("file::move", GIB_File_Move_f);
1082 	GIB_Builtin_Add ("file::delete", GIB_File_Delete_f);
1083 	GIB_Builtin_Add ("range", GIB_Range_f);
1084 	GIB_Builtin_Add ("print", GIB_Print_f);
1085 	GIB_Builtin_Add ("class", GIB_Class_f);
1086 	GIB_Builtin_Add ("emit", GIB_Emit_f);
1087 	GIB_Builtin_Add ("exists", GIB_Exists_f);
1088 	GIB_Builtin_Add ("error", GIB_Error_f);
1089 	GIB_Builtin_Add ("bp1", GIB_bp1_f);
1090 	GIB_Builtin_Add ("bp2", GIB_bp2_f);
1091 	GIB_Builtin_Add ("bp3", GIB_bp3_f);
1092 	GIB_Builtin_Add ("bp4", GIB_bp4_f);
1093 }
1094