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