1 /*
2 * alias.c -- Handles the whole kit and caboodle for aliases.
3 *
4 * Copyright (c) 1990 Michael Sandroff.
5 * Copyright (c) 1991, 1992 Troy Rollo.
6 * Copyright (c) 1992-1996 Matthew Green.
7 * Copyright 1997, 2014 EPIC Software Labs
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notices, the above paragraph (the one permitting redistribution),
17 * this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. The names of the author(s) may not be used to endorse or promote
20 * products derived from this software without specific prior written
21 * permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #define __need_cs_alist_hash__
37 #include "irc.h"
38 #define __need_ArgList_t__
39 #include "alias.h"
40 #include "alist.h"
41 #include "array.h"
42 #include "commands.h"
43 #include "files.h"
44 #include "hook.h"
45 #include "input.h"
46 #include "ircaux.h"
47 #include "output.h"
48 #include "screen.h"
49 #include "stack.h"
50 #include "status.h"
51 #include "vars.h"
52 #include "window.h"
53 #include "keys.h"
54 #include "functions.h"
55 #include "words.h"
56 #include "reg.h"
57 #include "vars.h"
58 #include "timer.h"
59
60 #define LEFT_BRACE '{'
61 #define RIGHT_BRACE '}'
62 #define LEFT_BRACKET '['
63 #define RIGHT_BRACKET ']'
64 #define LEFT_PAREN '('
65 #define RIGHT_PAREN ')'
66 #define DOUBLE_QUOTE '"'
67
68 /**************************** INTERMEDIATE INTERFACE *********************/
69 /* Just doing some changes for hooks */
70 /*
71 enum ARG_TYPES {
72 WORD,
73 UWORD,
74 DWORD,
75 QWORD
76 };
77 */
78 /* Ugh. XXX Bag on the side */
79 /*
80 struct ArgListT {
81 char * vars[32];
82 char * defaults[32];
83 int words[32];
84 enum ARG_TYPES types[32];
85 int void_flag;
86 int dot_flag;
87 };
88 typedef struct ArgListT ArgList;
89 ArgList *parse_arglist (char *arglist);
90 void destroy_arglist (ArgList **);
91 */
92
93 /*
94 * This is the description of an alias entry
95 * This is an ``array_item'' structure
96 */
97 typedef struct SymbolStru
98 {
99 char *name; /* name of alias */
100 u_32int_t hash; /* Hash of the name */
101
102 char * user_variable;
103 int user_variable_stub;
104 char * user_variable_package;
105
106 char * user_command;
107 int user_command_stub;
108 char * user_command_package;
109 ArgList *arglist; /* List of arguments to alias */
110
111 void (*builtin_command) (const char *, char *, const char *);
112 char * (*builtin_function) (char *);
113 char * (*builtin_expando) (void);
114 IrcVariable * builtin_variable;
115
116 struct SymbolStru * saved; /* For stacks */
117 int saved_hint;
118 } Symbol;
119
120 #define SAVED_VAR 1
121 #define SAVED_CMD 2
122 #define SAVED_BUILTIN_CMD 4
123 #define SAVED_BUILTIN_FUNCTION 8
124 #define SAVED_BUILTIN_EXPANDO 16
125 #define SAVED_BUILTIN_VAR 32
126
127 const char *symbol_types[] = {
128 "ASSIGN", "ALIAS", "BUILTIN_COMMAND",
129 "BUILTIN_FUNCTION", "BUILTIN_EXPANDO", "BUILTIN_VARIABLE",
130 NULL
131 };
132
133 /*
134 * This is the description for a list of aliases
135 * This is an ``array_set'' structure
136 */
137 #define ALIAS_CACHE_SIZE 4
138
139 typedef struct SymbolSetStru
140 {
141 Symbol ** list;
142 int max;
143 int max_alloc;
144 alist_func func;
145 hash_type hash;
146 } SymbolSet;
147
148 static SymbolSet globals = { NULL, 0, 0, strncmp, HASH_INSENSITIVE };
149
150 static Symbol *lookup_symbol (const char *name);
151 static Symbol *find_local_alias (const char *name, SymbolSet **list);
152
153 /*
154 * This is the ``stack frame''. Each frame has a ``name'' which is
155 * the name of the alias or on of the frame, or is NULL if the frame
156 * is not an ``enclosing'' frame. Each frame also has a ``current command''
157 * that is being executed, which is used to help us when the client crashes.
158 * Each stack also contains a list of local variables.
159 */
160 typedef struct RuntimeStackStru
161 {
162 const char *name; /* Name of the stack */
163 char *current; /* Current cmd being executed */
164 SymbolSet alias; /* Local variables */
165 int locked; /* Are we locked in a wait? */
166 int parent; /* Our parent stack frame */
167 } RuntimeStack;
168
169 /*
170 * This is the master stack frame. Its size is saved in ``max_wind''
171 * and the current frame being used is stored in ``wind_index''.
172 */
173 static RuntimeStack *call_stack = NULL;
174 int max_wind = -1;
175 int wind_index = -1;
176
177
178 /*
179 * This is where we keep track of where the last pending function call.
180 * This is used when you assign to the FUNCTION_RETURN value. Since it
181 * is neccesary to be able to access FUNCTION_RETURN in contexts where other
182 * local variables would not be visible, we do this as a quasi-neccesary
183 * hack. When you reference FUNCTION_RETURN, it goes right to this stack.
184 */
185 int last_function_call_level = -1;
186
187 /*
188 * The following actions are supported: add, delete, find, list
189 * On the following types of data: var_alias, cmd_alias, local_alias
190 * Except you cannot list or delete local_aliases.
191 *
192 * To fetch a variable, use ``get_variable''
193 * To fetch an alias, use ``get_cmd_alias''
194 * To fetch an ambiguous alias, use ``glob_cmd_alias''
195 * To recurse an array structure, use ``get_subarray_elements''
196 */
197
198 /*
199 * These are general purpose interface functions.
200 * However, the static ones should **always** be static! If you are tempted
201 * to use them outside of alias.c, please rethink what youre trying to do.
202 * Using these functions violates the encapsulation of the interface.
203 * Specifically, if you create a global variable and then want to delete it,
204 * try using a local variable so it is reaped automatically.
205 */
206 extern void add_var_alias (Char *name, Char *stuff, int noisy);
207 extern void add_local_alias (Char *name, Char *stuff, int noisy);
208 extern void add_cmd_alias (Char *name, ArgList *arglist, Char *stuff);
209 extern void add_var_stub_alias (Char *name, Char *stuff);
210 extern void add_cmd_stub_alias (Char *name, Char *stuff);
211 extern void add_builtin_cmd_alias (Char *, void (*)(Char *, char *, Char *));
212 extern void add_builtin_func_alias (Char *, char *(*)(char *));
213 extern void add_builtin_expando (Char *, char *(*)(void));
214
215 static void delete_var_alias (Char *name, int noisy);
216 static void delete_cmd_alias (Char *name, int noisy);
217 /* void delete_local_alias (Char *name); */
218
219 static void unload_cmd_alias (Char *fn);
220 static void unload_var_alias (Char *fn);
221 static void list_cmd_alias (Char *name);
222 static void list_var_alias (Char *name);
223 static void list_local_alias (Char *name);
224 static void destroy_cmd_aliases (SymbolSet *);
225 static void destroy_var_aliases (SymbolSet *);
226 static void destroy_builtin_commands (SymbolSet *);
227 static void destroy_builtin_functions (SymbolSet *);
228 static void destroy_builtin_variables (SymbolSet *);
229 static void destroy_builtin_expandos (SymbolSet *);
230
231 extern char * get_variable (Char *name);
232 extern char ** glob_cmd_alias (Char *name, int *howmany, int maxret, int start, int rev);
233 extern char ** glob_assign_alias (Char *name, int *howmany, int maxret, int start, int rev);
234 extern const char * get_cmd_alias (Char *name, void **args,
235 void (**func) (const char *, char *,
236 const char *));
237 extern char ** get_subarray_elements (Char *root, int *howmany, int type);
238
239
240 static char * get_variable_with_args (Char *str, Char *args);
241
flush_all_symbols(void)242 void flush_all_symbols (void)
243 {
244 int i;
245 Symbol *s;
246
247 for (i = 0; i < globals.max; i++)
248 {
249 s = globals.list[i];
250 new_free(&s->name);
251 new_free(&s->user_variable);
252 new_free(&s->user_variable_package);
253 new_free(&s->user_command);
254 new_free(&s->user_command_package);
255 destroy_arglist(&s->arglist);
256 s->builtin_command = NULL;
257 s->builtin_function = NULL;
258 s->builtin_expando = NULL;
259 if (s->builtin_variable)
260 {
261 if (s->builtin_variable->type == STR_VAR)
262 new_free(&s->builtin_variable->data->string);
263 new_free(&s->builtin_variable->data);
264 new_free(&s->builtin_variable->script);
265 new_free(&s->builtin_variable);
266 }
267 new_free(&globals.list[i]);
268 }
269 new_free(&globals.list);
270 }
271
272
273 /************************** HIGH LEVEL INTERFACE ***********************/
274
275 /*
276 * User front end to the ALIAS command
277 * Syntax to debug alias: ALIAS /S
278 * Syntax to add alias: ALIAS name [{] irc command(s) [}]
279 * Syntax to delete alias: ALIAS -name
280 */
BUILT_IN_COMMAND(aliascmd)281 BUILT_IN_COMMAND(aliascmd)
282 {
283 char *name;
284 char *real_name;
285 char *ptr;
286
287 /*
288 * If no name present, list all aliases
289 */
290 if (!(name = next_arg(args, &args)))
291 {
292 list_cmd_alias(NULL);
293 return;
294 }
295
296 /*
297 * Alias can take an /s arg, which shows some data we've collected
298 */
299 if (!my_strnicmp(name, "/S", 2))
300 {
301 say("Sorry, this EPIC does not have caches");
302 return;
303 }
304
305 /*
306 * Canonicalize the alias name
307 */
308 real_name = remove_brackets(name, NULL);
309
310 /*
311 * Find the argument body
312 */
313 while (my_isspace(*args))
314 args++;
315
316 /*
317 * If there is no argument body, we probably want to delete alias
318 */
319 if (!args || !*args)
320 {
321 /*
322 * If the alias name starts with a hyphen, then we are
323 * going to delete it.
324 */
325 if (real_name[0] == '-')
326 {
327 if (real_name[1])
328 delete_cmd_alias(real_name + 1, 1);
329 else
330 say("You must specify an alias to be removed.");
331 }
332
333 /*
334 * Otherwise, the user wants us to list that alias
335 */
336 else
337 list_cmd_alias(real_name);
338 }
339
340 /*
341 * If there is an argument body, then we have to register it
342 */
343 else
344 {
345 ArgList *arglist = NULL;
346
347 /*
348 * Aliases may contain a parameter list, which is parsed
349 * at registration time.
350 */
351 if (*args == LEFT_PAREN)
352 {
353 ssize_t span;
354
355 args++;
356 if ((span = MatchingBracket(args, '(', ')')) < 0)
357 say("Unmatched lparen in ALIAS %s", real_name);
358 else
359 {
360 ptr = args + span;
361 *ptr++ = 0;
362 while (*ptr && my_isspace(*ptr))
363 ptr++;
364 if (!*ptr)
365 say("Missing alias body in ALIAS %s",
366 real_name);
367
368 while (*args && my_isspace(*args))
369 args++;
370 arglist = parse_arglist(args);
371 args = ptr;
372 }
373 }
374
375 /*
376 * Aliases' bodies can be surrounded by a set of braces,
377 * which are stripped off.
378 */
379 if (*args == LEFT_BRACE)
380 {
381 ssize_t span;
382
383 args++;
384 if ((span = MatchingBracket(args, '{', '}')) < 0)
385 say("Unmatched brace in ALIAS %s", real_name);
386 else
387 {
388 ptr = args + span;
389 *ptr++ = 0;
390 while (*ptr && my_isspace(*ptr))
391 ptr++;
392
393 if (*ptr)
394 say("Junk [%s] after closing brace in ALIAS %s",
395 ptr, real_name);
396
397 while (*args && my_isspace(*args))
398 args++;
399 }
400 }
401
402 /*
403 * Register the alias
404 */
405 add_cmd_alias(real_name, arglist, args);
406 }
407
408 new_free(&real_name);
409 return;
410 }
411
412 /*
413 * User front end to the ASSIGN command
414 * Syntax to add variable: ASSIGN name text
415 * Syntax to delete variable: ASSIGN -name
416 */
BUILT_IN_COMMAND(assigncmd)417 BUILT_IN_COMMAND(assigncmd)
418 {
419 char *real_name;
420 char *name;
421
422 /*
423 * If there are no arguments, list all the global variables
424 */
425 if (!(name = next_arg(args, &args)))
426 {
427 list_var_alias(NULL);
428 return;
429 }
430
431 /*
432 * Canonicalize the variable name
433 */
434 real_name = remove_brackets(name, NULL);
435
436 /*
437 * Find the stuff to assign to the variable
438 */
439 while (my_isspace(*args))
440 args++;
441
442 /*
443 * If there is no body, then the user probably wants to delete
444 * the variable
445 */
446 if (!args || !*args)
447 {
448 /*
449 * If the variable name starts with a hyphen, then we remove
450 * the variable
451 */
452 if (real_name[0] == '-')
453 {
454 if (real_name[1])
455 delete_var_alias(real_name + 1, 1);
456 else
457 say("You must specify an alias to be removed.");
458 }
459
460 /*
461 * Otherwise, the user wants us to list the variable
462 */
463 else
464 list_var_alias(real_name);
465 }
466
467 /*
468 * Register the variable
469 */
470 else
471 add_var_alias(real_name, args, 1);
472
473 new_free(&real_name);
474 return;
475 }
476
477 /*
478 * User front end to the STUB command
479 * Syntax to stub an alias to a file: STUB ALIAS name[,name] filename(s)
480 * Syntax to stub a variable to a file: STUB ASSIGN name[,name] filename(s)
481 */
BUILT_IN_COMMAND(stubcmd)482 BUILT_IN_COMMAND(stubcmd)
483 {
484 int type;
485 char *cmd;
486 char *name;
487 const char *usage = "Usage: STUB (alias|assign) <name> <file> [<file> ...]";
488
489 /*
490 * The first argument is the type of stub to make
491 * (alias or assign)
492 */
493 if (!(cmd = upper(next_arg(args, &args))))
494 {
495 my_error("Missing stub type");
496 say("%s", usage);
497 return;
498 }
499
500 if (!strncmp(cmd, "ALIAS", strlen(cmd)))
501 type = COMMAND_ALIAS;
502 else if (!strncmp(cmd, "ASSIGN", strlen(cmd)))
503 type = VAR_ALIAS;
504 else
505 {
506 my_error("[%s] is an Unrecognized stub type", cmd);
507 say("%s", usage);
508 return;
509 }
510
511 /*
512 * The next argument is the name of the item to be stubbed.
513 * This is not optional.
514 */
515 if (!(name = next_arg(args, &args)))
516 {
517 my_error("Missing alias name");
518 say("%s", usage);
519 return;
520 }
521
522 /*
523 * Find the filename argument
524 */
525 while (my_isspace(*args))
526 args++;
527
528 /*
529 * The rest of the argument(s) are the files to load when the
530 * item is referenced. This is not optional.
531 */
532 if (!args || !*args)
533 {
534 my_error("Missing file name");
535 say("%s", usage);
536 return;
537 }
538
539 /*
540 * Now we iterate over the item names we were given. For each
541 * item name, seperated from the next by a comma, stub that item
542 * to the given filename(s) specified as the arguments.
543 */
544 while (name && *name)
545 {
546 char *next_name;
547 char *real_name;
548
549 if ((next_name = strchr(name, ',')))
550 *next_name++ = 0;
551
552 real_name = remove_brackets(name, NULL);
553 if (type == COMMAND_ALIAS)
554 add_cmd_stub_alias(real_name, args);
555 else
556 add_var_stub_alias(real_name, args);
557
558 new_free(&real_name);
559 name = next_name;
560 }
561 }
562
BUILT_IN_COMMAND(localcmd)563 BUILT_IN_COMMAND(localcmd)
564 {
565 char *name;
566
567 if (!(name = next_arg(args, &args)))
568 {
569 list_local_alias(NULL);
570 return;
571 }
572
573 while (args && *args && my_isspace(*args))
574 args++;
575
576 if (!args)
577 args = LOCAL_COPY(empty_string);
578
579 if (!my_strnicmp(name, "-dump", 2)) /* Illegal name anyways */
580 {
581 destroy_var_aliases(&call_stack[wind_index].alias);
582 return;
583 }
584
585 while (name && *name)
586 {
587 char *next_name;
588 char *real_name;
589
590 if ((next_name = strchr(name, ',')))
591 *next_name++ = 0;
592
593 real_name = remove_brackets(name, NULL);
594 add_local_alias(real_name, args, 1);
595 new_free(&real_name);
596 name = next_name;
597 }
598 }
599
BUILT_IN_COMMAND(dumpcmd)600 BUILT_IN_COMMAND(dumpcmd)
601 {
602 const char *blah = empty_string;
603 int all = 0;
604 int dumped = 0;
605
606 upper(args);
607
608 if (!args || !*args || !strncmp(args, "ALL", 3))
609 all = 1;
610
611 while (all || (blah = next_arg(args, &args)))
612 {
613 dumped = 0;
614
615 if (all || !strncmp(blah, "VAR", strlen(blah)))
616 {
617 say("Dumping your global variables");
618 destroy_var_aliases(&globals);
619 dumped++;
620 }
621 if (all || !strncmp(blah, "ALIAS", strlen(blah)))
622 {
623 say("Dumping your global aliases");
624 destroy_cmd_aliases(&globals);
625 dumped++;
626 }
627 if (all || !strncmp(blah, "ON", strlen(blah)))
628 {
629 say("Dumping your ONs");
630 flush_on_hooks();
631 dumped++;
632 }
633
634 if (!dumped)
635 say("Dump what? ('%s' is unrecognized)", blah);
636
637 if (all)
638 break;
639 }
640 }
641
BUILT_IN_COMMAND(unloadcmd)642 BUILT_IN_COMMAND(unloadcmd)
643 {
644 char *filename;
645
646 if (!(filename = next_arg(args, &args)))
647 my_error("You must supply a filename for /UNLOAD.");
648 else
649 {
650 do_hook(UNLOAD_LIST, "%s", filename);
651 say("Removing aliases from %s ...", filename);
652 unload_cmd_alias(filename);
653 say("Removing assigns from %s ...", filename);
654 unload_var_alias(filename);
655 say("Removing hooks from %s ...", filename);
656 unload_on_hooks(filename);
657 say("Removing keybinds from %s ...", filename);
658 unload_bindings(filename);
659 say("Removing timers from %s ...", filename);
660 unload_timers(filename);
661 say("Done.");
662 }
663 }
664
665
666 /*
667 * Argument lists look like this:
668 *
669 * LIST := LPAREN TERM [COMMA TERM] RPAREN)
670 * LPAREN := '('
671 * RPAREN := ')'
672 * COMMA := ','
673 * TERM := LVAL QUAL | "..." | "void"
674 * LVAL := <An alias name>
675 * QUAL := NUM "words"
676 *
677 * In English:
678 * An argument list is a comma seperated list of variable descriptors (TERM)
679 * enclosed in a parenthesis set. Each variable descriptor may contain any
680 * valid alias name followed by an action qualifier, or may be the "..."
681 * literal string, or may be the "void" literal string. If a variable
682 * descriptor is an alias name, then that positional argument will be removed
683 * from the argument list and assigned to that variable. If the qualifier
684 * specifies how many words are to be taken, then that many are taken.
685 * If the variable descriptor is the literal string "...", then all argument
686 * list parsing stops there and all remaining alias arguments are placed
687 * into the $* special variable. If the variable descriptor is the literal
688 * string "void", then the balance of the remaining alias arguments are
689 * discarded and $* will expand to the false value. If neither "..." nor
690 * "void" are provided in the argument list, then that last variable in the
691 * list will recieve all of the remaining arguments left at its position.
692 *
693 * Examples:
694 *
695 * # This example puts $0 in $channel, $1 in $mag, and $2- in $nicklist.
696 * /alias opalot (channel, mag, nicklist) {
697 * fe ($nicklist) xx yy zz {
698 * mode $channel ${mag}ooo $xx $yy $zz
699 * }
700 * }
701 *
702 * # This example puts $0 in $channel, $1 in $mag, and the new $* is old $2-
703 * /alias opalot (channel, mag, ...) {
704 * fe ($*) xx yy zz {
705 * mode $channel ${mag}ooo $xx $yy $zz
706 * }
707 * }
708 *
709 * # This example throws away any arguments passed to this alias
710 * /alias booya (void) { echo Booya! }
711 */
parse_arglist(char * arglist)712 ArgList *parse_arglist (char *arglist)
713 {
714 char * this_term;
715 char * next_term;
716 char * varname;
717 char * modifier, *value;
718 int arg_count = 0;
719 ArgList *args = new_malloc(sizeof(ArgList));
720
721 if (arglist == NULL)
722 panic(1, "parse_arglist: arglist is NULL and it shouldn't be.");
723
724 args->void_flag = args->dot_flag = 0;
725 for (this_term = arglist; *this_term; this_term = next_term)
726 {
727 while (isspace(*this_term))
728 this_term++;
729 next_in_comma_list(this_term, &next_term);
730 if (!(varname = next_arg(this_term, &this_term)))
731 continue;
732
733 args->types[arg_count] = WORD;
734 if (!my_stricmp(varname, "void")) {
735 args->void_flag = 1;
736 break;
737 } else if (!my_stricmp(varname, "...")) {
738 args->dot_flag = 1;
739 break;
740 } else {
741 args->vars[arg_count] = malloc_strdup(varname);
742 args->defaults[arg_count] = NULL;
743 args->words[arg_count] = 1;
744
745 while ((modifier = next_arg(this_term, &this_term)))
746 {
747 if (!(value = new_next_arg(this_term, &this_term)))
748 break;
749 if (!my_stricmp(modifier, "default"))
750 {
751 args->defaults[arg_count] = malloc_strdup(value);
752 }
753 else if (!my_stricmp(modifier, "words"))
754 {
755 args->types[arg_count] = WORD;
756 args->words[arg_count] = atol(value);
757 }
758 else if (!my_stricmp(modifier, "uwords"))
759 {
760 args->types[arg_count] = UWORD;
761 args->words[arg_count] = atol(value);
762 }
763 else if (!my_stricmp(modifier, "qwords"))
764 {
765 args->types[arg_count] = QWORD;
766 args->words[arg_count] = atol(value);
767 }
768 else if (!my_stricmp(modifier, "dwords"))
769 {
770 args->types[arg_count] = DWORD;
771 args->words[arg_count] = atol(value);
772 }
773 else
774 {
775 yell("Bad arglist parameter modifier %s -- did you forget to put a comma before this variable names?", modifier);
776 }
777 }
778 arg_count++;
779 }
780 }
781 args->vars[arg_count] = NULL;
782 return args;
783 }
784
destroy_arglist(ArgList ** arglist)785 void destroy_arglist (ArgList **arglist)
786 {
787 int i = 0;
788
789 if (!arglist || !*arglist)
790 return;
791
792 for (i = 0; ; i++)
793 {
794 if (!(*arglist)->vars[i])
795 break;
796 new_free(&(*arglist)->vars[i]);
797 new_free(&(*arglist)->defaults[i]);
798 }
799 new_free((char **)arglist);
800 }
801
802 /* static ArgList *clone_arglist (ArgList *orig) */
clone_arglist(ArgList * orig)803 ArgList *clone_arglist (ArgList *orig)
804 {
805 ArgList *args;
806 int i = 0;
807
808 if (!orig)
809 return NULL;
810
811 args = new_malloc(sizeof(ArgList));
812 for (i = 0; i < 32; i++)
813 {
814 args->vars[i] = NULL;
815 args->defaults[i] = NULL;
816 args->words[i] = 0;
817 args->types[i] = WORD;
818 }
819 for (i = 0; ; i++)
820 {
821 if (!orig->vars[i])
822 break;
823 malloc_strcpy(&args->vars[i], orig->vars[i]);
824 malloc_strcpy(&args->defaults[i], orig->defaults[i]);
825 args->words[i] = orig->words[i];
826 args->types[i] = orig->types[i];
827 }
828 args->void_flag = orig->void_flag;
829 args->dot_flag = orig->dot_flag;
830
831 return args;
832 }
833
prepare_alias_call(void * al,char ** stuff)834 void prepare_alias_call (void *al, char **stuff)
835 {
836 ArgList *args = (ArgList *)al;
837 int i;
838
839 if (!args)
840 return;
841
842 for (i = 0; args->vars[i]; i++)
843 {
844 char *next_val;
845 char *expanded = NULL;
846 int type = 0, do_dequote_it;
847
848 switch (args->types[i])
849 {
850 case WORD:
851 if (!(x_debug & DEBUG_DWORD))
852 {
853 type = DWORD_NO;
854 do_dequote_it = 0;
855 }
856 else if (args->words[i] <= 1)
857 {
858 type = DWORD_DWORDS;
859 do_dequote_it = 1;
860 }
861 else
862 {
863 type = DWORD_YES;
864 do_dequote_it = 0;
865 }
866 break;
867 case UWORD:
868 type = DWORD_NO;
869 do_dequote_it = 0;
870 break;
871 case DWORD:
872 type = DWORD_YES;
873 do_dequote_it = 1;
874 break;
875 case QWORD:
876 type = DWORD_YES;
877 do_dequote_it = 0;
878 break;
879 default:
880 panic(1, "Alias list argument [%d] has unsupported typed [%d]", i, args->types[i]);
881 /* NOTREACHED */
882 return;
883 }
884
885 /* Last argument on the list and no ... argument? */
886 if (!args->vars[i + 1] && !args->dot_flag && !args->void_flag)
887 {
888 next_val = *stuff;
889 *stuff = endstr(*stuff);
890 }
891
892 /* Yank the next word from the arglist */
893 else
894 {
895 next_val = universal_next_arg_count(*stuff, stuff, args->words[i], type, 0, "\"");
896 }
897
898 if (!next_val || !*next_val)
899 {
900 if ((next_val = args->defaults[i]))
901 next_val = expanded = expand_alias(next_val, *stuff);
902 else
903 next_val = LOCAL_COPY(empty_string);
904 }
905
906 /* Do dequoting last so it's useful for ``defaults'' */
907 if (next_val && *next_val && do_dequote_it == 1)
908 {
909 size_t clue;
910 clue = strlen(next_val);
911 dequoter(&next_val, &clue, 1, type, "\"");
912 }
913
914 /* Add the local variable */
915 add_local_alias(args->vars[i], next_val, 0);
916 if (expanded)
917 new_free(&expanded);
918 }
919
920 /* Throw away rest of args if wanted */
921 if (args->void_flag)
922 *stuff = endstr(*stuff);
923 }
924
925 /* static char * print_arglist (ArgList *args) */
print_arglist(ArgList * args)926 char * print_arglist (ArgList *args)
927 {
928 char * retval = NULL;
929 size_t cluep = 0;
930 int i;
931
932 if (!args)
933 return NULL;
934
935 for (i = 0; args->vars[i]; i++)
936 {
937 if (i > 0)
938 malloc_strcat_c(&retval, ", ", &cluep);
939
940 malloc_strcat_c(&retval, args->vars[i], &cluep);
941
942 switch (args->types[i])
943 {
944 case WORD:
945 malloc_strcat_c(&retval, " words ", &cluep);
946 break;
947 case UWORD:
948 malloc_strcat_c(&retval, " uwords ", &cluep);
949 break;
950 case QWORD:
951 malloc_strcat_c(&retval, " qwords ", &cluep);
952 break;
953 case DWORD:
954 malloc_strcat_c(&retval, " dwords ", &cluep);
955 break;
956 }
957 malloc_strcat_c(&retval, ltoa(args->words[i]), &cluep);
958
959 if (args->defaults[i])
960 {
961 malloc_strcat_c(&retval, " default ", &cluep);
962 malloc_strcat_c(&retval, args->defaults[i], &cluep);
963 }
964 }
965
966 if (args->void_flag)
967 {
968 if (i > 0)
969 malloc_strcat_c(&retval, ", ", &cluep);
970 malloc_strcat_c(&retval, "void", &cluep);
971 }
972 else if (args->dot_flag)
973 {
974 if (i > 0)
975 malloc_strcat_c(&retval, ", ", &cluep);
976 malloc_strcat_c(&retval, "...", &cluep);
977 }
978
979 return retval;
980 }
981
982
983 #undef ew_next_arg
984 /***************************************************************************/
985
make_new_Symbol(const char * name)986 static Symbol *make_new_Symbol (const char *name)
987 {
988 Symbol *tmp = (Symbol *) new_malloc(sizeof(Symbol));
989 tmp->name = malloc_strdup(name);
990
991 tmp->user_variable = NULL;
992 tmp->user_variable_stub = 0;
993 tmp->user_variable_package = NULL;
994
995 tmp->user_command = NULL;
996 tmp->user_command_stub = 0;
997 tmp->user_command_package = NULL;
998 tmp->arglist = NULL;
999
1000 tmp->builtin_command = NULL;
1001 tmp->builtin_function = NULL;
1002 tmp->builtin_expando = NULL;
1003 tmp->builtin_variable = NULL;
1004
1005 tmp->saved = NULL;
1006 tmp->saved_hint = 0;
1007 return tmp;
1008 }
1009
1010 /*
1011 * Purge a symbol if it is empty.
1012 * A symbol is "empty" IFF
1013 * - It has no data for any valid symbol type
1014 * - It does not have any /stack push'ed data below it
1015 * UNLESS
1016 * - It is a standalone item (list == NULL)
1017 *
1018 * This function returns 1 if this symbol is empty, and it was removed
1019 * from list (if appropriate), and it was free()d; no further use of
1020 * 'item' may be used after this function returns 1.
1021 *
1022 * This function returns 0 if the symbol is not empty. The symbol will
1023 * not have been changed in any way.
1024 *
1025 * IF this is a standalone item, then the symbol can be considered empty
1026 * even if it has /stack push'd data below it. A standalone item will
1027 * still be GC'd, even if it has stacked data below it! You *must* save a
1028 * pointer to 'item->saved' before calling this function on a standalone
1029 * item and you *must* do something with that pointer if this function
1030 * returns 1! (If you don't, you'll leak your stacked data!)
1031 */
GC_symbol(Symbol * item,array * list,int loc)1032 static int GC_symbol (Symbol *item, array *list, int loc)
1033 {
1034 if (item->user_variable)
1035 return 0;
1036 if (item->user_command)
1037 return 0;
1038 if (item->builtin_command)
1039 return 0;
1040 if (item->builtin_function)
1041 return 0;
1042 if (item->builtin_expando)
1043 return 0;
1044 if (item->builtin_variable)
1045 return 0;
1046 if (item->saved && list != NULL)
1047 return 0;
1048
1049 if (list && loc >= 0)
1050 array_pop(list, loc);
1051
1052 new_free(&item->user_variable_package);
1053 new_free(&item->user_command_package);
1054 destroy_arglist(&item->arglist);
1055 new_free(&(item->name));
1056 new_free((char **)&item);
1057 return 1;
1058 }
1059
1060 /* * * */
1061 /*
1062 * add_var_alias: Add a global variable
1063 *
1064 * name -- name of the alias to create (must be canonicalized)
1065 * stuff -- what to have ``name'' expand to.
1066 *
1067 * If ``name'' is FUNCTION_RETURN, then it will create the local
1068 * return value (die die die)
1069 *
1070 * If ``name'' refers to an already created local variable, that
1071 * local variable is used (invisibly)
1072 */
add_var_alias(const char * orig_name,const char * stuff,int noisy)1073 void add_var_alias (const char *orig_name, const char *stuff, int noisy)
1074 {
1075 const char *ptr;
1076 Symbol *tmp = NULL;
1077 int local = 0;
1078 char *save, *name;
1079
1080 save = name = remove_brackets(orig_name, NULL);
1081 if (*name == ':')
1082 {
1083 name++, local = 1;
1084 if (*name == ':')
1085 name++, local = -1;
1086 }
1087
1088 /*
1089 * Weed out invalid variable names
1090 */
1091 ptr = after_expando(name, 1, NULL);
1092 if (*ptr)
1093 my_error("ASSIGN names may not contain '%c' (You asked for [%s])", *ptr, name);
1094
1095 /*
1096 * Weed out FUNCTION_RETURN (die die die)
1097 */
1098 else if (!strcmp(name, "FUNCTION_RETURN"))
1099 add_local_alias(name, stuff, noisy);
1100
1101 /*
1102 * Pass the buck on local variables
1103 */
1104 else if ((local == 1) || (local == 0 && find_local_alias(name, NULL)))
1105 add_local_alias(name, stuff, noisy);
1106
1107 else if (stuff && *stuff)
1108 {
1109 int cnt, loc;
1110
1111 /*
1112 * Look to see if the given alias already exists.
1113 * If it does, and the ``stuff'' to assign to it is
1114 * empty, then we should remove the variable outright
1115 */
1116 tmp = (Symbol *) find_array_item ((array *)&globals, name, &cnt, &loc);
1117 if (!tmp || cnt >= 0)
1118 {
1119 tmp = make_new_Symbol(name);
1120 add_to_array ((array *)&globals, (array_item *)tmp);
1121 }
1122
1123 if (current_package())
1124 {
1125 if (!tmp->user_variable_package)
1126 tmp->user_variable_package = malloc_strdup(current_package());
1127 else if (strcmp(tmp->user_variable_package, current_package()))
1128 malloc_strcpy(&(tmp->user_variable_package), current_package());
1129 }
1130
1131 malloc_strcpy(&(tmp->user_variable), stuff);
1132 tmp->user_variable_stub = 0;
1133
1134
1135 /*
1136 * And tell the user.
1137 */
1138 if (noisy)
1139 say("Assign %s added [%s]", name, stuff);
1140 }
1141 else
1142 delete_var_alias(name, noisy);
1143
1144 new_free(&save);
1145 return;
1146 }
1147
add_var_stub_alias(const char * orig_name,const char * stuff)1148 void add_var_stub_alias (const char *orig_name, const char *stuff)
1149 {
1150 Symbol *tmp = NULL;
1151 const char *ptr;
1152 char *name;
1153
1154 name = remove_brackets(orig_name, NULL);
1155
1156 ptr = after_expando(name, 1, NULL);
1157 if (*ptr)
1158 {
1159 my_error("Assign names may not contain '%c' (You asked for [%s])", *ptr, name);
1160 new_free(&name);
1161 return;
1162 }
1163 else if (!strcmp(name, "FUNCTION_RETURN"))
1164 {
1165 my_error("You may not stub the FUNCTION_RETURN variable.");
1166 new_free(&name);
1167 return;
1168 }
1169
1170
1171 if (!(tmp = lookup_symbol(name)))
1172 {
1173 tmp = make_new_Symbol(name);
1174 if (current_package())
1175 tmp->user_variable_package = malloc_strdup(current_package());
1176 add_to_array ((array *)&globals, (array_item *)tmp);
1177 }
1178 else if (current_package())
1179 {
1180 if (!tmp->user_variable_package ||
1181 strcmp(tmp->user_variable_package, current_package()))
1182 malloc_strcpy(&tmp->user_variable_package, current_package());
1183 }
1184
1185 malloc_strcpy(&(tmp->user_variable), stuff);
1186 tmp->user_variable_stub = 1;
1187
1188 say("Assign %s stubbed to file %s", name, stuff);
1189 new_free(&name);
1190 return;
1191 }
1192
add_local_alias(const char * orig_name,const char * stuff,int noisy)1193 void add_local_alias (const char *orig_name, const char *stuff, int noisy)
1194 {
1195 const char *ptr;
1196 Symbol *tmp = NULL;
1197 SymbolSet *list = NULL;
1198 char * name;
1199
1200 name = remove_brackets(orig_name, NULL);
1201
1202 /*
1203 * Weed out invalid variable names
1204 */
1205 ptr = after_expando(name, 1, NULL);
1206 if (*ptr)
1207 {
1208 my_error("LOCAL names may not contain '%c' (You asked for [%s])",
1209 *ptr, name);
1210 new_free(&name);
1211 return;
1212 }
1213
1214 /*
1215 * Now we see if this local variable exists anywhere
1216 * within our view. If it is, we dont care where.
1217 * If it doesnt, then we add it to the current frame,
1218 * where it will be reaped later.
1219 */
1220 if (!(tmp = find_local_alias (name, &list)))
1221 {
1222 tmp = make_new_Symbol(name);
1223 add_to_array ((array *)list, (array_item *)tmp);
1224 }
1225
1226 /* Fill in the interesting stuff */
1227 malloc_strcpy(&(tmp->user_variable), stuff);
1228 if (tmp->user_variable) /* Oh blah. */
1229 {
1230 if (x_debug & DEBUG_LOCAL_VARS && noisy)
1231 yell("Assign %s (local) added [%s]", name, stuff);
1232 else if (noisy)
1233 say("Assign %s (local) added [%s]", name, stuff);
1234 }
1235
1236 new_free(&name);
1237 return;
1238 }
1239
1240 /* * * */
add_cmd_alias(const char * orig_name,ArgList * arglist,const char * stuff)1241 void add_cmd_alias (const char *orig_name, ArgList *arglist, const char *stuff)
1242 {
1243 Symbol *tmp = NULL;
1244 char *name;
1245 char *argstr;
1246
1247 name = remove_brackets(orig_name, NULL);
1248 if (!(tmp = lookup_symbol(name)))
1249 {
1250 tmp = make_new_Symbol(name);
1251 if (current_package())
1252 tmp->user_command_package = malloc_strdup(current_package());
1253 add_to_array ((array *)&globals, (array_item *)tmp);
1254 }
1255 else if (current_package())
1256 {
1257 if (tmp->user_command_package == NULL ||
1258 strcmp(tmp->user_command_package, current_package()))
1259 malloc_strcpy(&tmp->user_command_package, current_package());
1260 }
1261
1262 malloc_strcpy(&(tmp->user_command), stuff);
1263 tmp->user_command_stub = 0;
1264 destroy_arglist(&tmp->arglist);
1265 tmp->arglist = arglist;
1266
1267 argstr = print_arglist(arglist);
1268 if (argstr)
1269 {
1270 say("Alias %s (%s) added [%s]", name, argstr, stuff);
1271 new_free(&argstr);
1272 }
1273 else
1274 say("Alias %s added [%s]", name, stuff);
1275
1276 new_free(&name);
1277 return;
1278 }
1279
1280
add_cmd_stub_alias(const char * orig_name,const char * stuff)1281 void add_cmd_stub_alias (const char *orig_name, const char *stuff)
1282 {
1283 Symbol *tmp = NULL;
1284 char *name;
1285
1286 name = remove_brackets(orig_name, NULL);
1287 if (!(tmp = lookup_symbol(name)))
1288 {
1289 tmp = make_new_Symbol(name);
1290 if (current_package())
1291 tmp->user_command_package = malloc_strdup(current_package());
1292 add_to_array ((array *)&globals, (array_item *)tmp);
1293 }
1294 else if (current_package())
1295 {
1296 if (tmp->user_command_package == NULL ||
1297 strcmp(tmp->user_command_package, current_package()))
1298 malloc_strcpy(&(tmp->user_command_package), current_package());
1299 }
1300
1301 malloc_strcpy(&(tmp->user_command), stuff);
1302 tmp->user_command_stub = 1;
1303
1304 say("Alias %s stubbed to file %s", name, stuff);
1305
1306 new_free(&name);
1307 return;
1308 }
1309
add_builtin_cmd_alias(const char * name,void (* func)(const char *,char *,const char *))1310 void add_builtin_cmd_alias (const char *name, void (*func) (const char *, char *, const char *))
1311 {
1312 Symbol *tmp = NULL;
1313 int cnt, loc;
1314
1315 tmp = (Symbol *) find_array_item ((array *)&globals, name, &cnt, &loc);
1316 if (!tmp || cnt >= 0)
1317 {
1318 tmp = make_new_Symbol(name);
1319 add_to_array ((array *)&globals, (array_item *)tmp);
1320 }
1321
1322 tmp->builtin_command = func;
1323 return;
1324 }
1325
add_builtin_func_alias(const char * name,char * (* func)(char *))1326 void add_builtin_func_alias (const char *name, char * (*func) (char *))
1327 {
1328 Symbol *tmp = NULL;
1329 int cnt, loc;
1330
1331 tmp = (Symbol *) find_array_item ((array *)&globals, name, &cnt, &loc);
1332 if (!tmp || cnt >= 0)
1333 {
1334 tmp = make_new_Symbol(name);
1335 add_to_array ((array *)&globals, (array_item *)tmp);
1336 }
1337
1338 tmp->builtin_function = func;
1339 return;
1340 }
1341
add_builtin_expando(const char * name,char * (* func)(void))1342 void add_builtin_expando (const char *name, char *(*func) (void))
1343 {
1344 Symbol *tmp = NULL;
1345 int cnt, loc;
1346
1347 tmp = (Symbol *) find_array_item ((array *)&globals, name, &cnt, &loc);
1348 if (!tmp || cnt >= 0)
1349 {
1350 tmp = make_new_Symbol(name);
1351 add_to_array ((array *)&globals, (array_item *)tmp);
1352 }
1353
1354 tmp->builtin_expando = func;
1355 return;
1356 }
1357
add_builtin_variable_alias(const char * name,IrcVariable * var)1358 void add_builtin_variable_alias (const char *name, IrcVariable *var)
1359 {
1360 Symbol *tmp = NULL;
1361 int cnt, loc;
1362
1363 tmp = (Symbol *) find_array_item ((array *)&globals, name, &cnt, &loc);
1364 if (!tmp || cnt >= 0)
1365 {
1366 tmp = make_new_Symbol(name);
1367 add_to_array((array *)&globals, (array_item *)tmp);
1368 }
1369
1370 tmp->builtin_variable = var;
1371 return;
1372 }
1373
1374
1375
1376 /************************ LOW LEVEL INTERFACE *************************/
1377
1378 static int unstub_in_progress = 0;
1379
unstub_variable(Symbol * item)1380 static Symbol *unstub_variable (Symbol *item)
1381 {
1382 char *name;
1383 char *file;
1384
1385 if (!item)
1386 return NULL;
1387
1388 name = LOCAL_COPY(item->name);
1389 if (item->user_variable_stub)
1390 {
1391 file = LOCAL_COPY(item->user_variable);
1392 delete_var_alias(item->name, 0);
1393
1394 if (!unstub_in_progress)
1395 {
1396 unstub_in_progress = 1;
1397 load("LOAD", file, empty_string);
1398 unstub_in_progress = 0;
1399 }
1400
1401 /* Look the name up again */
1402 item = lookup_symbol(name);
1403 }
1404 return item;
1405 }
1406
unstub_command(Symbol * item)1407 static Symbol *unstub_command (Symbol *item)
1408 {
1409 char *name;
1410 char *file;
1411
1412 if (!item)
1413 return NULL;
1414
1415 name = LOCAL_COPY(item->name);
1416 if (item->user_command_stub)
1417 {
1418 file = LOCAL_COPY(item->user_command);
1419 delete_cmd_alias(item->name, 0);
1420
1421 if (!unstub_in_progress)
1422 {
1423 unstub_in_progress = 1;
1424 load("LOAD", file, empty_string);
1425 unstub_in_progress = 0;
1426 }
1427
1428 /* Look the name up again */
1429 item = lookup_symbol(name);
1430 }
1431 return item;
1432 }
1433
1434
1435 /*
1436 * 'name' is expected to already be in canonical form (uppercase, dot notation)
1437 */
lookup_symbol(const char * name)1438 static Symbol * lookup_symbol (const char *name)
1439 {
1440 Symbol * item = NULL;
1441 int loc;
1442 int cnt = 0;
1443
1444 #if 0
1445 name += strspn(name, ":"); /* Accept ::global */
1446 #endif
1447
1448 item = (Symbol *)find_array_item((array *)&globals, name, &cnt, &loc);
1449 if (cnt >= 0)
1450 item = NULL;
1451 if (item && item->user_variable_stub)
1452 item = unstub_variable(item);
1453 if (item && item->user_command_stub)
1454 item = unstub_command(item);
1455 return item;
1456 }
1457
1458 /*
1459 * An example will best describe the semantics:
1460 *
1461 * A local variable will be returned if and only if there is already a
1462 * variable that is exactly ``name'', or if there is a variable that
1463 * is an exact leading subset of ``name'' and that variable ends in a
1464 * period (a dot).
1465 */
find_local_alias(const char * orig_name,SymbolSet ** list)1466 static Symbol * find_local_alias (const char *orig_name, SymbolSet **list)
1467 {
1468 Symbol *alias = NULL;
1469 int c;
1470 const char *ptr;
1471 int implicit = -1;
1472 int function_return = 0;
1473 char * name;
1474
1475 /* No name is an error */
1476 if (!orig_name)
1477 return NULL;
1478
1479 name = remove_brackets(orig_name, NULL);
1480 upper(name);
1481
1482 ptr = after_expando(name, 1, NULL);
1483 if (*ptr) {
1484 new_free(&name);
1485 return NULL;
1486 }
1487
1488 if (!my_stricmp(name, "FUNCTION_RETURN"))
1489 function_return = 1;
1490
1491 /*
1492 * Search our current local variable stack, and wind our way
1493 * backwards until we find a NAMED stack -- that is the enclosing
1494 * alias or ON call. If we find a variable in one of those enclosing
1495 * stacks, then we use it. If we dont, we progress.
1496 *
1497 * This needs to be optimized for the degenerate case, when there
1498 * is no local variable available... It will be true 99.999% of
1499 * the time.
1500 */
1501 for (c = wind_index; c >= 0; c = call_stack[c].parent)
1502 {
1503 /* XXXXX */
1504 if (function_return && last_function_call_level != -1)
1505 c = last_function_call_level;
1506
1507 if (x_debug & DEBUG_LOCAL_VARS)
1508 yell("Looking for [%s] in level [%d]", name, c);
1509
1510 if (call_stack[c].alias.list)
1511 {
1512 int x, cnt, loc;
1513
1514 /* We can always hope that the variable exists */
1515 find_array_item((array*)&call_stack[c].alias, name, &cnt, &loc);
1516 if (cnt < 0)
1517 alias = call_stack[c].alias.list[loc];
1518
1519 /* XXXX - This is bletcherous */
1520 /*
1521 * I agree, however, there doesn't seem to be any other
1522 * reasonable way to do it. I guess launching multiple
1523 * binary searches on relevant portions of name would
1524 * do it, but the overhead could(?) do damage.
1525 *
1526 * Actualy, thinking about it again, seperating the
1527 * implicit variables from the normal ones would
1528 * probably work.
1529 */
1530 else if (strchr(name, '.'))
1531 for (x = 0; x < loc; x++)
1532 {
1533 Symbol *item;
1534 size_t len;
1535
1536 item = call_stack[c].alias.list[x];
1537 len = strlen(item->name);
1538
1539 if (streq(item->name, name) == len) {
1540 if (item->name[len-1] == '.') {
1541 implicit = c;
1542 break;
1543 }
1544 }
1545 }
1546
1547 if (!alias && implicit >= 0)
1548 {
1549 alias = make_new_Symbol(name);
1550 add_to_array ((array *)&call_stack[implicit].alias, (array_item *)alias);
1551 }
1552 }
1553
1554 if (alias)
1555 {
1556 if (x_debug & DEBUG_LOCAL_VARS)
1557 yell("I found [%s] in level [%d] (%s)", name, c, alias->user_variable);
1558 break;
1559 }
1560
1561 if (*call_stack[c].name || call_stack[c].parent == -1 ||
1562 (function_return && last_function_call_level != -1))
1563 {
1564 if (x_debug & DEBUG_LOCAL_VARS)
1565 yell("I didnt find [%s], stopped at level [%d]", name, c);
1566 break;
1567 }
1568 }
1569
1570 new_free(&name);
1571
1572 if (alias)
1573 {
1574 if (list)
1575 *list = &call_stack[c].alias;
1576 return alias;
1577 }
1578 else if (list)
1579 *list = &call_stack[wind_index].alias;
1580
1581 return NULL;
1582 }
1583
1584
1585 /* * */
delete_var_alias(const char * orig_name,int noisy)1586 static void delete_var_alias (const char *orig_name, int noisy)
1587 {
1588 Symbol *item;
1589 char * name;
1590 int cnt, loc;
1591
1592 name = remove_brackets(orig_name, NULL);
1593 upper(name);
1594 item = (Symbol *)find_array_item((array *)&globals, name, &cnt, &loc);
1595 if (item && cnt < 0)
1596 {
1597 new_free(&item->user_variable);
1598 item->user_variable_stub = 0;
1599 new_free(&(item->user_variable_package));
1600 GC_symbol(item, (array *)&globals, loc);
1601 if (noisy)
1602 say("Assign %s removed", name);
1603 }
1604 else if (noisy)
1605 say("No such assign: %s", name);
1606 new_free(&name);
1607 }
1608
delete_cmd_alias(const char * orig_name,int noisy)1609 static void delete_cmd_alias (const char *orig_name, int noisy)
1610 {
1611 Symbol *item;
1612 char * name;
1613 int cnt, loc;
1614
1615 name = remove_brackets(orig_name, NULL);
1616 upper(name);
1617 item = (Symbol *)find_array_item((array *)&globals, name, &cnt, &loc);
1618 if (item && cnt < 0)
1619 {
1620 new_free(&item->user_command);
1621 item->user_command_stub = 0;
1622 new_free(&(item->user_command_package));
1623 destroy_arglist(&item->arglist);
1624 GC_symbol(item, (array *)&globals, loc);
1625 if (noisy)
1626 say("Alias %s removed", name);
1627 }
1628 else if (noisy)
1629 say("No such alias: %s", name);
1630 new_free(&name);
1631 }
1632
delete_builtin_command(const char * orig_name)1633 void delete_builtin_command (const char *orig_name)
1634 {
1635 Symbol *item;
1636 char * name;
1637 int cnt, loc;
1638
1639 name = remove_brackets(orig_name, NULL);
1640 upper(name);
1641 item = (Symbol *)find_array_item((array *)&globals, name, &cnt, &loc);
1642 if (item && cnt < 0)
1643 {
1644 item->builtin_command = NULL;
1645 GC_symbol(item, (array *)&globals, loc);
1646 }
1647 new_free(&name);
1648 }
1649
delete_builtin_function(const char * orig_name)1650 void delete_builtin_function (const char *orig_name)
1651 {
1652 Symbol *item;
1653 char * name;
1654 int cnt, loc;
1655
1656 name = remove_brackets(orig_name, NULL);
1657 upper(name);
1658 item = (Symbol *)find_array_item((array *)&globals, name, &cnt, &loc);
1659 if (item && cnt < 0)
1660 {
1661 item->builtin_function = NULL;
1662 GC_symbol(item, (array *)&globals, loc);
1663 }
1664 new_free(&name);
1665 }
1666
delete_builtin_expando(const char * orig_name)1667 void delete_builtin_expando (const char *orig_name)
1668 {
1669 Symbol *item;
1670 char * name;
1671 int cnt, loc;
1672
1673 name = remove_brackets(orig_name, NULL);
1674 upper(name);
1675 item = (Symbol *)find_array_item((array *)&globals, name, &cnt, &loc);
1676 if (item && cnt < 0)
1677 {
1678 item->builtin_expando = NULL;
1679 GC_symbol(item, (array *)&globals, loc);
1680 }
1681 new_free(&name);
1682 }
1683
delete_builtin_variable(const char * orig_name)1684 void delete_builtin_variable (const char *orig_name)
1685 {
1686 Symbol *item;
1687 char * name;
1688 int cnt, loc;
1689
1690 name = remove_brackets(orig_name, NULL);
1691 upper(name);
1692 item = (Symbol *)find_array_item((array *)&globals, name, &cnt, &loc);
1693 if (item && cnt < 0)
1694 {
1695 item->builtin_variable = NULL;
1696 GC_symbol(item, (array *)&globals, loc);
1697 }
1698 new_free(&name);
1699 }
1700
1701 /* * * */
bucket_local_alias(Bucket * b,const char * name)1702 static void bucket_local_alias (Bucket *b, const char *name)
1703 {
1704 }
1705
1706 #define BUCKET_FUNCTION(x, y) \
1707 void bucket_ ## x (Bucket *b, const char *name) \
1708 { \
1709 int i; \
1710 size_t len; \
1711 Symbol *item; \
1712 \
1713 len = strlen(name); \
1714 for (i = 0; i < globals.max; i++) \
1715 { \
1716 item = globals.list[i]; \
1717 if (!my_strnicmp(name, item->name, len)) \
1718 { \
1719 if (item-> y ) \
1720 add_to_bucket(b, item->name, item-> y); \
1721 } \
1722 } \
1723 }
1724
BUCKET_FUNCTION(var_alias,user_variable)1725 BUCKET_FUNCTION(var_alias, user_variable)
1726 BUCKET_FUNCTION(cmd_alias, user_command)
1727 BUCKET_FUNCTION(builtin_commands, builtin_command)
1728 BUCKET_FUNCTION(builtin_functions, builtin_function)
1729 BUCKET_FUNCTION(builtin_expandos, builtin_expando)
1730 BUCKET_FUNCTION(builtin_variables, builtin_variable)
1731
1732 /* * * */
1733 static void list_local_alias (const char *orig_name)
1734 {
1735 size_t len = 0;
1736 int cnt;
1737 int DotLoc, LastDotLoc = 0;
1738 char *LastStructName = NULL;
1739 char *s;
1740 char *name = NULL;
1741 Symbol *item;
1742
1743 say("Visible Local Assigns:");
1744 if (orig_name)
1745 {
1746 name = remove_brackets(orig_name, NULL);
1747 len = strlen(upper(name));
1748 }
1749
1750 for (cnt = wind_index; cnt >= 0; cnt = call_stack[cnt].parent)
1751 {
1752 int x;
1753 if (!call_stack[cnt].alias.list)
1754 continue;
1755 for (x = 0; x < call_stack[cnt].alias.max; x++)
1756 {
1757 item = call_stack[cnt].alias.list[x];
1758 if (!name || !strncmp(item->name, name, len))
1759 {
1760 if ((s = strchr(item->name + len, '.')))
1761 {
1762 DotLoc = s - item->name;
1763 if (!LastStructName || (DotLoc != LastDotLoc) ||
1764 strncmp(item->name, LastStructName, DotLoc))
1765 {
1766 put_it("\t%*.*s\t<Structure>", DotLoc, DotLoc,
1767 item->name);
1768 LastStructName = item->name;
1769 LastDotLoc = DotLoc;
1770 }
1771 }
1772 else
1773 put_it("\t%s\t%s", item->name, item->user_variable);
1774 }
1775 }
1776 }
1777 }
1778
1779 /*
1780 * This function is strictly O(N). Its possible to address this.
1781 */
list_var_alias(const char * orig_name)1782 static void list_var_alias (const char *orig_name)
1783 {
1784 size_t len = 0;
1785 int DotLoc,
1786 LastDotLoc = 0;
1787 const char *LastStructName = NULL;
1788 int cnt;
1789 char *s;
1790 const char *script;
1791 char *name = NULL;
1792
1793 say("Assigns:");
1794
1795 if (orig_name)
1796 {
1797 name = remove_brackets(orig_name, NULL);
1798 len = strlen(upper(name));
1799 }
1800
1801 for (cnt = 0; cnt < globals.max; cnt++)
1802 {
1803 Symbol *item = globals.list[cnt];
1804
1805 if (item == NULL)
1806 continue;
1807
1808 if (!item->user_variable)
1809 continue;
1810
1811 if (!name || !strncmp(item->name, name, len))
1812 {
1813 script = empty(item->user_variable_package) ? "*" :
1814 item->user_variable_package;
1815
1816 if ((s = strchr(item->name + len, '.')))
1817 {
1818 DotLoc = s - globals.list[cnt]->name;
1819 if (!LastStructName || (DotLoc != LastDotLoc) ||
1820 strncmp(item->name, LastStructName, DotLoc))
1821 {
1822 say("[%s]\t%*.*s\t<Structure>", script, DotLoc,
1823 DotLoc, item->name);
1824 LastStructName = item->name;
1825 LastDotLoc = DotLoc;
1826 }
1827 }
1828 else
1829 {
1830 if (item->user_variable_stub)
1831 say("[%s]\t%s STUBBED TO %s", script,
1832 item->name, item->user_variable);
1833 else
1834 say("[%s]\t%s\t%s", script,
1835 item->name, item->user_variable);
1836 }
1837 }
1838 }
1839
1840 new_free(&name);
1841 }
1842
1843 /*
1844 * This function is strictly O(N). Its possible to address this.
1845 */
list_cmd_alias(const char * orig_name)1846 static void list_cmd_alias (const char *orig_name)
1847 {
1848 size_t len = 0;
1849 int DotLoc,
1850 LastDotLoc = 0;
1851 char *LastStructName = NULL;
1852 int cnt;
1853 char *s;
1854 const char *script;
1855 char *name = NULL;
1856
1857 say("Aliases:");
1858
1859 if (orig_name)
1860 {
1861 name = remove_brackets(orig_name, NULL);
1862 len = strlen(upper(name));
1863 }
1864
1865 for (cnt = 0; cnt < globals.max; cnt++)
1866 {
1867 Symbol *item = globals.list[cnt];
1868
1869 if (item == NULL)
1870 continue;
1871
1872 if (!item->user_command)
1873 continue;
1874
1875 if (!name || !strncmp(item->name, name, len))
1876 {
1877 script = empty(item->user_command_package) ? "*" :
1878 item->user_command_package;
1879
1880 if ((s = strchr(item->name + len, '.')))
1881 {
1882 DotLoc = s - item->name;
1883 if (!LastStructName || (DotLoc != LastDotLoc) ||
1884 strncmp(item->name, LastStructName, DotLoc))
1885 {
1886 say("[%s]\t%*.*s\t<Structure>", script, DotLoc,
1887 DotLoc, item->name);
1888 LastStructName = item->name;
1889 LastDotLoc = DotLoc;
1890 }
1891 }
1892 else
1893 {
1894 if (item->user_command_stub)
1895 say("[%s]\t%s STUBBED TO %s", script,
1896 item->name, item->user_command);
1897 else
1898 {
1899 char *arglist = print_arglist(item->arglist);
1900 if (arglist)
1901 {
1902 say("[%s]\t%s (%s)\t%s", script,
1903 item->name, arglist,
1904 item->user_command);
1905 new_free(&arglist);
1906 }
1907 else
1908 say("[%s]\t%s\t%s", script,
1909 item->name, item->user_command);
1910 }
1911 }
1912 }
1913 }
1914 new_free(&name);
1915 }
1916
list_builtin_commands(const char * orig_name)1917 static void list_builtin_commands (const char *orig_name)
1918 {
1919 }
1920
list_builtin_functions(const char * orig_name)1921 static void list_builtin_functions (const char *orig_name)
1922 {
1923 }
1924
list_builtin_expandos(const char * orig_name)1925 static void list_builtin_expandos (const char *orig_name)
1926 {
1927 }
1928
list_builtin_variables(const char * orig_name)1929 static void list_builtin_variables (const char *orig_name)
1930 {
1931 }
1932
1933 /************************* UNLOADING SCRIPTS ************************/
unload_cmd_alias(const char * package)1934 static void unload_cmd_alias (const char *package)
1935 {
1936 int cnt;
1937 Symbol *item;
1938
1939 for (cnt = 0; cnt < globals.max; cnt++)
1940 {
1941 item = globals.list[cnt];
1942
1943 if (!item->user_command_package)
1944 continue;
1945 else if (!strcmp(item->user_command_package, package)) {
1946 delete_cmd_alias(item->name, 0);
1947 cnt = -1;
1948 continue;
1949 }
1950 }
1951 }
1952
unload_var_alias(const char * package)1953 static void unload_var_alias (const char *package)
1954 {
1955 int cnt;
1956 Symbol *item;
1957
1958 for (cnt = 0; cnt < globals.max; cnt++)
1959 {
1960 item = globals.list[cnt];
1961
1962 if (!item->user_variable_package)
1963 continue;
1964 else if (!strcmp(item->user_variable_package, package)) {
1965 delete_var_alias(item->name, 0);
1966 cnt = -1;
1967 continue;
1968 }
1969 }
1970 }
1971
unload_builtin_commands(const char * filename)1972 static void unload_builtin_commands (const char *filename)
1973 {
1974 }
1975
unload_builtin_functions(const char * filename)1976 static void unload_builtin_functions (const char *filename)
1977 {
1978 }
1979
unload_builtin_expandos(const char * filename)1980 static void unload_builtin_expandos (const char *filename)
1981 {
1982 }
1983
unload_builtin_variables(const char * filename)1984 static void unload_builtin_variables (const char *filename)
1985 {
1986 }
1987
1988 /* * */
1989 /*
1990 * This function is strictly O(N). This should probably be addressed.
1991 *
1992 * Updated as per get_subarray_elements.
1993 */
glob_cmd_alias(const char * name,int * howmany,int maxret,int start,int rev)1994 char ** glob_cmd_alias (const char *name, int *howmany, int maxret, int start, int rev)
1995 {
1996 int pos, max;
1997 int cnt;
1998 int len;
1999 char **matches = NULL;
2000 int matches_size = 0;
2001
2002 len = strlen(name);
2003 *howmany = 0;
2004 if (len) {
2005 find_array_item((array*)&globals, name, &max, &pos);
2006 } else {
2007 pos = 0;
2008 max = globals.max;
2009 }
2010 if (0 > max) max = -max;
2011
2012 for (cnt = 0; cnt < max; cnt++, pos++)
2013 {
2014 if (!globals.list[pos]->user_command)
2015 continue;
2016 if (strchr(globals.list[pos]->name + len, '.'))
2017 continue;
2018
2019 if (*howmany >= matches_size)
2020 {
2021 matches_size += 5;
2022 RESIZE(matches, char *, matches_size + 1);
2023 }
2024 matches[*howmany] = malloc_strdup(globals.list[pos]->name);
2025 *howmany += 1;
2026 }
2027
2028 if (*howmany)
2029 matches[*howmany] = NULL;
2030 else
2031 new_free((char **)&matches);
2032
2033 return matches;
2034 }
2035
2036 /*
2037 * This function is strictly O(N). This should probably be addressed.
2038 *
2039 * Updated as per get_subarray_elements.
2040 */
glob_assign_alias(const char * name,int * howmany,int maxret,int start,int rev)2041 char ** glob_assign_alias (const char *name, int *howmany, int maxret, int start, int rev)
2042 {
2043 int pos, max;
2044 int cnt;
2045 int len;
2046 char **matches = NULL;
2047 int matches_size = 0;
2048
2049 len = strlen(name);
2050 *howmany = 0;
2051 if (len) {
2052 find_array_item((array*)&globals, name, &max, &pos);
2053 } else {
2054 pos = 0;
2055 max = globals.max;
2056 }
2057 if (0 > max) max = -max;
2058
2059 for (cnt = 0; cnt < max; cnt++, pos++)
2060 {
2061 if (!globals.list[pos]->user_variable)
2062 continue;
2063 if (strchr(globals.list[pos]->name + len, '.'))
2064 continue;
2065
2066 if (*howmany >= matches_size)
2067 {
2068 matches_size += 5;
2069 RESIZE(matches, char *, matches_size + 1);
2070 }
2071 matches[*howmany] = malloc_strdup(globals.list[pos]->name);
2072 *howmany += 1;
2073 }
2074
2075 if (*howmany)
2076 matches[*howmany] = NULL;
2077 else
2078 new_free((char **)&matches);
2079
2080 return matches;
2081 }
2082
2083 #if 0
2084 char **glob_builtin_commands (const char *name, int *howmany, int maxret, int start, int rev)
2085 {
2086 return NULL;
2087 }
2088
2089 char **glob_builtin_functions (const char *name, int *howmany, int maxret, int start, int rev)
2090 {
2091 return NULL;
2092 }
2093
2094 char **glob_builtin_expandos (const char *name, int *howmany, int maxret, int start, int rev)
2095 {
2096 return NULL;
2097 }
2098
2099 char **glob_builtin_variables (const char *name, int *howmany, int maxret, int start, int rev)
2100 {
2101 return NULL;
2102 }
2103 #endif
2104
2105 #define PMATCH_SYMBOL(x, y) \
2106 char ** pmatch_ ## x (const char *name, int *howmany, int maxret, int start, int rev) \
2107 { \
2108 int cnt, cnt1; \
2109 int len; \
2110 char **matches = NULL; \
2111 int matches_size = 5; \
2112 \
2113 len = strlen(name); \
2114 *howmany = 0; \
2115 matches = RESIZE(matches, char *, matches_size); \
2116 \
2117 for (cnt1 = 0; cnt1 < globals.max; cnt1++) \
2118 { \
2119 cnt = rev ? globals.max - cnt1 - 1 : cnt1; \
2120 if (!globals.list[cnt]-> y ) \
2121 continue; \
2122 \
2123 if (wild_match(name, globals.list[cnt]->name)) \
2124 { \
2125 if (start--) \
2126 continue; \
2127 else \
2128 start++; \
2129 matches[*howmany] = globals.list[cnt]->name; \
2130 *howmany += 1; \
2131 if (*howmany == matches_size) \
2132 { \
2133 matches_size += 5; \
2134 RESIZE(matches, char *, matches_size); \
2135 } \
2136 if (maxret && --maxret <= 0) \
2137 break; \
2138 } \
2139 } \
2140 \
2141 if (*howmany) \
2142 matches[*howmany] = NULL; \
2143 else \
2144 new_free((char **)&matches); \
2145 \
2146 return matches; \
2147 }
2148
PMATCH_SYMBOL(assign_alias,user_variable)2149 PMATCH_SYMBOL(assign_alias, user_variable)
2150 PMATCH_SYMBOL(cmd_alias, user_command)
2151 PMATCH_SYMBOL(builtin_variables, builtin_variable)
2152 PMATCH_SYMBOL(builtin_commands, builtin_command)
2153 PMATCH_SYMBOL(builtin_functions, builtin_function)
2154 PMATCH_SYMBOL(builtin_expandos, builtin_expando)
2155 static PMATCH_SYMBOL(any_symbol, name)
2156
2157 /*****************************************************************************/
2158 /*
2159 * This function is strictly O(N). This should probably be addressed.
2160 *
2161 * OK, so it isn't _strictly_ O(N) anymore, however, it is still O(N)
2162 * for N being all elements below the subarray being requested. This
2163 * makes recursive /foreach's such as purge run much faster, however,
2164 * since each variable will be tested no more than its current depth
2165 * times, rather than every single time a /foreach is performed.
2166 *
2167 * In the worst case scenario where the entire variable space consists
2168 * of a single flat subarray, the new algorithm would perform no worse
2169 * than the old.
2170 */
2171 char ** get_subarray_elements (const char *orig_root, int *howmany, int type)
2172 {
2173 SymbolSet *as; /* XXXX */
2174 Symbol *s;
2175 int pos, cnt, max;
2176 int cmp = 0;
2177 char **matches = NULL;
2178 int matches_size = 0;
2179 size_t end;
2180 char *last = NULL;
2181 char *root = NULL;
2182
2183 as = &globals;
2184 root = malloc_strdup2(orig_root, ".");
2185 find_array_item((array*)as, root, &max, &pos);
2186
2187 if (0 > max)
2188 max = -max;
2189 *howmany = 0;
2190 cmp = strlen(root);
2191 new_free(&root);
2192
2193 for (cnt = 0; cnt < max; cnt++, pos++)
2194 {
2195 s = (Symbol *)ARRAY_ITEM(as, pos);
2196
2197 end = strcspn(s->name + cmp, ".");
2198 if (last && !my_strnicmp(s->name, last, cmp + end))
2199 continue;
2200
2201 /* Must have an entry for the correct type */
2202 if (type == COMMAND_ALIAS && s->user_command == NULL)
2203 continue;
2204 if (type == VAR_ALIAS && s->user_variable == NULL)
2205 continue;
2206
2207 if (*howmany >= matches_size)
2208 {
2209 matches_size = *howmany + 5;
2210 RESIZE(matches, char *, matches_size + 1);
2211 }
2212 matches[*howmany] = malloc_strndup(s->name, cmp + end);
2213 last = matches[*howmany];
2214 *howmany += 1;
2215 }
2216
2217 if (*howmany)
2218 matches[*howmany] = NULL;
2219 else
2220 new_free((char **)&matches);
2221
2222 return matches;
2223 }
2224
2225
2226 /***************************************************************************/
destroy_cmd_aliases(SymbolSet * my_array)2227 static void destroy_cmd_aliases (SymbolSet *my_array)
2228 {
2229 int cnt = 0;
2230 Symbol *item;
2231
2232 for (;;)
2233 {
2234 for (cnt = 0; cnt < my_array->max; cnt++)
2235 {
2236 item = my_array->list[cnt];
2237 if (!item->user_command && !item->user_command_stub &&
2238 !item->arglist && !item->user_command_package)
2239 continue;
2240
2241 new_free((void **)&item->user_command);
2242 new_free((void **)&item->user_command_package);
2243 item->user_command_stub = 0;
2244 destroy_arglist(&item->arglist);
2245 GC_symbol(item, (array *)my_array, cnt);
2246 break;
2247 }
2248 if (cnt >= my_array->max)
2249 return;
2250 }
2251 }
2252
destroy_var_aliases(SymbolSet * my_array)2253 static void destroy_var_aliases (SymbolSet *my_array)
2254 {
2255 int cnt = 0;
2256 Symbol *item;
2257
2258 for (;;)
2259 {
2260 for (cnt = 0; cnt < my_array->max; cnt++)
2261 {
2262 item = my_array->list[cnt];
2263 if (!item->user_variable && !item->user_variable_stub)
2264 continue;
2265
2266 new_free((void **)&item->user_variable);
2267 new_free((void **)&item->user_variable_package);
2268 item->user_variable_stub = 0;
2269 GC_symbol(item, (array *)my_array, cnt);
2270 break;
2271 }
2272 if (cnt >= my_array->max)
2273 return;
2274 }
2275 }
2276
destroy_builtin_commands(SymbolSet * my_array)2277 static void destroy_builtin_commands (SymbolSet *my_array)
2278 {
2279 int cnt = 0;
2280 Symbol *item;
2281
2282 for (;;)
2283 {
2284 for (cnt = 0; cnt < my_array->max; cnt++)
2285 {
2286 item = my_array->list[cnt];
2287 if (!item->builtin_command)
2288 continue;
2289 item->builtin_command = NULL;
2290 GC_symbol(item, (array *)my_array, cnt);
2291 break;
2292 }
2293 if (cnt >= my_array->max)
2294 return;
2295 }
2296 }
2297
destroy_builtin_functions(SymbolSet * my_array)2298 static void destroy_builtin_functions (SymbolSet *my_array)
2299 {
2300 int cnt = 0;
2301 Symbol *item;
2302
2303 for (;;)
2304 {
2305 for (cnt = 0; cnt < my_array->max; cnt++)
2306 {
2307 item = my_array->list[cnt];
2308 if (!item->builtin_function)
2309 continue;
2310 item->builtin_function = NULL;
2311 GC_symbol(item, (array *)my_array, cnt);
2312 break;
2313 }
2314 if (cnt >= my_array->max)
2315 return;
2316 }
2317 }
2318
destroy_builtin_expandos(SymbolSet * my_array)2319 static void destroy_builtin_expandos (SymbolSet *my_array)
2320 {
2321 int cnt = 0;
2322 Symbol *item;
2323
2324 for (;;)
2325 {
2326 for (cnt = 0; cnt < my_array->max; cnt++)
2327 {
2328 item = my_array->list[cnt];
2329 if (!item->builtin_expando)
2330 continue;
2331 item->builtin_expando = NULL;
2332 GC_symbol(item, (array *)my_array, cnt);
2333 break;
2334 }
2335 if (cnt >= my_array->max)
2336 return;
2337 }
2338 }
2339
destroy_builtin_variables(SymbolSet * my_array)2340 static void destroy_builtin_variables (SymbolSet *my_array)
2341 {
2342 int cnt = 0;
2343 Symbol *item;
2344
2345 for (;;)
2346 {
2347 for (cnt = 0; cnt < my_array->max; cnt++)
2348 {
2349 item = my_array->list[cnt];
2350 if (!item->builtin_variable)
2351 continue;
2352 item->builtin_variable = NULL; /* XXX memory leak */
2353 GC_symbol(item, (array *)my_array, cnt);
2354 break;
2355 }
2356 if (cnt >= my_array->max)
2357 return;
2358 }
2359 }
2360
2361 /******************* RUNTIME STACK SUPPORT **********************************/
2362
make_local_stack(const char * name)2363 int make_local_stack (const char *name)
2364 {
2365 wind_index++;
2366
2367 #ifdef MAX_STACK_FRAMES
2368 if (wind_index >= MAX_STACK_FRAMES)
2369 {
2370 system_exception++;
2371 return 0;
2372 }
2373 #endif
2374
2375 if (wind_index >= max_wind)
2376 {
2377 int tmp_wind = wind_index;
2378
2379 if (max_wind == -1)
2380 max_wind = 8;
2381 else
2382 max_wind <<= 1;
2383
2384 RESIZE(call_stack, RuntimeStack, max_wind);
2385 for (; wind_index < max_wind; wind_index++)
2386 {
2387 call_stack[wind_index].alias.max = 0;
2388 call_stack[wind_index].alias.max_alloc = 0;
2389 call_stack[wind_index].alias.list = NULL;
2390 call_stack[wind_index].alias.func = strncmp;
2391 call_stack[wind_index].alias.hash = HASH_INSENSITIVE;
2392 call_stack[wind_index].current = NULL;
2393 call_stack[wind_index].name = NULL;
2394 call_stack[wind_index].parent = -1;
2395 }
2396 wind_index = tmp_wind;
2397 }
2398
2399 /* Just in case... */
2400 destroy_local_stack();
2401 wind_index++; /* XXXX - chicanery */
2402
2403 if (name)
2404 {
2405 call_stack[wind_index].name = name;
2406 call_stack[wind_index].parent = -1;
2407 }
2408 else
2409 {
2410 call_stack[wind_index].name = empty_string;
2411 call_stack[wind_index].parent = wind_index - 1;
2412 }
2413 call_stack[wind_index].locked = 0;
2414 return 1;
2415 }
2416
find_locked_stack_frame(void)2417 static int find_locked_stack_frame (void)
2418 {
2419 int i;
2420 for (i = 0; i < wind_index; i++)
2421 if (call_stack[i].locked)
2422 return i;
2423
2424 return -1;
2425 }
2426
bless_local_stack(void)2427 void bless_local_stack (void)
2428 {
2429 call_stack[wind_index].name = empty_string;
2430 call_stack[wind_index].parent = find_locked_stack_frame();
2431 }
2432
destroy_local_stack(void)2433 void destroy_local_stack (void)
2434 {
2435 /*
2436 * We clean up as best we can here...
2437 */
2438 if (call_stack[wind_index].alias.list)
2439 destroy_var_aliases(&call_stack[wind_index].alias);
2440 if (call_stack[wind_index].current)
2441 call_stack[wind_index].current = 0;
2442 if (call_stack[wind_index].name)
2443 call_stack[wind_index].name = 0;
2444
2445 wind_index--;
2446 }
2447
set_current_command(char * line)2448 void set_current_command (char *line)
2449 {
2450 call_stack[wind_index].current = line;
2451 }
2452
unset_current_command(void)2453 void unset_current_command (void)
2454 {
2455 call_stack[wind_index].current = NULL;
2456 }
2457
lock_stack_frame(void)2458 void lock_stack_frame (void)
2459 {
2460 call_stack[wind_index].locked = 1;
2461 }
2462
unlock_stack_frame(void)2463 void unlock_stack_frame (void)
2464 {
2465 int lock = find_locked_stack_frame();
2466 if (lock >= 0)
2467 call_stack[lock].locked = 0;
2468 }
2469
dump_call_stack(void)2470 void dump_call_stack (void)
2471 {
2472 int i;
2473
2474 yell("Call stack");
2475 for (i = wind_index; i >= 0; i--)
2476 yell("[%3d] %s", i, call_stack[i].current ? call_stack[i].current : "<async>");
2477 yell("End of call stack");
2478 }
2479
panic_dump_call_stack(void)2480 void panic_dump_call_stack (void)
2481 {
2482 if (wind_index >= 0)
2483 {
2484 int i;
2485
2486 fprintf(stderr, "Call stack\n");
2487 for (i = wind_index; i >= 0; i--)
2488 fprintf(stderr, "[%3d] %s\n", i,
2489 call_stack[i].current ? call_stack[i].current : "<async>");
2490 fprintf(stderr, "End of call stack\n");
2491 }
2492 else
2493 fprintf(stderr, "Stack is corrupted [wind_index is %d], sorry.\n",
2494 wind_index);
2495 }
2496
2497
2498 /************************* DIRECT VARIABLE EXPANSION ************************/
2499 /*
2500 * get_variable: This returns the rvalue of the symbol "str".
2501 *
2502 * An rvalue is what an expando is substituted with if it is used on the
2503 * right hand side of an assignment.
2504 *
2505 * 1) local variable
2506 * 2) global variable
2507 * 3) environment variable
2508 * 4) The empty string
2509 */
get_variable(const char * str)2510 char *get_variable (const char *str)
2511 {
2512 return get_variable_with_args(str, NULL);
2513 }
2514
2515
get_variable_with_args(const char * str,const char * args)2516 static char * get_variable_with_args (const char *str, const char *args)
2517 {
2518 Symbol *alias = NULL;
2519 char *ret = NULL;
2520 char *name = NULL;
2521 char *freep = NULL;
2522 int copy = 0;
2523 int local = 0;
2524
2525 freep = name = remove_brackets(str, args);
2526
2527 /*
2528 * Support $:var to mean local variable ONLY (no globals)
2529 * Support $::var to mean global variable ONLY (no locals)
2530 * Support $: with nothing after it as a built in expando. Ick.
2531 */
2532 if (*name == ':' && name[1])
2533 {
2534 name++, local = 1;
2535 if (*name == ':')
2536 name++, local = -1;
2537 }
2538
2539 /*
2540 * local == -1 means "local variables not allowed"
2541 * local == 0 means "locals first, then globals"
2542 * local == 1 means "global variables not allowed"
2543 */
2544 if ((local != -1) && (alias = find_local_alias(name, NULL)))
2545 copy = 1, ret = alias->user_variable;
2546 else if (local == 1)
2547 (void) 0;
2548
2549 if (ret == NULL && ((alias = lookup_symbol(name)) != NULL))
2550 {
2551 if (alias->user_variable)
2552 copy = 1, ret = alias->user_variable;
2553 else if (alias->builtin_expando)
2554 copy = 0, ret = alias->builtin_expando();
2555 else if (alias->builtin_variable)
2556 copy = 0, ret = make_string_var_bydata((const void *)alias->builtin_variable);
2557 }
2558 /*
2559 if (ret == NULL && (ret = make_string_var(str)))
2560 copy = 0;
2561 */
2562
2563 if (ret == NULL)
2564 copy = 1, ret = getenv(str);
2565
2566 if (ret == NULL)
2567 {
2568 copy = 0, ret = malloc_strdup(empty_string);
2569 if (x_debug & DEBUG_UNKNOWN)
2570 yell("Variable lookup to non-existant assign [%s]", name);
2571 }
2572
2573 new_free(&freep);
2574 return (copy ? malloc_strdup(ret) : ret);
2575 }
2576
2577 /* * */
get_cmd_alias(const char * name,void ** args,void (** func)(const char *,char *,const char *))2578 const char * get_cmd_alias (const char *name, void **args, void (**func) (const char *, char *, const char *))
2579 {
2580 Symbol *item;
2581
2582 if ((item = lookup_symbol(name)))
2583 {
2584 if (args)
2585 *args = (void *)item->arglist;
2586 *func = item->builtin_command;
2587 return item->user_command;
2588 }
2589
2590 *func = NULL;
2591 return NULL;
2592 }
2593
2594 /* * */
get_func_alias(const char * name,void ** args,char * (** func)(char *))2595 const char * get_func_alias (const char *name, void **args, char * (**func) (char *))
2596 {
2597 Symbol *item;
2598
2599 if ((item = lookup_symbol(name)))
2600 {
2601 if (args)
2602 *args = (void *)item->arglist;
2603 *func = item->builtin_function;
2604 return item->user_command;
2605 }
2606
2607 *func = NULL;
2608 return NULL;
2609 }
2610
get_var_alias(const char * name,char * (** efunc)(void),IrcVariable ** var)2611 const char * get_var_alias (const char *name, char *(**efunc)(void), IrcVariable **var)
2612 {
2613 Symbol *item;
2614
2615 if ((item = lookup_symbol(name)))
2616 {
2617 *efunc = item->builtin_expando;
2618 *var = item->builtin_variable;
2619 return item->user_variable;
2620 }
2621
2622 *efunc = NULL;
2623 *var = NULL;
2624 return NULL;
2625 }
2626
2627
2628 /******************* expression and text parsers ***************************/
2629 /* XXXX - bogus for now */
2630 #include "expr2.c"
2631 #include "expr.c"
2632
2633
2634 /****************************** ALIASCTL ************************************/
2635 /* Used by function_aliasctl */
2636 /* MUST BE FIXED */
aliasctl(char * input)2637 char *aliasctl (char *input)
2638 {
2639 int list = -1;
2640 char *listc;
2641 enum { EXISTS, GET, SET, NMATCH, PMATCH, GETPACKAGE, SETPACKAGE, MAXRET } op;
2642 static int maxret = 0;
2643 int start = 0;
2644 int reverse = 0;
2645
2646 GET_FUNC_ARG(listc, input);
2647 if (!my_strnicmp(listc, "ASSIGN", 2))
2648 list = VAR_ALIAS;
2649 else if (!my_strnicmp(listc, "ALIAS", 2))
2650 list = COMMAND_ALIAS;
2651 else if (!my_strnicmp(listc, "LOCAL", 2))
2652 list = VAR_ALIAS_LOCAL;
2653 else if (!my_strnicmp(listc, "MAXRET", 4))
2654 {
2655 int old_maxret = maxret;
2656 if (input && *input)
2657 GET_INT_ARG(maxret, input);
2658 RETURN_INT(old_maxret);
2659 }
2660 else
2661 RETURN_EMPTY;
2662
2663 GET_FUNC_ARG(listc, input);
2664 if ((start = my_atol(listc)))
2665 GET_FUNC_ARG(listc, input);
2666 if (!my_strnicmp(listc, "GETPACKAGE", 4))
2667 op = GETPACKAGE;
2668 else if (!my_strnicmp(listc, "GET", 1))
2669 op = GET;
2670 else if (!my_strnicmp(listc, "SETPACKAGE", 4))
2671 op = SETPACKAGE;
2672 else if (!my_strnicmp(listc, "SET", 1))
2673 op = SET;
2674 else if (!my_strnicmp(listc, "MATCH", 1))
2675 op = NMATCH;
2676 else if (!my_strnicmp(listc, "RMATCH", 2))
2677 op = NMATCH, reverse = 1;
2678 else if (!my_strnicmp(listc, "PMATCH", 1))
2679 op = PMATCH;
2680 else if (!my_strnicmp(listc, "RPMATCH", 2))
2681 op = PMATCH, reverse = 1;
2682 else if (!my_strnicmp(listc, "EXISTS", 1))
2683 op = EXISTS;
2684 else
2685 RETURN_EMPTY;
2686
2687 GET_FUNC_ARG(listc, input);
2688 switch (op)
2689 {
2690 case (GET) :
2691 case (EXISTS) :
2692 case (GETPACKAGE) :
2693 case (SETPACKAGE) :
2694 {
2695 Symbol *alias = NULL;
2696 SymbolSet *a_list;
2697
2698 upper(listc);
2699 if (list == VAR_ALIAS_LOCAL)
2700 alias = find_local_alias(listc, &a_list);
2701 else
2702 alias = lookup_symbol(listc);
2703
2704 if (alias)
2705 {
2706 if (op == GET)
2707 {
2708 if (list == COMMAND_ALIAS)
2709 RETURN_STR(alias->user_command);
2710 else
2711 RETURN_STR(alias->user_variable);
2712 }
2713 else if (op == EXISTS)
2714 RETURN_INT(1);
2715 else if (op == GETPACKAGE)
2716 {
2717 if (list == VAR_ALIAS_LOCAL || list == VAR_ALIAS)
2718 RETURN_STR(alias->user_variable_package);
2719 else
2720 RETURN_STR(alias->user_command_package);
2721 }
2722 else /* op == SETPACKAGE */
2723 {
2724 if (list == VAR_ALIAS_LOCAL || list == VAR_ALIAS)
2725 malloc_strcpy(&alias->user_variable_package, input);
2726 else
2727 malloc_strcpy(&alias->user_command_package, input);
2728 RETURN_INT(1);
2729 }
2730 }
2731 else
2732 {
2733 if (op == GET || op == GETPACKAGE)
2734 RETURN_EMPTY;
2735 else /* EXISTS or SETPACKAGE */
2736 RETURN_INT(0);
2737 }
2738 }
2739 case (SET) :
2740 {
2741 upper(listc);
2742 if (list == VAR_ALIAS_LOCAL)
2743 add_local_alias(listc, input, 0);
2744 else if (list == VAR_ALIAS)
2745 add_var_alias(listc, input, 0);
2746 else
2747 add_cmd_alias(listc, NULL, input);
2748
2749 RETURN_INT(1);
2750 }
2751 case (NMATCH) :
2752 {
2753 char **mlist = NULL;
2754 char *mylist = NULL;
2755 size_t mylistclue = 0;
2756 int num = 0, ctr;
2757
2758 if (!my_stricmp(listc, "*"))
2759 listc = LOCAL_COPY(empty_string);
2760
2761 upper(listc);
2762
2763 if (list == COMMAND_ALIAS)
2764 mlist = glob_cmd_alias(listc, &num, maxret, start, reverse);
2765 else if (list == VAR_ALIAS)
2766 mlist = glob_assign_alias(listc, &num, maxret, start, reverse);
2767 else
2768 RETURN_EMPTY;
2769
2770 for (ctr = 0; ctr < num; ctr++)
2771 {
2772 malloc_strcat_word_c(&mylist, space, mlist[ctr],DWORD_DWORDS, &mylistclue);
2773 new_free((char **)&mlist[ctr]);
2774 }
2775 new_free((char **)&mlist);
2776 if (mylist)
2777 return mylist;
2778 RETURN_EMPTY;
2779 }
2780 case (PMATCH) :
2781 {
2782 char ** mlist = NULL;
2783 char * mylist = NULL;
2784 size_t mylistclue = 0;
2785 int num = 0,
2786 ctr;
2787
2788 if (list == COMMAND_ALIAS)
2789 mlist = pmatch_cmd_alias(listc, &num, maxret, start, reverse);
2790 else if (list == VAR_ALIAS)
2791 mlist = pmatch_assign_alias(listc, &num, maxret, start, reverse);
2792 else
2793 RETURN_EMPTY;
2794
2795 for (ctr = 0; ctr < num; ctr++)
2796 malloc_strcat_word_c(&mylist, space, mlist[ctr], DWORD_DWORDS, &mylistclue);
2797 new_free((char **)&mlist);
2798 if (mylist)
2799 return mylist;
2800 RETURN_EMPTY;
2801 }
2802 default :
2803 my_error("aliasctl: Error");
2804 RETURN_EMPTY;
2805 }
2806 RETURN_EMPTY;
2807 }
2808
2809
2810
2811 /*************************** stacks **************************************/
2812 /* * * */
stack_push_var_alias(const char * name)2813 int stack_push_var_alias (const char *name)
2814 {
2815 Symbol *item, *sym;
2816 int cnt = 0, loc = 0;
2817
2818 item = (Symbol *)find_array_item((array *)&globals, name, &cnt, &loc);
2819 if (!item || cnt >= 0)
2820 {
2821 item = make_new_Symbol(name);
2822 add_to_array((array *)&globals, (array_item *)item);
2823 }
2824
2825 sym = make_new_Symbol(name);
2826 malloc_strcpy(&sym->user_variable, item->user_variable);
2827 sym->user_variable_stub = item->user_variable_stub;
2828 malloc_strcpy(&sym->user_variable_package, item->user_variable_package);
2829 sym->saved = item->saved;
2830 sym->saved_hint = SAVED_VAR;
2831 item->saved = sym;
2832 return 0;
2833 }
2834
stack_pop_var_alias(const char * name)2835 int stack_pop_var_alias (const char *name)
2836 {
2837 Symbol *item, *sym, *s, *ss;
2838 int cnt = 0, loc = 0;
2839
2840 item = (Symbol *)find_array_item((array *)&globals, name, &cnt, &loc);
2841 if (!item || cnt >= 0)
2842 return -1;
2843
2844 for (sym = item; sym; sym = sym->saved)
2845 if (sym->saved && sym->saved->saved_hint == SAVED_VAR)
2846 break;
2847 if (!sym)
2848 return -1;
2849
2850 s = sym->saved;
2851 ss = sym->saved->saved;
2852 malloc_strcpy(&item->user_variable, s->user_variable);
2853 item->user_variable_stub = s->user_variable_stub;
2854 malloc_strcpy(&item->user_variable_package, s->user_variable_package);
2855 new_free(&s->user_variable);
2856 new_free(&s->user_variable_package);
2857
2858 if (GC_symbol(s, NULL, -1))
2859 sym->saved = ss;
2860 GC_symbol(item, (array *)&globals, loc);
2861 return 0;
2862 }
2863
stack_list_var_alias(const char * name)2864 int stack_list_var_alias (const char *name)
2865 {
2866 Symbol *item, *sym;
2867 int counter = 0;
2868
2869 if (!(item = lookup_symbol(name)))
2870 return -1;
2871
2872 for (sym = item->saved; sym; sym = sym->saved)
2873 {
2874 if (sym->saved_hint == SAVED_VAR)
2875 {
2876 if (sym->user_variable == NULL)
2877 say("\t%s\t<Placeholder>", sym->name);
2878 else if (sym->user_variable_stub)
2879 say("\t%s STUBBED TO %s", sym->name, sym->user_variable);
2880 else
2881 say("\t%s\t%s", sym->name, sym->user_variable);
2882 counter++;
2883 }
2884 }
2885
2886 if (counter)
2887 return 0;
2888 return -1;
2889 }
2890
2891 /* * * */
stack_push_cmd_alias(char * name)2892 int stack_push_cmd_alias (char *name)
2893 {
2894 Symbol *item, *sym;
2895 int cnt = 0, loc = 0;
2896
2897 item = (Symbol *)find_array_item((array *)&globals, name, &cnt, &loc);
2898 if (!item || cnt >= 0)
2899 {
2900 item = make_new_Symbol(name);
2901 add_to_array((array *)&globals, (array_item *)item);
2902 }
2903
2904 sym = make_new_Symbol(name);
2905 malloc_strcpy(&sym->user_command, item->user_command);
2906 sym->user_command_stub = item->user_command_stub;
2907 malloc_strcpy(&sym->user_command_package, item->user_command_package);
2908 sym->arglist = clone_arglist(item->arglist);
2909 sym->saved = item->saved;
2910 sym->saved_hint = SAVED_CMD;
2911 item->saved = sym;
2912 return 0;
2913 }
2914
stack_pop_cmd_alias(const char * name)2915 int stack_pop_cmd_alias (const char *name)
2916 {
2917 Symbol *item, *sym, *s, *ss;
2918 int cnt = 0, loc = 0;
2919
2920 item = (Symbol *)find_array_item((array *)&globals, name, &cnt, &loc);
2921 if (!item || cnt >= 0)
2922 return -1;
2923
2924 for (sym = item; sym; sym = sym->saved)
2925 {
2926 if (sym->saved && sym->saved->saved_hint == SAVED_CMD)
2927 break;
2928 }
2929 if (!sym)
2930 return -1;
2931
2932 s = sym->saved;
2933 ss = sym->saved->saved;
2934 malloc_strcpy(&item->user_command, s->user_command);
2935 item->user_command_stub = s->user_command_stub;
2936 malloc_strcpy(&item->user_command_package, s->user_command_package);
2937 new_free(&s->user_command);
2938 new_free(&s->user_command_package);
2939
2940 if (GC_symbol(s, NULL, -1))
2941 sym->saved = ss;
2942 GC_symbol(item, (array *)&globals, loc);
2943 return 0;
2944 }
2945
stack_list_cmd_alias(const char * name)2946 int stack_list_cmd_alias (const char *name)
2947 {
2948 Symbol *item, *sym;
2949 int counter = 0;
2950
2951 if (!(item = lookup_symbol(name)))
2952 return -1;
2953
2954 for (sym = item->saved; sym; sym = sym->saved)
2955 {
2956 if (sym->saved_hint == SAVED_CMD)
2957 {
2958 if (sym->user_command == NULL)
2959 say("\t%s\t<Placeholder>", sym->name);
2960 else if (sym->user_command_stub)
2961 say("\t%s STUBBED TO %s", sym->name, sym->user_command);
2962 else
2963 say("\t%s\t%s", sym->name, sym->user_command);
2964 counter++;
2965 }
2966 }
2967
2968 if (counter)
2969 return 0;
2970 return -1;
2971 }
2972
2973
2974
2975 /* * * */
2976 #if 0
2977 int stack_push_builtin_cmd_alias (const char *name)
2978 {
2979 Symbol *item, *sym;
2980 int cnt = 0, loc = 0;
2981
2982 item = (Symbol *)find_array_item((array *)&globals, name, &cnt, &loc);
2983 if (!item || cnt >= 0)
2984 {
2985 item = make_new_Symbol(name);
2986 add_to_array((array *)&globals, (array_item *)item);
2987 }
2988
2989 sym = make_new_Symbol(name);
2990 sym->builtin_command = item->builtin_command;
2991 sym->saved = item->saved;
2992 sym->saved_hint = SAVED_BUILTIN_CMD;
2993 item->saved = sym;
2994 return 0;
2995 }
2996
2997 int stack_pop_builtin_cmd_alias (const char *name)
2998 {
2999 Symbol *item, *sym, *s, *n;
3000 int cnt = 0, loc = 0;
3001
3002 item = (Symbol *)find_array_item((array *)&globals, name, &cnt, &loc);
3003 if (!item || cnt >= 0)
3004 return -1;
3005
3006 for (sym = item; sym; sym = sym->saved)
3007 {
3008 if (sym->saved && sym->saved->saved_hint == SAVED_BUILTIN_VAR)
3009 break;
3010 }
3011 if (!sym)
3012 return -1;
3013
3014 s = sym->saved;
3015 n = sym->saved->saved;
3016 item->builtin_command = s->builtin_command;
3017 s->builtin_command = NULL;
3018
3019 if (GC_symbol(s, NULL, -1))
3020 sym->saved = n;
3021 GC_symbol(item, (array *)&globals, loc);
3022 return 0;
3023 }
3024
3025 int stack_list_builtin_cmd_alias (const char *name)
3026 {
3027 Symbol *item, *sym;
3028 int counter = 0;
3029
3030 if (!(item = lookup_symbol(name)))
3031 return -1;
3032
3033 for (sym = item->saved; sym; sym = sym->saved)
3034 {
3035 if (sym->saved_hint == SAVED_BUILTIN_CMD)
3036 {
3037 if (sym->builtin_command == NULL)
3038 say("\t%s\t<Placeholder>", sym->name);
3039 else
3040 say("\t%s\t%p", sym->name, sym->builtin_command);
3041 counter++;
3042 }
3043 }
3044
3045 if (counter)
3046 return 0;
3047 return -1;
3048 }
3049 #endif
3050
3051 /* * * */
stack_push_builtin_func_alias(const char * name)3052 int stack_push_builtin_func_alias (const char *name)
3053 {
3054 Symbol *item, *sym;
3055 int cnt = 0, loc = 0;
3056
3057 item = (Symbol *)find_array_item((array *)&globals, name, &cnt, &loc);
3058 if (!item || cnt >= 0)
3059 {
3060 item = make_new_Symbol(name);
3061 add_to_array((array *)&globals, (array_item *)item);
3062 }
3063
3064 sym = make_new_Symbol(name);
3065 sym->builtin_function = item->builtin_function;
3066 sym->saved = item->saved;
3067 sym->saved_hint = SAVED_BUILTIN_FUNCTION;
3068 item->saved = sym;
3069 return 0;
3070 }
3071
stack_pop_builtin_function_alias(const char * name)3072 int stack_pop_builtin_function_alias (const char *name)
3073 {
3074 Symbol *item, *sym, *s, *n;
3075 int cnt = 0, loc = 0;
3076
3077 item = (Symbol *)find_array_item((array *)&globals, name, &cnt, &loc);
3078 if (!item || cnt >= 0)
3079 return -1;
3080
3081 for (sym = item; sym; sym = sym->saved)
3082 {
3083 if (sym->saved && sym->saved->saved_hint == SAVED_BUILTIN_FUNCTION)
3084 break;
3085 }
3086 if (!sym)
3087 return -1;
3088
3089 s = sym->saved;
3090 n = sym->saved->saved;
3091 item->builtin_function = s->builtin_function;
3092 s->builtin_function = NULL;
3093
3094 if (GC_symbol(s, NULL, -1))
3095 sym->saved = n;
3096 GC_symbol(item, (array *)&globals, loc);
3097 return 0;
3098 }
3099
stack_list_builtin_function_alias(const char * name)3100 int stack_list_builtin_function_alias (const char *name)
3101 {
3102 Symbol *item, *sym;
3103 int counter = 0;
3104
3105 if (!(item = lookup_symbol(name)))
3106 return -1;
3107
3108 for (sym = item->saved; sym; sym = sym->saved)
3109 {
3110 if (sym->saved_hint == SAVED_BUILTIN_FUNCTION)
3111 {
3112 if (sym->builtin_function == NULL)
3113 say("\t%s\t<Placeholder>", sym->name);
3114 else
3115 say("\t%s\t%p", sym->name, sym->builtin_function);
3116 counter++;
3117 }
3118 }
3119
3120 if (counter)
3121 return 0;
3122 return -1;
3123 }
3124
3125 /* * * */
stack_push_builtin_expando_alias(const char * name)3126 int stack_push_builtin_expando_alias (const char *name)
3127 {
3128 Symbol *item, *sym;
3129 int cnt = 0, loc = 0;
3130
3131 item = (Symbol *)find_array_item((array *)&globals, name, &cnt, &loc);
3132 if (!item || cnt >= 0)
3133 {
3134 item = make_new_Symbol(name);
3135 add_to_array((array *)&globals, (array_item *)item);
3136 }
3137
3138 sym = make_new_Symbol(name);
3139 sym->builtin_expando = item->builtin_expando;
3140 sym->saved = item->saved;
3141 sym->saved_hint = SAVED_BUILTIN_EXPANDO;
3142 item->saved = sym;
3143 return 0;
3144 }
3145
stack_pop_builtin_expando_alias(const char * name)3146 int stack_pop_builtin_expando_alias (const char *name)
3147 {
3148 Symbol *item, *sym, *s, *n;
3149 int cnt = 0, loc = 0;
3150
3151 item = (Symbol *)find_array_item((array *)&globals, name, &cnt, &loc);
3152 if (!item || cnt >= 0)
3153 return -1;
3154
3155 for (sym = item; sym; sym = sym->saved)
3156 {
3157 if (sym->saved && sym->saved->saved_hint == SAVED_BUILTIN_EXPANDO)
3158 break;
3159 }
3160 if (!sym)
3161 return -1;
3162
3163 s = sym->saved;
3164 n = sym->saved->saved;
3165 item->builtin_expando = s->builtin_expando;
3166 s->builtin_expando = NULL;
3167
3168 if (GC_symbol(s, NULL, -1))
3169 sym->saved = n;
3170 GC_symbol(item, (array *)&globals, loc);
3171 return 0;
3172 }
3173
stack_list_builtin_expando_alias(const char * name)3174 int stack_list_builtin_expando_alias (const char *name)
3175 {
3176 Symbol *item, *sym;
3177 int counter = 0;
3178
3179 if (!(item = lookup_symbol(name)))
3180 return -1;
3181
3182 for (sym = item->saved; sym; sym = sym->saved)
3183 {
3184 if (sym->saved_hint == SAVED_BUILTIN_EXPANDO)
3185 {
3186 if (sym->builtin_expando == NULL)
3187 say("\t%s\t<Placeholder>", sym->name);
3188 else
3189 say("\t%s\t%p", sym->name, sym->builtin_expando);
3190 counter++;
3191 }
3192 }
3193
3194 if (counter)
3195 return 0;
3196 return -1;
3197 }
3198
3199
3200 /* * * */
stack_push_builtin_var_alias(const char * name)3201 int stack_push_builtin_var_alias (const char *name)
3202 {
3203 Symbol *item, *sym;
3204 int cnt = 0, loc = 0;
3205
3206 item = (Symbol *)find_array_item((array *)&globals, name, &cnt, &loc);
3207 if (!item || cnt >= 0)
3208 {
3209 item = make_new_Symbol(name);
3210 add_to_array((array *)&globals, (array_item *)item);
3211 }
3212
3213 sym = make_new_Symbol(name);
3214 sym->builtin_variable = clone_biv(item->builtin_variable);
3215 sym->saved = item->saved;
3216 sym->saved_hint = SAVED_BUILTIN_VAR;
3217 item->saved = sym;
3218 return 0;
3219 }
3220
stack_pop_builtin_var_alias(const char * name)3221 int stack_pop_builtin_var_alias (const char *name)
3222 {
3223 Symbol *item, *sym, *s, *n;
3224 int cnt = 0, loc = 0;
3225
3226 item = (Symbol *)find_array_item((array *)&globals, name, &cnt, &loc);
3227 if (!item || cnt >= 0)
3228 return -1;
3229
3230 for (sym = item; sym; sym = sym->saved)
3231 {
3232 if (sym->saved && sym->saved->saved_hint == SAVED_BUILTIN_VAR)
3233 break;
3234 }
3235 if (!sym)
3236 return -1;
3237
3238 s = sym->saved;
3239 n = sym->saved->saved;
3240 unclone_biv(name, s->builtin_variable);
3241 s->builtin_variable = NULL;
3242
3243 if (GC_symbol(s, NULL, -1))
3244 sym->saved = n;
3245 GC_symbol(item, (array *)&globals, loc);
3246 return 0;
3247 }
3248
stack_list_builtin_var_alias(const char * name)3249 int stack_list_builtin_var_alias (const char *name)
3250 {
3251 Symbol *item, *sym;
3252 int counter = 0;
3253
3254 if (!(item = lookup_symbol(name)))
3255 return -1;
3256
3257 for (sym = item->saved; sym; sym = sym->saved)
3258 {
3259 if (sym->saved_hint == SAVED_BUILTIN_VAR)
3260 {
3261 if (sym->builtin_variable == NULL)
3262 say("\t%s\t<Placeholder>", sym->name);
3263 else
3264 {
3265 char *s;
3266 s = make_string_var_bydata((const void *)sym->builtin_variable);
3267 if (!s)
3268 s = malloc_strdup("<EMPTY>");
3269
3270 say("\t%s\t%s", sym->name, s);
3271 new_free(&s);
3272 }
3273 counter++;
3274 }
3275 }
3276
3277 if (counter)
3278 return 0;
3279 return -1;
3280 }
3281
3282 /*
3283 * Here's the plan. An all-encompasing low-level symbol manipulation thingee.
3284 * This interface is not intended to replace $aliasctl(), but rather to
3285 * supplement it. No, $aliasctl() will never be removed. Yes, much of
3286 * its functionality (but not all) is duplicated here.
3287 *
3288 * $symbolctl(TYPES)
3289 * Return all of the types supported in this version of EPIC:
3290 * ALIAS ASSIGN BUILTIN_COMMAND
3291 * BUILTIN_FUNCTION BUILTIN_EXPANDO BUILTIN_VARIABLE
3292 *
3293 * $symbolctl(PMATCH <type> <pattern>)
3294 * Return all symbols of type <type> that match <pattern>. You can use
3295 * the special value "*" for <type> to get symbols of all types.
3296 *
3297 * $symbolctl(CREATE <symbol>)
3298 * Ensure that <symbol> exists in the global symbol table. When symbols
3299 * are first created, they do not contain any actual values, but rather
3300 * act as a placeholder in case you want to set any. You must ensure
3301 * that a symbol exists before you try to change its values. CREATEing
3302 * a symbol that already exists is harmless; feel free to do it.
3303 *
3304 * $symbolctl(DELETE <symbol>)
3305 * $symbolctl(DELETE <symbol> <type>)
3306 * Delete all of the values of a particular symbol, or just one type.
3307 * Example: $symbolctl(DELETE booya ALIAS) is the same as /alias -booya
3308 * Warning: You can delete built in variables/functions/etc with this!
3309 * There's no way to restore them back if you do! Caution!
3310 *
3311 * $symbolctl(CHECK <symbol>)
3312 * Inspects <symbol> to see if it has any values left. If there are no
3313 * values left for <symbol>, it is removed from the global symbol table.
3314 * You must then CREATE it again if you want to use it later.
3315 *
3316 * *** IMPORTANT NOTE ABOUT "LEVELS" ****
3317 * In order to "get" or "set" a symbol's values, the symbol needs to exist.
3318 * If you try to "get" or "set" a symbol that doesn't exist, $symbolctl() will
3319 * return the empty string to tell you that it failed. You need to use the
3320 * CREATE operation above to bootstrap a new symbol before using it.
3321 *
3322 * Now, /STACK PUSH and /STACK POP work by manipulating "levels" in the symbol
3323 * table. By rule, <level> == 1 always refers to the "current" value of a
3324 * symbol. If you do /STACK PUSH, then the value you pushed will be copied to
3325 * <level> == 2. If you /STACK PUSH something else, that values moves to
3326 * <level> == 3. So what you can do is use "GET x LEVELS" to find out how
3327 * many levels a symbol has, and then use "GET x <num>" to find out if there
3328 * is a symbol type that interest you at that level. IN THIS WAY you can
3329 * directly manipulate the /stack push values without having to actually use
3330 * the /stack command.
3331 *
3332 * In general, <level> is always 1 for everything you want to do, unless you
3333 * are intentionally monkeying around with your /stack values.
3334 *
3335 * *** NOW BACK TO YOUR REGULARLY SCHEDULED HELP ***
3336 * $symbolctl(GET <symbol> LEVELS)
3337 * Return the number of levels of <symbol> that are /STACKed. This
3338 * value is always 1 unless you have /STACK PUSHed something.
3339 * $symbolctl(GET <symbol> <level>)
3340 * Return all of the <type>s that are defined for <symbol> at <level>.
3341 * If <level> is 1, it gets the current value(s). If <level> is > 1,
3342 * it starts looking at the /STACK PUSHed values.
3343 *
3344 * $symbolctl(GET <symbol> <level> ALIAS VALUE)
3345 * $symbolctl(GET <symbol> <level> ALIAS STUB)
3346 * $symbolctl(GET <symbol> <level> ALIAS PACKAGE)
3347 * $symbolctl(GET <symbol> <level> ALIAS ARGLIST)
3348 * Retrieve one of the values for one of your aliases
3349 *
3350 * $symbolctl(GET <symbol> <level> ASSIGN VALUE)
3351 * $symbolctl(GET <symbol> <level> ASSIGN STUB)
3352 * $symbolctl(GET <symbol> <level> ASSIGN PACKAGE)
3353 * Retrieve one of the values for one of your assigns
3354 *
3355 * $symbolctl(GET <symbol> <level> BUILTIN_COMMAND)
3356 * $symbolctl(GET <symbol> <level> BUILTIN_FUNCTION)
3357 * $symbolctl(GET <symbol> <level> BUILTIN_EXPANDO)
3358 * Returns 0 if these types are not in use (ie, if there is not a built
3359 * in command), and returns non-zero if there is. If you're smart, you
3360 * won't try to do anything with the non-zero value.
3361 *
3362 * $symbolctl(GET <symbol> <level> BUILTIN_VARIABLE TYPE)
3363 * $symbolctl(GET <symbol> <level> BUILTIN_VARIABLE DATA)
3364 * $symbolctl(GET <symbol> <level> BUILTIN_VARIABLE BUILTIN)
3365 * $symbolctl(GET <symbol> <level> BUILTIN_VARIABLE SCRIPT)
3366 * $symbolctl(GET <symbol> <level> BUILTIN_VARIABLE FLAGS)
3367 * Retrieve information about a /SET.
3368 * The "TYPE" is one of "STR", "INT", "BOOL", or "CHAR"
3369 * Generally, either "BUILTIN" or "SCRIPT" is set, but not both.
3370 *
3371 * $symbolctl(SET <symbol> <level> ALIAS VALUE <string>)
3372 * $symbolctl(SET <symbol> <level> ALIAS STUB <string>)
3373 * $symbolctl(SET <symbol> <level> ALIAS PACKAGE <string>)
3374 * $symbolctl(SET <symbol> <level> ALIAS ARGLIST <string>)
3375 * Change one of the values for one of your aliases. If you omit
3376 * the <string>, it will clear the value.
3377 *
3378 * $symbolctl(SET <symbol> <level> ASSIGN VALUE <string>)
3379 * $symbolctl(SET <symbol> <level> ASSIGN STUB <string>)
3380 * $symbolctl(SET <symbol> <level> ASSIGN PACKAGE <string>)
3381 * Change one of the values for one of your assigns. If you omit
3382 * the <string>, it will clear the value.
3383 *
3384 * $symbolctl(SET <symbol> <level> BUILTIN_VARIABLE)
3385 * Create a new user-created /SET with default values (type == BOOL,
3386 * data == OFF, script is <empty>.)
3387 * $symbolctl(SET <symbol> <level> BUILTIN_VARIABLE TYPE <set-type>)
3388 * $symbolctl(SET <symbol> <level> BUILTIN_VARIABLE DATA <string>)
3389 * $symbolctl(SET <symbol> <level> BUILTIN_VARIABLE BUILTIN)
3390 * $symbolctl(SET <symbol> <level> BUILTIN_VARIABLE SCRIPT <code>)
3391 * $symbolctl(SET <symbol> <level> BUILTIN_VARIABLE FLAGS)
3392 * Change one of the values for one of your /set's. You cannot change
3393 * values for system /set's, sorry. Setting the TYPE value changes the
3394 * DATA value to a default (<empty> for strings, 0 for everything else)
3395 * so always set DATA after setting TYPE.
3396 * Yes, you can change the TYPE of a /set after you create it!
3397 * It's probably a bad idea to set FLAGS for the present.
3398 */
symbolctl(char * input)3399 char *symbolctl (char *input)
3400 {
3401 int len;
3402 char *listc;
3403 char *ret = NULL;
3404 size_t clue = 0;
3405 Symbol *s;
3406 int i;
3407 int level;
3408 char *symbol, *type, *pattern, *attr;
3409 int cnt, l;
3410
3411 GET_FUNC_ARG(listc, input);
3412 len = strlen(listc);
3413
3414 if (!my_strnicmp(listc, "TYPES", len)) {
3415 for (i = 0; symbol_types[i]; i++)
3416 malloc_strcat_word_c(&ret, space, symbol_types[i], DWORD_DWORDS, &clue);
3417 RETURN_MSTR(ret);
3418
3419 } else if (!my_strnicmp(listc, "PMATCH", len)) {
3420 char **names;
3421 int num = 0;
3422 int maxret = 0;
3423 int start = 0;
3424 int rev = 0;
3425
3426 GET_FUNC_ARG(type, input);
3427 GET_FUNC_ARG(pattern, input);
3428 if (!my_stricmp(type, "ALIAS")) {
3429 names = pmatch_cmd_alias(pattern, &num, maxret, start, rev);
3430 } else if (!my_stricmp(type, "ASSIGN")) {
3431 names = pmatch_assign_alias(pattern, &num, maxret, start, rev);
3432 } else if (!my_stricmp(type, "BUILTIN_COMMAND")) {
3433 names = pmatch_builtin_commands(pattern, &num, maxret, start, rev);
3434 } else if (!my_stricmp(type, "BUILTIN_FUNCTION")) {
3435 names = pmatch_builtin_functions(pattern, &num, maxret, start, rev);
3436 } else if (!my_stricmp(type, "BUILTIN_EXPANDO")) {
3437 names = pmatch_builtin_expandos(pattern, &num, maxret, start, rev);
3438 } else if (!my_stricmp(type, "BUILTIN_VARIABLE")) {
3439 names = pmatch_builtin_variables(pattern, &num, maxret, start, rev);
3440 } else if (!my_stricmp(type, "*")) {
3441 names = pmatch_any_symbol(pattern, &num, maxret, start, rev);
3442 } else
3443 RETURN_EMPTY;
3444
3445 for (i = 0; i < num; i++)
3446 malloc_strcat_word_c(&ret, space, names[i], DWORD_DWORDS, &clue);
3447 new_free((char **)&names);
3448 RETURN_MSTR(ret);
3449
3450 } else if (!my_strnicmp(listc, "CREATE", len)) {
3451 GET_FUNC_ARG(symbol, input);
3452 upper(symbol);
3453 s = (Symbol *)find_array_item((array *)&globals, symbol, &cnt, &l);
3454 if (!s || cnt >= 0)
3455 {
3456 s = make_new_Symbol(symbol);
3457 add_to_array((array *)&globals, (array_item *)s);
3458 RETURN_INT(1);
3459 }
3460 RETURN_INT(0);
3461
3462 } else if (!my_strnicmp(listc, "DELETE", len)) {
3463 GET_FUNC_ARG(symbol, input);
3464 upper(symbol);
3465 s = (Symbol *)find_array_item((array *)&globals, symbol, &cnt, &l);
3466 if (s && cnt < 0) {
3467 int all = 0;
3468
3469 if (!input || !*input)
3470 all = 1;
3471 if (all || !my_stricmp(input, "ASSIGN")) {
3472 new_free(&s->user_variable);
3473 s->user_variable_stub = 0;
3474 new_free(&s->user_variable_package);
3475 }
3476 if (all || !my_stricmp(input, "ALIAS")) {
3477 new_free(&s->user_command);
3478 s->user_command_stub = 0;
3479 new_free(&s->user_command_package);
3480 destroy_arglist(&s->arglist);
3481 }
3482 if (all || !my_stricmp(input, "BUILTIN_COMMAND"))
3483 s->builtin_command = NULL;
3484 if (all || !my_stricmp(input, "BUILTIN_FUNCTION"))
3485 s->builtin_function = NULL;
3486 if (all || !my_stricmp(input, "BUILTIN_EXPANDO"))
3487 s->builtin_expando = NULL;
3488 if (all || !my_stricmp(input, "BUILTIN_VARIABLE")) {
3489 if (s->builtin_variable && is_var_builtin(symbol))
3490 RETURN_INT(0);
3491 if (s->builtin_variable) {
3492 new_free(&s->builtin_variable->script);
3493 if (s->builtin_variable->type == STR_VAR)
3494 new_free(&s->builtin_variable->data->string);
3495 new_free(&s->builtin_variable->data);
3496 new_free(&s->builtin_variable);
3497 }
3498 }
3499 GC_symbol(s, (array *)&globals, l);
3500 RETURN_INT(1);
3501 }
3502 RETURN_INT(0);
3503
3504 } else if (!my_strnicmp(listc, "CHECK", len)) {
3505 GET_FUNC_ARG(symbol, input);
3506 upper(symbol);
3507 s = (Symbol *)find_array_item((array *)&globals, symbol, &cnt, &l);
3508 if (s && cnt < 0) {
3509 GC_symbol(s, (array *)&globals, l);
3510 RETURN_INT(1);
3511 }
3512 RETURN_INT(0);
3513
3514 } else if (!my_strnicmp(listc, "GET", len)) {
3515 char *x;
3516
3517 GET_FUNC_ARG(symbol, input);
3518 upper(symbol);
3519 s = (Symbol *)find_array_item((array *)&globals, symbol, &cnt, &l);
3520 if (!s || cnt >= 0)
3521 RETURN_EMPTY;
3522
3523 GET_FUNC_ARG(x, input)
3524 if (!(my_stricmp(x, "LEVELS"))) {
3525 i = 1;
3526 while (s->saved)
3527 i++, s = s->saved;
3528 RETURN_INT(i);
3529 }
3530
3531 GET_INT_ARG(level, x);
3532 for (i = 1; i < level; i++)
3533 {
3534 if (!s->saved)
3535 RETURN_EMPTY;
3536 s = s->saved;
3537 }
3538
3539 if (!input || !*input) {
3540 if (s->user_variable || s->user_variable_stub)
3541 malloc_strcat_word_c(&ret, space, "ASSIGN", DWORD_NO, &clue);
3542 if (s->user_command || s->user_command_stub)
3543 malloc_strcat_word_c(&ret, space, "ALIAS", DWORD_NO, &clue);
3544 if (s->builtin_command)
3545 malloc_strcat_word_c(&ret, space, "BUILTIN_COMMAND", DWORD_NO, &clue);
3546 if (s->builtin_function)
3547 malloc_strcat_word_c(&ret, space, "BUILTIN_FUNCTION", DWORD_NO, &clue);
3548 if (s->builtin_expando)
3549 malloc_strcat_word_c(&ret, space, "BUILTIN_EXPANDO", DWORD_NO, &clue);
3550 if (s->builtin_variable)
3551 malloc_strcat_word_c(&ret, space, "BUILTIN_VARIABLE", DWORD_NO, &clue);
3552 RETURN_MSTR(ret);
3553 }
3554
3555 GET_FUNC_ARG(type, input);
3556 if (!my_stricmp(type, "ALIAS")) {
3557 GET_FUNC_ARG(attr, input);
3558 if (!my_stricmp(attr, "VALUE"))
3559 RETURN_STR(s->user_command);
3560 else if (!my_stricmp(attr, "STUB"))
3561 RETURN_INT(s->user_command_stub);
3562 else if (!my_stricmp(attr, "PACKAGE"))
3563 RETURN_STR(s->user_command_package);
3564 else if (!my_stricmp(attr, "ARGLIST"))
3565 RETURN_MSTR(print_arglist(s->arglist));
3566 else
3567 RETURN_EMPTY;
3568 } else if (!my_stricmp(type, "ASSIGN")) {
3569 GET_FUNC_ARG(attr, input);
3570 if (!my_stricmp(attr, "VALUE"))
3571 RETURN_STR(s->user_variable);
3572 else if (!my_stricmp(attr, "STUB"))
3573 RETURN_INT(s->user_variable_stub);
3574 else if (!my_stricmp(attr, "PACKAGE"))
3575 RETURN_STR(s->user_variable_package);
3576 else
3577 RETURN_EMPTY;
3578 } else if (!my_stricmp(type, "BUILTIN_COMMAND")) {
3579 RETURN_INT((long)s->builtin_command);
3580 } else if (!my_stricmp(type, "BUILTIN_FUNCTION")) {
3581 RETURN_INT((long)s->builtin_function);
3582 } else if (!my_stricmp(type, "BUILTIN_EXPANDO")) {
3583 RETURN_INT((long)s->builtin_expando);
3584 } else if (!my_stricmp(type, "BUILTIN_VARIABLE")) {
3585 if (!s->builtin_variable)
3586 RETURN_EMPTY;
3587
3588 GET_FUNC_ARG(attr, input);
3589 if (!my_stricmp(attr, "TYPE")) {
3590 switch (s->builtin_variable->type) {
3591 case STR_VAR: RETURN_STR("STR");
3592 case INT_VAR: RETURN_STR("INT");
3593 case BOOL_VAR: RETURN_STR("BOOL");
3594 case CHAR_VAR: RETURN_STR("CHAR");
3595 default: RETURN_STR("???");
3596 }
3597 } else if (!my_stricmp(attr, "DATA"))
3598 RETURN_MSTR(make_string_var_bydata((const void *)s->builtin_variable));
3599 else if (!my_stricmp(attr, "FUNC"))
3600 RETURN_INT((long)s->builtin_variable->func);
3601 else if (!my_stricmp(attr, "SCRIPT"))
3602 RETURN_STR(s->builtin_variable->script);
3603 else if (!my_stricmp(attr, "FLAGS"))
3604 RETURN_INT(s->builtin_variable->pending);
3605 else if (!my_stricmp(attr, "PENDING"))
3606 RETURN_INT(s->builtin_variable->pending);
3607 else
3608 RETURN_EMPTY;
3609 } else
3610 RETURN_EMPTY;
3611 } else if (!my_strnicmp(listc, "SET", len)) {
3612 char *x;
3613
3614 GET_FUNC_ARG(symbol, input);
3615 upper(symbol);
3616 s = (Symbol *)find_array_item((array *)&globals, symbol, &cnt, &l);
3617 if (!s || cnt >= 0)
3618 RETURN_EMPTY;
3619
3620 GET_FUNC_ARG(x, input)
3621 GET_INT_ARG(level, x);
3622 for (i = 1; i < level; i++)
3623 {
3624 if (!s->saved)
3625 RETURN_EMPTY;
3626 s = s->saved;
3627 }
3628
3629 GET_FUNC_ARG(type, input);
3630 if (!my_stricmp(type, "ALIAS")) {
3631 GET_FUNC_ARG(attr, input);
3632 if (!my_stricmp(attr, "VALUE")) {
3633 if (input && *input)
3634 malloc_strcpy(&s->user_command, input);
3635 else
3636 new_free(&s->user_command);
3637 RETURN_INT(1);
3638 } else if (!my_stricmp(attr, "STUB")) {
3639 if (is_number(input)) {
3640 s->user_command_stub = my_atol(input);
3641 RETURN_INT(1);
3642 }
3643 RETURN_EMPTY;
3644 } else if (!my_stricmp(attr, "PACKAGE")) {
3645 if (input && *input)
3646 malloc_strcpy(&s->user_command_package, input);
3647 else
3648 new_free(&s->user_command_package);
3649 RETURN_INT(1);
3650 } else if (!my_stricmp(attr, "ARGLIST")) {
3651 destroy_arglist(&s->arglist);
3652 if (input && *input)
3653 s->arglist = parse_arglist(input);
3654 RETURN_INT(1);
3655 } else
3656 RETURN_EMPTY;
3657 } else if (!my_stricmp(type, "ASSIGN")) {
3658 GET_FUNC_ARG(attr, input);
3659 if (!my_stricmp(attr, "VALUE")) {
3660 if (input && *input)
3661 malloc_strcpy(&s->user_variable, input);
3662 else
3663 new_free(&s->user_variable);
3664 RETURN_INT(1);
3665 } else if (!my_stricmp(attr, "STUB")) {
3666 if (is_number(input)) {
3667 s->user_variable_stub = my_atol(input);
3668 RETURN_INT(1);
3669 }
3670 RETURN_EMPTY;
3671 } else if (!my_stricmp(attr, "PACKAGE")) {
3672 if (input && *input)
3673 malloc_strcpy(&s->user_variable_package, input);
3674 else
3675 new_free(&s->user_variable_package);
3676 RETURN_INT(1);
3677 } else
3678 RETURN_EMPTY;
3679 } else if (!my_stricmp(type, "BUILTIN_COMMAND")) {
3680 RETURN_EMPTY;
3681 } else if (!my_stricmp(type, "BUILTIN_FUNCTION")) {
3682 RETURN_EMPTY;
3683 } else if (!my_stricmp(type, "BUILTIN_EXPANDO")) {
3684 RETURN_EMPTY;
3685 } else if (!my_stricmp(type, "BUILTIN_VARIABLE")) {
3686 IrcVariable *v;
3687
3688 if (s->builtin_variable) {
3689 /* Not permitted to change a builtin variable */
3690 if (s->builtin_variable->func)
3691 RETURN_EMPTY;
3692 v = s->builtin_variable;
3693 } else {
3694 v = (IrcVariable *)new_malloc(sizeof(IrcVariable));
3695 v->type = BOOL_VAR;
3696 v->data = new_malloc(sizeof(union builtin_variable));
3697 v->data->integer = 0;
3698 v->pending = 0;
3699 v->func = NULL;
3700 v->script = NULL;
3701 add_builtin_variable_alias(symbol, v);
3702 }
3703
3704 GET_FUNC_ARG(attr, input);
3705 if (!my_stricmp(attr, "TYPE")) {
3706 int newval;
3707
3708 if (!input)
3709 RETURN_EMPTY;
3710
3711 if (!my_stricmp(input, "BOOL")) newval = BOOL_VAR;
3712 else if (!my_stricmp(input, "STR")) newval = STR_VAR;
3713 else if (!my_stricmp(input, "INT")) newval = INT_VAR;
3714 else if (!my_stricmp(input, "CHAR")) newval = CHAR_VAR;
3715 else
3716 RETURN_EMPTY;
3717
3718 if (v->type == STR_VAR)
3719 new_free(&v->data->string);
3720 if (newval == STR_VAR)
3721 v->data->string = NULL;
3722 else
3723 v->data->integer = 0;
3724
3725 v->type = newval;
3726 RETURN_INT(1);
3727 } else if (!my_stricmp(attr, "DATA")) {
3728 if (!*input)
3729 input = NULL;
3730 RETURN_INT(set_variable(symbol, v, input, 0));
3731 } else if (!my_stricmp(attr, "FUNC")) {
3732 RETURN_EMPTY; /* Can't do this */
3733 } else if (!my_stricmp(attr, "SCRIPT")) {
3734 if (input && *input)
3735 malloc_strcpy(&v->script, input);
3736 else
3737 new_free(&v->script);
3738 RETURN_INT(1);
3739 } else if (!my_stricmp(attr, "FLAGS")) {
3740 if (!is_number(input))
3741 RETURN_EMPTY;
3742 v->pending = my_atol(input);
3743 RETURN_INT(1);
3744 } else if (!my_stricmp(attr, "PENDING")) {
3745 if (!is_number(input))
3746 RETURN_EMPTY;
3747 v->pending = my_atol(input);
3748 RETURN_INT(1);
3749 } else
3750 RETURN_EMPTY;
3751 } else
3752 RETURN_EMPTY;
3753 } else
3754 RETURN_EMPTY;
3755 }
3756
3757 /* Pure fantasy for now. */
3758 #if 0
3759 /* Statements are either blocks, expressions, or commands */
3760 enum StatementTypeE {
3761 BLOCK_STATEMENT,
3762 EXPR_STATEMENT,
3763 CMD_STATEMENT
3764 };
3765
3766 /* A block is a collection of statements */
3767 struct BlockT {
3768 size_t numcmds;
3769 union StatementT *cmds;
3770 };
3771
3772 /* A command statement has a command, and an argument list */
3773 struct CommandStatementT {
3774 enum StatementTypeE type;
3775 wchar_t * cmd;
3776 wchar_t * args;
3777 };
3778
3779 /* An expression statement has a math expression */
3780 struct ExpressionStatementT {
3781 enum StatementTypeE type;
3782 wchar_t * expr;
3783 };
3784
3785 /* A block statement has a block (natch) */
3786 struct BlockStatementT {
3787 enum StatementTypeE type;
3788 struct BlockT block;
3789 };
3790
3791 /*
3792 * A statement is either a command statement,
3793 * an expression statement, or a block statement.
3794 */
3795 union StatementT {
3796 enum StatementTypeE type;
3797 struct CommandStatementT;
3798 struct ExpressionStatementT;
3799 struct BlockStatementT;
3800 #endif
3801
3802