Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
BitchX
GitHub Repository: BitchX/BitchX1.3
Path: blob/master/source/alias.c
1069 views
1
/*
2
* alias.c Handles command aliases for irc.c
3
*
4
* Written By Michael Sandrof
5
*
6
* Copyright(c) 1990, 1995 Michael Sandroff and others
7
*
8
* See the COPYRIGHT file, or do a HELP IRCII COPYRIGHT
9
*/
10
11
#define _cs_alist_hash_
12
#include "irc.h"
13
static char cvsrevision[] = "$Id: alias.c 26 2008-04-30 13:57:56Z keaston $";
14
CVS_REVISION(alias_c)
15
#include "struct.h"
16
#include "alias.h"
17
#include "alist.h"
18
#include "array.h"
19
#include "dcc.h"
20
#include "commands.h"
21
#include "files.h"
22
#include "history.h"
23
#include "hook.h"
24
#include "input.h"
25
#include "ircaux.h"
26
#include "names.h"
27
#include "notify.h"
28
#include "numbers.h"
29
#include "output.h"
30
#include "parse.h"
31
#include "screen.h"
32
#include "server.h"
33
#include "status.h"
34
#include "vars.h"
35
#include "window.h"
36
#include "ircterm.h"
37
#include "server.h"
38
#include "list.h"
39
#include "keys.h"
40
#include "userlist.h"
41
#include "misc.h"
42
#include "newio.h"
43
#include "stack.h"
44
#include "module.h"
45
#include "timer.h"
46
#define MAIN_SOURCE
47
#include "modval.h"
48
49
#include <sys/stat.h>
50
51
#define LEFT_BRACE '{'
52
#define RIGHT_BRACE '}'
53
#define LEFT_BRACKET '['
54
#define RIGHT_BRACKET ']'
55
#define LEFT_PAREN '('
56
#define RIGHT_PAREN ')'
57
#define DOUBLE_QUOTE '"'
58
59
#ifdef WANT_DLL
60
#ifdef dll_functions
61
#error blah
62
#endif
63
BuiltInDllFunctions *dll_functions = NULL;
64
#endif
65
66
67
68
/* Used for statistics gathering */
69
static unsigned long alias_total_allocated = 0;
70
static unsigned long alias_total_bytes_allocated = 0;
71
static unsigned long var_cache_hits = 0;
72
static unsigned long var_cache_misses = 0;
73
static unsigned long var_cache_missed_by = 0;
74
static unsigned long var_cache_passes = 0;
75
static unsigned long cmd_cache_hits = 0;
76
static unsigned long cmd_cache_misses = 0;
77
static unsigned long cmd_cache_missed_by = 0;
78
static unsigned long cmd_cache_passes = 0;
79
80
int last_function_call_level = -1;
81
82
/* Ugh. XXX Bag on the side */
83
ArgList *parse_arglist (char *arglist);
84
void destroy_arglist (ArgList *);
85
86
87
static void delete_all_var_alias (char *name);
88
static void delete_cmd_alias (char *name, int owd);
89
static void list_cmd_alias (char *name);
90
static void list_var_alias (char *name);
91
static void list_local_alias (char *name);
92
static char * get_variable_with_args (const char *str, const char *args, int *args_flag);
93
void add_cmd_alias (char *, ArgList *, char *);
94
95
/*
96
* after_expando: This replaces some much more complicated logic strewn
97
* here and there that attempted to figure out just how long an expando
98
* name was supposed to be. Well, now this changes that. This will slurp
99
* up everything in 'start' that could possibly be put after a $ that could
100
* result in a syntactically valid expando. All you need to do is tell it
101
* if the expando is an rvalue or an lvalue (it *does* make a difference)
102
*/
103
static char *lval[] = { "rvalue", "lvalue" };
104
char *after_expando (char *start, int lvalue, int *call)
105
{
106
char *rest;
107
char *str;
108
109
/*
110
* One or two leading colons are allowed
111
*/
112
if (!*start)
113
return start;
114
115
str = start;
116
if (*str == ':')
117
if (*++str == ':')
118
++str;
119
120
/*
121
* This handles 99.99% of the cases
122
*/
123
while (*str && (isalpha((unsigned char)*str) || isdigit((unsigned char)*str) || *str == '_' || *str == '.'))
124
str++;
125
126
/*
127
* This handles any places where a var[var] could sneak in on
128
* us. Supposedly this should never happen, but who can tell?
129
*/
130
while (*str == '[')
131
{
132
if (!(rest = MatchingBracket(str + 1, '[', ']')))
133
{
134
if (!(rest = strchr(str, ']')))
135
{
136
debugyell("Unmatched bracket in %s (%s)",
137
lval[lvalue], start);
138
return empty_string;
139
}
140
}
141
str = rest + 1;
142
}
143
144
/*
145
* Rvalues may include a function call, slurp up the argument list.
146
*/
147
if (!lvalue && *str == '(')
148
{
149
if (!(rest = MatchingBracket(str + 1, '(', ')')))
150
{
151
if (!(rest = strchr(str, ')')))
152
{
153
debugyell("Unmatched paren in %s (%s)",
154
lval[lvalue], start);
155
return empty_string;
156
}
157
}
158
*call = 1;
159
str = rest + 1;
160
}
161
162
/*
163
* If the entire thing looks to be invalid, perhaps its a
164
* special built-in expando. Check to see if it is, and if it
165
* is, then slurp up the first character as valid.
166
*/
167
if (str == start || (str == start + 1 && *start == ':'))
168
{
169
int is_builtin = 0;
170
171
built_in_alias(*start, &is_builtin);
172
if (is_builtin && (str == start))
173
str++;
174
}
175
176
177
178
/*
179
* All done!
180
*/
181
return str;
182
}
183
184
185
/*
186
* aliascmd: The user interface for /ALIAS
187
*/
188
BUILT_IN_COMMAND(aliascmd)
189
{
190
char *name;
191
char *real_name;
192
char *ptr;
193
void show_alias_caches(void);
194
195
/*
196
* If no name present, list all aliases
197
*/
198
if (!(name = next_arg(args, &args)))
199
{
200
list_cmd_alias(NULL);
201
return;
202
}
203
204
/*
205
* Alias can take an /s arg, which shows some data we've collected
206
*/
207
if (!my_strnicmp(name, "/S", 2))
208
{
209
extern u_32int_t bin_ints;
210
extern u_32int_t lin_ints;
211
extern u_32int_t bin_chars;
212
extern u_32int_t lin_chars;
213
extern u_32int_t alist_searches;
214
extern u_32int_t char_searches;
215
216
say("Total aliases handled: %ld",
217
alias_total_allocated);
218
say("Total bytes allocated to aliases: %ld",
219
alias_total_bytes_allocated);
220
221
say("Var command hits/misses/passes/missed-by [%ld/%ld/%ld/%3.1f]",
222
var_cache_hits,
223
var_cache_misses,
224
var_cache_passes,
225
( var_cache_misses ? (double)
226
(var_cache_missed_by / var_cache_misses) : 0.0));
227
say("Cmd command hits/misses/passes/missed-by [%ld/%ld/%ld/%3.1f]",
228
cmd_cache_hits,
229
cmd_cache_misses,
230
cmd_cache_passes,
231
( cmd_cache_misses ? (double)
232
(cmd_cache_missed_by / cmd_cache_misses) : 0.0));
233
say("Ints(bin/lin)/Chars(bin/lin)/Lookups: [(%d/%d)/(%d/%d)] (%d/%d)",
234
bin_ints, lin_ints, bin_chars, lin_chars,
235
alist_searches, char_searches);
236
show_alias_caches();
237
return;
238
}
239
240
/*
241
* Canonicalize the alias name
242
*/
243
real_name = remove_brackets(name, NULL, NULL);
244
245
/*
246
* Find the argument body
247
*/
248
while (my_isspace(*args))
249
args++;
250
251
/*
252
* If there is no argument body, we probably want to delete alias
253
*/
254
if (!args || !*args)
255
{
256
/*
257
* If the alias name starts with a hyphen, then we are
258
* going to delete it.
259
*/
260
if (real_name[0] == '-')
261
{
262
if (real_name[1])
263
delete_cmd_alias(real_name + 1, window_display);
264
else
265
say("You must specify an alias to be removed.");
266
}
267
268
/*
269
* Otherwise, the user wants us to list that alias
270
*/
271
else
272
list_cmd_alias(real_name);
273
}
274
275
/*
276
* If there is an argument body, then we have to register it
277
*/
278
else
279
{
280
ArgList *arglist = NULL;
281
282
/*
283
* Aliases may contain a parameter list, which is parsed
284
* at registration time.
285
*/
286
if (*args == LEFT_PAREN)
287
{
288
ptr = MatchingBracket(++args, LEFT_PAREN, RIGHT_PAREN);
289
if (!ptr)
290
say("Unmatched lparen in %s %s",
291
command, real_name);
292
else
293
{
294
*ptr++ = 0;
295
while (*ptr && my_isspace(*ptr))
296
ptr++;
297
if (!*ptr)
298
say("Missing alias body in %s %s",
299
command, real_name);
300
301
while (*args && my_isspace(*args))
302
args++;
303
304
arglist = parse_arglist(args);
305
args = ptr;
306
}
307
}
308
309
/*
310
* Aliases' bodies can be surrounded by a set of braces,
311
* which are stripped off.
312
*/
313
if (*args == LEFT_BRACE)
314
{
315
ptr = MatchingBracket(++args, LEFT_BRACE, RIGHT_BRACE);
316
317
if (!ptr)
318
say("Unmatched brace in %s %s", command, real_name);
319
else
320
{
321
*ptr++ = 0;
322
while (*ptr && my_isspace(*ptr))
323
ptr++;
324
325
if (*ptr)
326
say("Junk [%s] after closing brace in %s %s", ptr, command, real_name);
327
328
while (*args && my_isspace(*args))
329
args++;
330
331
}
332
}
333
334
/*
335
* Register the alias
336
*/
337
add_cmd_alias(real_name, arglist, args);
338
}
339
340
new_free(&real_name);
341
return;
342
}
343
344
345
BUILT_IN_COMMAND(purge)
346
{
347
char *arg, *real_name;
348
while ((arg = next_arg(args, &args)))
349
{
350
real_name = remove_brackets(arg, NULL, NULL);
351
delete_all_var_alias(real_name);
352
new_free(&real_name);
353
}
354
}
355
356
/*
357
* User front end to the ASSIGN command
358
* Syntax to add variable: ASSIGN name text
359
* Syntax to delete variable: ASSIGN -name
360
*/
361
BUILT_IN_COMMAND(assigncmd)
362
{
363
char *real_name;
364
char *name;
365
366
/*
367
* If there are no arguments, list all the global variables
368
*/
369
if (!(name = next_arg(args, &args)))
370
{
371
list_var_alias(NULL);
372
return;
373
}
374
375
/*
376
* Canonicalize the variable name
377
*/
378
real_name = remove_brackets(name, NULL, NULL);
379
380
/*
381
* Find the stuff to assign to the variable
382
*/
383
while (my_isspace(*args))
384
args++;
385
386
/*
387
* If there is no body, then the user probably wants to delete
388
* the variable
389
*/
390
if (!args || !*args)
391
{
392
/*
393
* If the variable name starts with a hyphen, then we remove
394
* the variable
395
*/
396
if (real_name[0] == '-')
397
{
398
if (real_name[1])
399
delete_var_alias(real_name + 1, window_display);
400
else
401
say("You must specify an alias to be removed.");
402
}
403
404
/*
405
* Otherwise, the user wants us to list the variable
406
*/
407
else
408
list_var_alias(real_name);
409
}
410
411
/*
412
* Register the variable
413
*/
414
else
415
add_var_alias(real_name, args);
416
417
new_free(&real_name);
418
return;
419
}
420
421
/*
422
* User front end to the STUB command
423
* Syntax to stub an alias to a file: STUB ALIAS name[,name] filename(s)
424
* Syntax to stub a variable to a file: STUB ASSIGN name[,name] filename(s)
425
*/
426
BUILT_IN_COMMAND(stubcmd)
427
{
428
int type;
429
char *cmd;
430
char *name;
431
432
/*
433
* The first argument is the type of stub to make
434
* (alias or assign)
435
*/
436
if (!(cmd = upper(next_arg(args, &args))))
437
{
438
error("Missing Stub type");
439
return;
440
}
441
442
if (!strncmp(cmd, "ALIAS", strlen(cmd)))
443
type = COMMAND_ALIAS;
444
else if (!strncmp(cmd, "ASSIGN", strlen(cmd)))
445
type = VAR_ALIAS;
446
else
447
{
448
error("[%s] is an Unrecognized stub type", cmd);
449
return;
450
}
451
452
/*
453
* The next argument is the name of the item to be stubbed.
454
* This is not optional.
455
*/
456
if (!(name = next_arg(args, &args)))
457
{
458
error("Missing alias name");
459
return;
460
}
461
462
/*
463
* Find the filename argument
464
*/
465
while (my_isspace(*args))
466
args++;
467
468
/*
469
* The rest of the argument(s) are the files to load when the
470
* item is referenced. This is not optional.
471
*/
472
if (!args || !*args)
473
{
474
error("Missing file name");
475
return;
476
}
477
478
/*
479
* Now we iterate over the item names we were given. For each
480
* item name, seperated from the next by a comma, stub that item
481
* to the given filename(s) specified as the arguments.
482
*/
483
while (name && *name)
484
{
485
char *next_name;
486
char *real_name;
487
488
if ((next_name = strchr(name, ',')))
489
*next_name++ = 0;
490
491
real_name = remove_brackets(name, NULL, NULL);
492
if (type == COMMAND_ALIAS)
493
add_cmd_stub_alias(real_name, args);
494
else
495
add_var_stub_alias(real_name, args);
496
497
new_free(&real_name);
498
name = next_name;
499
}
500
}
501
502
BUILT_IN_COMMAND(localcmd)
503
{
504
char *name;
505
506
if (!(name = next_arg(args, &args)))
507
{
508
list_local_alias(NULL);
509
return;
510
}
511
512
while (args && *args && my_isspace(*args))
513
args++;
514
515
if (!args)
516
args = empty_string;
517
518
while (name && *name)
519
{
520
char *next_name;
521
char *real_name;
522
523
if ((next_name = strchr(name, ',')))
524
*next_name++ = 0;
525
526
real_name = remove_brackets(name, NULL, NULL);
527
add_local_alias(real_name, args);
528
new_free(&real_name);
529
name = next_name;
530
}
531
}
532
533
BUILT_IN_COMMAND(dumpcmd)
534
{
535
FILE *fp;
536
char *filename = NULL;
537
char *expand = NULL;
538
char *blah;
539
540
if (!args || !*args)
541
{
542
if (!command)
543
{
544
destroy_aliases(COMMAND_ALIAS);
545
destroy_aliases(VAR_ALIAS);
546
destroy_aliases(VAR_ALIAS_LOCAL);
547
flush_on_hooks();
548
delete_all_ext_fset();
549
delete_all_timers();
550
delete_all_arrays();
551
}
552
return;
553
554
}
555
while ((blah = next_arg(args, &args)))
556
{
557
if (!my_strnicmp(blah,"FI",2))
558
{
559
#ifdef PUBLIC_ACCESS
560
bitchsay("This command has been disabled on a public access system");
561
return;
562
#else
563
malloc_sprintf(&filename, "~/%s.dump", version);
564
expand = expand_twiddle(filename);
565
new_free(&filename);
566
if ((fp = fopen(expand, "w")) != NULL)
567
{
568
save_bindings(fp, 0);
569
save_hooks(fp, 0);
570
save_variables(fp, 0);
571
save_aliases(fp, 0);
572
save_assigns(fp, 0);
573
save_servers(fp);
574
fclose(fp);
575
}
576
bitchsay("Saved to ~/%s.dump", version);
577
new_free(&expand);
578
#endif
579
}
580
else if (!my_strnicmp(blah,"BIND",4) || !my_strnicmp(blah, "KEY", 3))
581
{
582
remove_bindings();
583
init_keys();
584
init_keys2();
585
}
586
else if (!my_strnicmp(blah, "AR", 2))
587
delete_all_arrays();
588
else if (!my_strnicmp(blah,"V",1))
589
destroy_aliases(VAR_ALIAS);
590
else if (!my_strnicmp(blah,"ALI",3))
591
destroy_aliases(COMMAND_ALIAS);
592
else if (!my_strnicmp(blah,"O",1))
593
flush_on_hooks();
594
else if (!my_strnicmp(blah,"CH",2))
595
flush_channel_stats();
596
else if (!my_strnicmp(blah,"LO",2))
597
destroy_aliases(VAR_ALIAS_LOCAL);
598
else if (!my_strnicmp(blah, "TI", 2))
599
delete_all_timers();
600
else if (!my_strnicmp(blah, "FS", 2))
601
{
602
create_fsets(NULL, get_int_var(DISPLAY_ANSI_VAR));
603
delete_all_ext_fset();
604
}
605
else if (!my_strnicmp(blah, "WS", 2))
606
{
607
Window *win = NULL;
608
while (traverse_all_windows(&win))
609
{
610
if (win->wset)
611
{
612
remove_wsets_for_window(win);
613
win->wset = create_wsets_for_window(win);
614
build_status(win, NULL, 0);
615
}
616
}
617
}
618
else if (!my_strnicmp(blah, "CS", 2))
619
{
620
ChannelList *chan;
621
if (from_server == -1)
622
return;
623
for (chan = get_server_channels(from_server); chan; chan = chan->next)
624
{
625
remove_csets_for_channel(chan->csets);
626
chan->csets = create_csets_for_channel(chan->channel);
627
}
628
}
629
else if (!my_strnicmp(blah,"ALL",3))
630
{
631
remove_bindings();
632
init_keys();
633
init_keys2();
634
destroy_aliases(COMMAND_ALIAS);
635
destroy_aliases(VAR_ALIAS);
636
destroy_aliases(VAR_ALIAS_LOCAL);
637
flush_on_hooks();
638
delete_all_timers();
639
delete_all_ext_fset();
640
delete_all_arrays();
641
}
642
}
643
}
644
645
/*
646
* Argument lists look like this:
647
*
648
* LIST := LPAREN TERM [COMMA TERM] RPAREN)
649
* LPAREN := '('
650
* RPAREN := ')'
651
* COMMA := ','
652
* TERM := LVAL QUAL | "..." | "void"
653
* LVAL := <An alias name>
654
* QUAL := NUM "words"
655
*
656
* In English:
657
* An argument list is a comma seperated list of variable descriptors (TERM)
658
* enclosed in a parenthesis set. Each variable descriptor may contain any
659
* valid alias name followed by an action qualifier, or may be the "..."
660
* literal string, or may be the "void" literal string. If a variable
661
* descriptor is an alias name, then that positional argument will be removed
662
* from the argument list and assigned to that variable. If the qualifier
663
* specifies how many words are to be taken, then that many are taken.
664
* If the variable descriptor is the literal string "...", then all argument
665
* list parsing stops there and all remaining alias arguments are placed
666
* into the $* special variable. If the variable descriptor is the literal
667
* string "void", then the balance of the remaining alias arguments are
668
* discarded and $* will expand to the false value. If neither "..." nor
669
* "void" are provided in the argument list, then that last variable in the
670
* list will recieve all of the remaining arguments left at its position.
671
*
672
* Examples:
673
*
674
* # This example puts $0 in $channel, $1 in $mag, and $2- in $nicklist.
675
* /alias opalot (channel, mag, nicklist) {
676
* fe ($nicklist) xx yy zz {
677
* mode $channel ${mag}ooo $xx $yy $zz
678
* }
679
* }
680
*
681
* # This example puts $0 in $channel, $1 in $mag, and the new $* is old $2-
682
* /alias opalot (channel, mag, ...) {
683
* fe ($*) xx yy zz {
684
* mode $channel ${mag}ooo $xx $yy $zz
685
* }
686
* }
687
*
688
* # This example throws away any arguments passed to this alias
689
* /alias booya (void) { echo Booya! }
690
*/
691
ArgList *parse_arglist (char *arglist)
692
{
693
char * this_term;
694
char * next_term;
695
char * varname;
696
char * modifier, *value;
697
int arg_count = 0;
698
ArgList *args = new_malloc(sizeof(ArgList));
699
700
args->void_flag = args->dot_flag = 0;
701
for (this_term = arglist; *this_term; this_term = next_term,arg_count++)
702
{
703
while (isspace((unsigned char)*this_term))
704
this_term++;
705
next_in_comma_list(this_term, &next_term);
706
if (!(varname = next_arg(this_term, &this_term)))
707
continue;
708
if (!my_stricmp(varname, "void")) {
709
args->void_flag = 1;
710
break;
711
} else if (!my_stricmp(varname, "...")) {
712
args->dot_flag = 1;
713
break;
714
} else {
715
args->vars[arg_count] = m_strdup(varname);
716
args->defaults[arg_count] = NULL;
717
718
if (!(modifier = next_arg(this_term, &this_term)))
719
continue;
720
if (!my_stricmp(modifier, "default"))
721
{
722
if (!(value = new_next_arg(this_term, &this_term)))
723
continue;
724
args->defaults[arg_count] = m_strdup(value);
725
}
726
}
727
}
728
args->vars[arg_count] = NULL;
729
return args;
730
}
731
732
void destroy_arglist (ArgList *arglist)
733
{
734
int i = 0;
735
736
if (!arglist)
737
return;
738
739
for (i = 0; ; i++)
740
{
741
if (!arglist->vars[i])
742
break;
743
new_free(&arglist->vars[i]);
744
new_free(&arglist->defaults[i]);
745
}
746
new_free(&arglist);
747
}
748
749
void prepare_alias_call (void *al, char **stuff)
750
{
751
ArgList *args = (ArgList *)al;
752
int i;
753
754
if (!args)
755
return;
756
757
for (i = 0; args->vars[i]; i++)
758
{
759
char *next_val;
760
char *expanded = NULL;
761
int af;
762
763
/* Last argument on the list and no ... argument? */
764
if (!args->vars[i + 1] && !args->dot_flag && !args->void_flag)
765
{
766
next_val = *stuff;
767
*stuff = empty_string;
768
}
769
770
/* Yank the next word from the arglist */
771
else
772
next_val = next_arg(*stuff, stuff);
773
774
if (!next_val || !*next_val)
775
{
776
if ((next_val = args->defaults[i]))
777
next_val = expanded = expand_alias(next_val, *stuff, &af, NULL);
778
else
779
next_val = empty_string;
780
}
781
782
/* Add the local variable */
783
add_local_alias(args->vars[i], next_val);
784
if (expanded)
785
new_free(&expanded);
786
}
787
788
/* Throw away rest of args if wanted */
789
if (args->void_flag)
790
*stuff = empty_string;
791
}
792
793
/**************************** INTERMEDIATE INTERFACE *********************/
794
/* We define Alias here to keep it encapsulated */
795
/*
796
* This is the description of an alias entry
797
* This is an ``array_item'' structure
798
*/
799
800
/*
801
* This is the description for a list of aliases
802
* This is an ``array_set'' structure
803
*/
804
#define ALIAS_CACHE_SIZE 10
805
806
typedef struct AliasStru
807
{
808
Alias **list;
809
int max;
810
int max_alloc;
811
alist_func func;
812
Alias **cache;
813
int cache_size;
814
int revoke_index;
815
} AliasSet;
816
817
static AliasSet var_alias = { NULL, 0, 0, strncmp, NULL, 0, 0 };
818
static AliasSet cmd_alias = { NULL, 0, 0, strncmp, NULL, 0, 0 };
819
820
Alias * find_var_alias (char *name);
821
static Alias * find_cmd_alias (char *name, int *cnt);
822
static Alias * find_local_alias (char *name, AliasSet **list);
823
824
/*
825
* This is the ``stack frame''. Each frame has a ``name'' which is
826
* the name of the alias or on of the frame, or is NULL if the frame
827
* is not an ``enclosing'' frame. Each frame also has a ``current command''
828
* that is being executed, which is used to help us when the client crashes.
829
* Each stack also contains a list of local variables.
830
*/
831
typedef struct RuntimeStackStru
832
{
833
char *name; /* Name of the stack */
834
char *current; /* Current cmd being executed */
835
AliasSet alias; /* Local variables */
836
int locked;
837
int parent;
838
} RuntimeStack;
839
840
/*
841
* This is the master stack frame. Its size is saved in ``max_wind''
842
* and the current frame being used is stored in ``wind_index''.
843
*/
844
static RuntimeStack *call_stack = NULL;
845
int max_wind = -1;
846
int wind_index = -1;
847
848
void show_alias_caches(void)
849
{
850
int i;
851
for (i = 0; i < var_alias.cache_size; i++)
852
{
853
if (var_alias.cache[i])
854
debugyell("VAR cache [%d]: [%s] [%s]", i, var_alias.cache[i]->name, var_alias.cache[i]->stuff);
855
else
856
debugyell("VAR cache [%d]: empty", i);
857
}
858
859
for (i = 0; i < cmd_alias.cache_size; i++)
860
{
861
if (cmd_alias.cache[i])
862
debugyell("CMD cache [%d]: [%s] [%s]", i, cmd_alias.cache[i]->name, cmd_alias.cache[i]->stuff);
863
else
864
debugyell("CMD cache [%d]: empty", i);
865
}
866
}
867
868
869
870
871
Alias *make_new_Alias (char *name)
872
{
873
Alias *tmp = (Alias *) new_malloc(sizeof(Alias));
874
tmp->name = m_strdup(name);
875
tmp->stuff = tmp->stub = NULL;
876
alias_total_bytes_allocated += sizeof(Alias) + strlen(name);
877
return tmp;
878
}
879
880
881
/*
882
* add_var_alias: Add a global variable
883
*
884
* name -- name of the alias to create (must be canonicalized)
885
* stuff -- what to have ``name'' expand to.
886
*
887
* If ``name'' is FUNCTION_RETURN, then it will create the local
888
* return value (die die die)
889
*
890
* If ``name'' refers to an already created local variable, that
891
* local variable is used (invisibly)
892
*/
893
void add_var_alias (char *name, char *stuff)
894
{
895
char *ptr;
896
Alias *tmp = NULL;
897
int af;
898
int local = 0;
899
char *save;
900
901
save = name = remove_brackets(name, NULL, &af);
902
if (*name == ':')
903
{
904
name++, local = 1;
905
if (*name == ':')
906
name++, local = -1;
907
}
908
/*
909
* Weed out invalid variable names
910
*/
911
ptr = after_expando(name, 1, NULL);
912
if (*ptr)
913
error("ASSIGN names may not contain '%c' (You asked for [%s])", *ptr, name);
914
915
916
/*
917
* Weed out FUNCTION_RETURN (die die die)
918
*/
919
else if (!strcmp(name, "FUNCTION_RETURN"))
920
add_local_alias(name, stuff);
921
922
/*
923
* Pass the buck on local variables
924
*/
925
else if ((local == 1) || ((local == 0) && find_local_alias(name, NULL)))
926
add_local_alias(name, stuff);
927
928
else if (stuff && *stuff)
929
{
930
int cnt, loc;
931
932
/*
933
* Look to see if the given alias already exists.
934
* If it does, and the ``stuff'' to assign to it is
935
* empty, then we should remove the variable outright
936
*/
937
tmp = (Alias *) find_array_item ((Array *)&var_alias, name, &cnt, &loc);
938
if (!tmp || cnt >= 0)
939
{
940
tmp = make_new_Alias(name);
941
add_to_array ((Array *)&var_alias, (Array_item *)tmp);
942
}
943
944
/*
945
* Then we fill in the interesting details
946
*/
947
malloc_strcpy(&(tmp->stuff), stuff);
948
new_free(&tmp->stub);
949
tmp->global = loading_global;
950
951
alias_total_allocated++;
952
alias_total_bytes_allocated += strlen(tmp->name) + strlen(tmp->stuff);
953
954
/*
955
* And tell the user.
956
*/
957
say("Assign %s added [%s]", name, stuff);
958
}
959
else
960
delete_var_alias(name, window_display);
961
962
new_free(&save);
963
return;
964
}
965
966
void add_local_alias (char *name, char *stuff)
967
{
968
char *ptr;
969
Alias *tmp = NULL;
970
AliasSet *list = NULL;
971
int af;
972
973
name = remove_brackets(name, NULL, &af);
974
975
/*
976
* Weed out invalid variable names
977
*/
978
ptr = after_expando(name, 1, NULL);
979
if (*ptr)
980
{
981
error("LOCAL names may not contain '%c' (You asked for [%s])", *ptr, name);
982
new_free(&name);
983
return;
984
}
985
/*
986
* Now we see if this local variable exists anywhere
987
* within our view. If it is, we dont care where.
988
* If it doesnt, then we add it to the current frame,
989
* where it will be reaped later.
990
*/
991
if (!(tmp = find_local_alias (name, &list)))
992
{
993
tmp = make_new_Alias(name);
994
add_to_array ((Array *)list, (Array_item *)tmp);
995
}
996
997
/* Fill in the interesting stuff */
998
malloc_strcpy(&(tmp->stuff), stuff);
999
alias_total_allocated++;
1000
alias_total_bytes_allocated += strlen(tmp->stuff);
1001
if (x_debug & DEBUG_LOCAL_VARS)
1002
debugyell("Assign %s (local) added [%s]", name, stuff);
1003
else
1004
say("Assign %s (local) added [%s]", name, stuff);
1005
1006
new_free(&name);
1007
return;
1008
}
1009
1010
void add_cmd_alias (char *name, ArgList *arglist, char *stuff)
1011
{
1012
Alias *tmp = NULL;
1013
int cnt, af, loc;
1014
1015
name = remove_brackets(name, NULL, &af);
1016
1017
tmp = (Alias *) find_array_item ((Array *)&cmd_alias, name, &cnt, &loc);
1018
if (!tmp || cnt >= 0)
1019
{
1020
tmp = make_new_Alias(name);
1021
add_to_array ((Array *)&cmd_alias, (Array_item *)tmp);
1022
}
1023
1024
malloc_strcpy(&(tmp->stuff), stuff);
1025
new_free(&tmp->stub);
1026
tmp->global = loading_global;
1027
tmp->arglist = arglist;
1028
1029
alias_total_allocated++;
1030
alias_total_bytes_allocated += strlen(tmp->stuff);
1031
say("Alias %s added [%s]", name, stuff);
1032
new_free(&name);
1033
return;
1034
}
1035
1036
void add_var_stub_alias (char *name, char *stuff)
1037
{
1038
Alias *tmp = NULL;
1039
char *ptr;
1040
int af;
1041
1042
name = remove_brackets(name, NULL, &af);
1043
1044
ptr = after_expando(name, 1, NULL);
1045
if (*ptr)
1046
error("Assign names may not contain '%c' (You asked for [%s])", *ptr, name);
1047
1048
else if (!strcmp(name, "FUNCTION_RETURN"))
1049
error("You may not stub the FUNCTION_RETURN variable.");
1050
1051
else
1052
{
1053
int cnt, loc;
1054
1055
tmp = (Alias *) find_array_item ((Array *)&var_alias, name, &cnt, &loc);
1056
if (!tmp || cnt >= 0)
1057
{
1058
tmp = make_new_Alias(name);
1059
add_to_array ((Array *)&var_alias, (Array_item *)tmp);
1060
}
1061
1062
malloc_strcpy(&(tmp->stub), stuff);
1063
new_free(&tmp->stuff);
1064
tmp->global = loading_global;
1065
1066
alias_total_allocated++;
1067
alias_total_bytes_allocated += strlen(tmp->stub);
1068
say("Assign %s stubbed to file %s", name, stuff);
1069
}
1070
1071
new_free(&name);
1072
return;
1073
}
1074
1075
1076
void add_cmd_stub_alias (char *name, char *stuff)
1077
{
1078
Alias *tmp = NULL;
1079
int cnt, af;
1080
1081
name = remove_brackets(name, NULL, &af);
1082
if (!(tmp = find_cmd_alias(name, &cnt)) || cnt >= 0)
1083
{
1084
tmp = make_new_Alias(name);
1085
add_to_array ((Array *)&cmd_alias, (Array_item *)tmp);
1086
}
1087
1088
malloc_strcpy(&(tmp->stub), stuff);
1089
new_free(&tmp->stuff);
1090
tmp->global = loading_global;
1091
1092
alias_total_allocated++;
1093
alias_total_bytes_allocated += strlen(tmp->stub);
1094
say("Assign %s stubbed to file %s", name, stuff);
1095
new_free(&name);
1096
return;
1097
}
1098
1099
1100
/************************ LOW LEVEL INTERFACE *************************/
1101
/* XXXX */
1102
static void unstub_alias (Alias *item);
1103
1104
static void resize_cache (AliasSet *set, int newsize)
1105
{
1106
int c, d;
1107
int oldsize = set->cache_size;
1108
1109
set->cache_size = newsize;
1110
if (newsize < oldsize)
1111
{
1112
for (d = oldsize; d < newsize; d++)
1113
set->cache[d]->cache_revoked = ++set->revoke_index;
1114
}
1115
1116
RESIZE(set->cache, Alias *, set->cache_size);
1117
for (c = oldsize; c < set->cache_size; c++)
1118
set->cache[c] = NULL;
1119
}
1120
1121
1122
/*
1123
* 'name' is expected to already be in canonical form (uppercase, dot notation)
1124
*/
1125
Alias * find_var_alias (char *name)
1126
{
1127
Alias *item = NULL;
1128
register int cache;
1129
int loc;
1130
int cnt = 0;
1131
register int i;
1132
u_32int_t mask;
1133
u_32int_t hash = cs_alist_hash(name, &mask);
1134
1135
if (!strcmp(name, "::"))
1136
name +=2;
1137
1138
if (var_alias.cache_size == 0)
1139
resize_cache(&var_alias, ALIAS_CACHE_SIZE);
1140
1141
for (cache = 0; cache < var_alias.cache_size; cache++)
1142
{
1143
if (var_alias.cache[cache] &&
1144
var_alias.cache[cache]->name &&
1145
(var_alias.cache[cache]->hash == hash) &&
1146
!strcmp(name, var_alias.cache[cache]->name))
1147
{
1148
item = var_alias.cache[cache];
1149
cnt = -1;
1150
var_cache_hits++;
1151
break;
1152
}
1153
}
1154
if (!item)
1155
{
1156
cache = var_alias.cache_size - 1;
1157
if ((item = (Alias *) find_array_item ((Array *)&var_alias, name, &cnt, &loc)))
1158
var_cache_misses++;
1159
else
1160
var_cache_passes++;
1161
}
1162
1163
if (cnt < 0)
1164
{
1165
if (var_alias.cache[cache])
1166
var_alias.cache[cache]->cache_revoked = ++var_alias.revoke_index;
1167
1168
for (i = cache; i > 0; i--)
1169
var_alias.cache[i] = var_alias.cache[i - 1];
1170
var_alias.cache[0] = item;
1171
1172
if (item->cache_revoked)
1173
var_cache_missed_by += var_alias.revoke_index - item->cache_revoked;
1174
1175
if (item->stub)
1176
{
1177
unstub_alias(item);
1178
if (!(item = find_var_alias(name)))
1179
return NULL;
1180
if (!item->stuff)
1181
{
1182
delete_var_alias(item->name, 0);
1183
return NULL;
1184
}
1185
}
1186
1187
return item;
1188
}
1189
1190
return NULL;
1191
}
1192
1193
static Alias * find_cmd_alias (char *name, int *cnt)
1194
{
1195
Alias *item = NULL;
1196
int loc;
1197
register int i;
1198
register int cache;
1199
u_32int_t mask;
1200
u_32int_t hash = cs_alist_hash(name, &mask);
1201
1202
if (cmd_alias.cache_size == 0)
1203
resize_cache(&cmd_alias, ALIAS_CACHE_SIZE);
1204
1205
for (cache = 0; cache < cmd_alias.cache_size; cache++)
1206
{
1207
if (cmd_alias.cache[cache] && cmd_alias.cache[cache]->name &&
1208
(cmd_alias.cache[cache]->hash == hash) &&
1209
!strcmp(name, cmd_alias.cache[cache]->name))
1210
{
1211
item = cmd_alias.cache[cache];
1212
*cnt = -1;
1213
cmd_cache_hits++;
1214
break;
1215
}
1216
if (cmd_alias.cache[cache] && !cmd_alias.cache[cache]->name)
1217
cmd_alias.cache[cache] = NULL;
1218
}
1219
1220
if (!item)
1221
{
1222
cache = cmd_alias.cache_size - 1;
1223
if ((item = (Alias *) find_array_item ((Array *)&cmd_alias, name, cnt, &loc)))
1224
cmd_cache_misses++;
1225
else
1226
cmd_cache_passes++;
1227
}
1228
1229
if (*cnt < 0 || *cnt == 1)
1230
{
1231
if (cmd_alias.cache[cache])
1232
cmd_alias.cache[cache]->cache_revoked = ++cmd_alias.revoke_index;
1233
1234
for (i = cache; i > 0; i--)
1235
cmd_alias.cache[i] = cmd_alias.cache[i - 1];
1236
cmd_alias.cache[0] = item;
1237
1238
if (item->cache_revoked)
1239
cmd_cache_missed_by += cmd_alias.revoke_index - item->cache_revoked;
1240
1241
if (item->stub)
1242
{
1243
unstub_alias(item);
1244
if (!(find_cmd_alias(name, cnt)))
1245
return NULL;
1246
if (!item->stuff)
1247
{
1248
delete_cmd_alias(item->name, 0);
1249
*cnt = 0;
1250
return NULL;
1251
}
1252
}
1253
1254
if (item->stuff)
1255
return item;
1256
/* XXXXXXXXXXXXXXXXXXXXXXXXX */
1257
}
1258
1259
return NULL;
1260
}
1261
1262
1263
static void unstub_alias (Alias *item)
1264
{
1265
static int already_looking = 0;
1266
char *copy;
1267
1268
copy = LOCAL_COPY(item->stub);
1269
new_free((char **)&item->stub);
1270
1271
/*
1272
* If already_looking is 1, then
1273
* we are un-stubbing this alias
1274
* because we are loading a file
1275
* that presumably it must be in.
1276
* So we dont load it again (duh).
1277
*/
1278
if (already_looking)
1279
return;
1280
1281
already_looking = 1;
1282
load("LOAD", copy, empty_string, NULL);
1283
already_looking = 0;
1284
}
1285
1286
1287
/*
1288
* An example will best describe the semantics:
1289
*
1290
* A local variable will be returned if and only if there is already a
1291
* variable that is exactly ``name'', or if there is a variable that
1292
* is an exact leading subset of ``name'' and that variable ends in a
1293
* period (a dot).
1294
*/
1295
static Alias * find_local_alias (char *name, AliasSet **list)
1296
{
1297
Alias *alias = NULL;
1298
int c = wind_index;
1299
char *ptr;
1300
int implicit = -1;
1301
int function_return = 0;
1302
1303
/* No name is an error */
1304
if (!name)
1305
return NULL;
1306
1307
ptr = after_expando(name, 1, NULL);
1308
if (*ptr || !call_stack)
1309
return NULL;
1310
if (!my_stricmp(name, "FUNCTION_RETURN"))
1311
function_return = 1;
1312
1313
/*
1314
* Search our current local variable stack, and wind our way
1315
* backwards until we find a NAMED stack -- that is the enclosing
1316
* alias or ON call. If we find a variable in one of those enclosing
1317
* stacks, then we use it. If we dont, we progress.
1318
*
1319
* This needs to be optimized for the degenerate case, when there
1320
* is no local variable available... It will be true 99.999% of
1321
* the time.
1322
*/
1323
for (c = wind_index; c >= 0; c = call_stack[c].parent)
1324
{
1325
/* XXXXX */
1326
if (function_return && last_function_call_level != -1)
1327
c = last_function_call_level;
1328
1329
if (x_debug & DEBUG_LOCAL_VARS)
1330
debugyell("Looking for [%s] in level [%d]", name, c);
1331
1332
if (call_stack[c].alias.list)
1333
{
1334
register int x;
1335
1336
/* XXXX - This is bletcherous */
1337
for (x = 0; x < call_stack[c].alias.max; x++)
1338
{
1339
size_t len = strlen(call_stack[c].alias.list[x]->name);
1340
1341
if (streq(call_stack[c].alias.list[x]->name, name) == len)
1342
{
1343
if (call_stack[c].alias.list[x]->name[len-1] == '.')
1344
implicit = c;
1345
else if (strlen(name) == len)
1346
{
1347
alias = call_stack[c].alias.list[x];
1348
break;
1349
}
1350
}
1351
else
1352
{
1353
if (my_stricmp(call_stack[c].alias.list[x]->name, name) > 0)
1354
continue;
1355
}
1356
}
1357
1358
if (!alias && implicit >= 0)
1359
{
1360
alias = make_new_Alias(name);
1361
add_to_array ((Array *)&call_stack[implicit].alias, (Array_item *)alias);
1362
}
1363
}
1364
1365
if (alias)
1366
{
1367
if (x_debug & DEBUG_LOCAL_VARS)
1368
debugyell("I found [%s] in level [%d] (%s)", name, c, alias->stuff);
1369
break;
1370
}
1371
1372
if (*call_stack[c].name || call_stack[c].parent == -1)
1373
{
1374
if (x_debug & DEBUG_LOCAL_VARS)
1375
debugyell("I didnt find [%s], stopped at level [%d]", name, c);
1376
break;
1377
}
1378
}
1379
1380
if (alias)
1381
{
1382
if (list)
1383
*list = &call_stack[c].alias;
1384
return alias;
1385
}
1386
else if (list)
1387
*list = &call_stack[wind_index].alias;
1388
1389
return NULL;
1390
}
1391
1392
1393
1394
1395
static void delete_all_var_alias (char *name)
1396
{
1397
Alias *item;
1398
int i;
1399
int count = 0;
1400
upper(name);
1401
while ((item = (Alias *) remove_all_from_array((Array *)&var_alias, name)))
1402
{
1403
for (i = 0; i < ALIAS_CACHE_SIZE; i++)
1404
{
1405
if (var_alias.cache[i] == item)
1406
var_alias.cache[i] = NULL;
1407
}
1408
1409
new_free(&(item->name));
1410
new_free(&(item->stuff));
1411
new_free(&(item->stub));
1412
new_free((char **)&item);
1413
count++;
1414
}
1415
}
1416
1417
void delete_var_alias (char *name, int owd)
1418
{
1419
Alias *item;
1420
int i;
1421
1422
upper(name);
1423
if ((item = (Alias *)remove_from_array ((Array *)&var_alias, name)))
1424
{
1425
for (i = 0; i < var_alias.cache_size; i++)
1426
{
1427
if (var_alias.cache[i] == item)
1428
var_alias.cache[i] = NULL;
1429
}
1430
1431
new_free(&(item->name));
1432
new_free(&(item->stuff));
1433
new_free(&(item->stub));
1434
new_free((char **)&item);
1435
if (owd)
1436
say("Assign %s removed", name);
1437
}
1438
else if (owd)
1439
say("No such assign: %s", name);
1440
}
1441
1442
static void delete_cmd_alias (char *name, int owd)
1443
{
1444
Alias *item;
1445
int i;
1446
1447
upper(name);
1448
if ((item = (Alias *)remove_from_array ((Array *)&cmd_alias, name)))
1449
{
1450
for (i = 0; i < cmd_alias.cache_size; i++)
1451
{
1452
if (cmd_alias.cache[i] == item)
1453
cmd_alias.cache[i] = NULL;
1454
}
1455
1456
new_free(&(item->name));
1457
new_free(&(item->stuff));
1458
new_free(&(item->stub));
1459
destroy_arglist(item->arglist);
1460
new_free((char **)&item);
1461
if (owd)
1462
say("Alias %s removed", name);
1463
}
1464
else if (owd)
1465
say("No such alias: %s", name);
1466
}
1467
1468
1469
1470
1471
1472
static void list_local_alias (char *name)
1473
{
1474
int len = 0, cnt;
1475
int DotLoc, LastDotLoc = 0;
1476
char *LastStructName = NULL;
1477
char *s;
1478
1479
say("Visible Local Assigns:");
1480
if (name)
1481
{
1482
upper(name);
1483
len = strlen(name);
1484
}
1485
1486
for (cnt = wind_index; cnt >= 0; cnt = call_stack[cnt].parent)
1487
{
1488
int x;
1489
if (!call_stack[cnt].alias.list)
1490
continue;
1491
for (x = 0; x < call_stack[cnt].alias.max; x++)
1492
{
1493
if (!name || !strncmp(call_stack[cnt].alias.list[x]->name, name, len))
1494
{
1495
if ((s = strchr(call_stack[cnt].alias.list[x]->name + len, '.')))
1496
{
1497
DotLoc = s - call_stack[cnt].alias.list[x]->name;
1498
if (!LastStructName || (DotLoc != LastDotLoc) || strncmp(call_stack[cnt].alias.list[x]->name, LastStructName, DotLoc))
1499
{
1500
put_it("\t%*.*s\t<Structure>", DotLoc, DotLoc, call_stack[cnt].alias.list[x]->name);
1501
LastStructName = call_stack[cnt].alias.list[x]->name;
1502
LastDotLoc = DotLoc;
1503
}
1504
}
1505
else
1506
{
1507
if (call_stack[cnt].alias.list[x]->stub)
1508
put_it("\t%s STUBBED TO %s", call_stack[cnt].alias.list[x]->name, call_stack[cnt].alias.list[x]->stub);
1509
else
1510
put_it("\t%s\t%s", call_stack[cnt].alias.list[x]->name, call_stack[cnt].alias.list[x]->stuff);
1511
}
1512
}
1513
}
1514
}
1515
}
1516
1517
/*
1518
* This function is strictly O(N). Its possible to address this.
1519
*/
1520
static void list_var_alias (char *name)
1521
{
1522
int len = 0;
1523
int DotLoc,
1524
LastDotLoc = 0;
1525
char *LastStructName = NULL;
1526
int cnt;
1527
char *s;
1528
1529
say("Assigns:");
1530
1531
if (name)
1532
{
1533
upper(name);
1534
len = strlen(name);
1535
}
1536
1537
for (cnt = 0; cnt < var_alias.max; cnt++)
1538
{
1539
if (!name || !strncmp(var_alias.list[cnt]->name, name, len))
1540
{
1541
if ((s = strchr(var_alias.list[cnt]->name + len, '.')))
1542
{
1543
DotLoc = s - var_alias.list[cnt]->name;
1544
if (!LastStructName || (DotLoc != LastDotLoc) || strncmp(var_alias.list[cnt]->name, LastStructName, DotLoc))
1545
{
1546
put_it("\t%*.*s\t<Structure>", DotLoc, DotLoc, var_alias.list[cnt]->name);
1547
LastStructName = var_alias.list[cnt]->name;
1548
LastDotLoc = DotLoc;
1549
}
1550
}
1551
else
1552
{
1553
if (var_alias.list[cnt]->stub)
1554
put_it("\t%s STUBBED TO %s", var_alias.list[cnt]->name, var_alias.list[cnt]->stub);
1555
else
1556
put_it("\t%s\t%s", var_alias.list[cnt]->name, var_alias.list[cnt]->stuff);
1557
}
1558
}
1559
}
1560
}
1561
1562
/*
1563
* This function is strictly O(N). Its possible to address this.
1564
*/
1565
static void list_cmd_alias (char *name)
1566
{
1567
int len = 0;
1568
int DotLoc,
1569
LastDotLoc = 0;
1570
char *LastStructName = NULL;
1571
int cnt;
1572
char *s;
1573
1574
say("Aliases:");
1575
1576
if (name)
1577
{
1578
upper(name);
1579
len = strlen(name);
1580
}
1581
1582
for (cnt = 0; cnt < cmd_alias.max; cnt++)
1583
{
1584
if (!name || !strncmp(cmd_alias.list[cnt]->name, name, len))
1585
{
1586
if ((s = strchr(cmd_alias.list[cnt]->name + len, '.')))
1587
{
1588
DotLoc = s - cmd_alias.list[cnt]->name;
1589
if (!LastStructName || (DotLoc != LastDotLoc) || strncmp(cmd_alias.list[cnt]->name, LastStructName, DotLoc))
1590
{
1591
put_it("\t%*.*s\t<Structure>", DotLoc, DotLoc, cmd_alias.list[cnt]->name);
1592
LastStructName = cmd_alias.list[cnt]->name;
1593
LastDotLoc = DotLoc;
1594
}
1595
}
1596
else
1597
{
1598
if (cmd_alias.list[cnt]->stub)
1599
put_it("\t%s STUBBED TO %s", cmd_alias.list[cnt]->name, cmd_alias.list[cnt]->stub);
1600
else
1601
put_it("\t%s\t%s", cmd_alias.list[cnt]->name, cmd_alias.list[cnt]->stuff);
1602
}
1603
}
1604
}
1605
}
1606
1607
1608
/************************* DIRECT VARIABLE EXPANSION ************************/
1609
/*
1610
* get_variable: This simply looks up the given str. It first checks to see
1611
* if its a user variable and returns it if so. If not, it checks to see if
1612
* it's an IRC variable and returns it if so. If not, it checks to see if
1613
* its and environment variable and returns it if so. If not, it returns
1614
* null. It mallocs the returned string
1615
*/
1616
char *get_variable (char *str)
1617
{
1618
int af = 0;
1619
return get_variable_with_args(str, NULL, &af);
1620
}
1621
1622
1623
static char *get_variable_with_args (const char *str, const char *args, int *args_flag)
1624
{
1625
Alias *alias = NULL;
1626
char *ret = NULL;
1627
char *name = NULL;
1628
char *freep = NULL;
1629
int copy = 0;
1630
int local = 0;
1631
1632
freep = name = remove_brackets(str, args, args_flag);
1633
1634
if (*name == ':' && name[1])
1635
{
1636
name++, local = 1;
1637
if (*name == ':')
1638
name++, local = -1;
1639
}
1640
1641
/*
1642
* local == -1 means "local variables not allowed"
1643
* local == 0 means "locals first, then globals"
1644
* local == 1 means "global variables not allowed"
1645
*/
1646
1647
if ((local != -1) && (alias = find_local_alias(name, NULL)))
1648
copy = 1, ret = alias->stuff;
1649
else if (local == 1)
1650
;
1651
else if ((alias = find_var_alias(name)) != NULL)
1652
copy = 1, ret = alias->stuff;
1653
else if ((strlen(str) == 1) && (ret = built_in_alias(*str, NULL)))
1654
;
1655
else if ((ret = make_string_var(str)))
1656
;
1657
else if ((ret = make_fstring_var(str)))
1658
;
1659
else
1660
copy = 1, ret = getenv(str);
1661
1662
if (x_debug & DEBUG_UNKNOWN && ret == NULL)
1663
debugyell("Variable lookup to non-existant assign [%s]", name);
1664
if ((internal_debug & DEBUG_VARIABLE) && alias_debug && !in_debug_yell)
1665
debugyell("%3d \t@%s == %s", debug_count++, str, ret ? ret : empty_string);
1666
new_free(&freep);
1667
return (copy ? m_strdup(ret) : ret);
1668
}
1669
1670
void debug_alias(char *name, int x)
1671
{
1672
Alias *item;
1673
int cnt;
1674
if (name && *name)
1675
{
1676
if ((item = find_cmd_alias(name, &cnt)) && cnt < 0)
1677
item->debug = DEBUG_CMDALIAS;
1678
}
1679
}
1680
1681
char * get_cmd_alias (char *name, int *howmany, char **complete_name, void **args)
1682
{
1683
Alias *item;
1684
1685
if ((item = find_cmd_alias(name, howmany)))
1686
{
1687
alias_debug += (item->debug ? 1 : 0);
1688
if (complete_name)
1689
malloc_strcpy(complete_name, item->name);
1690
if (args)
1691
*args = (void *)item->arglist;
1692
return item->stuff;
1693
}
1694
return NULL;
1695
}
1696
1697
/*
1698
* This function is strictly O(N). This should probably be addressed.
1699
*/
1700
char ** glob_cmd_alias (char *name, int *howmany)
1701
{
1702
int cnt;
1703
int cmp;
1704
int len;
1705
char **matches = NULL;
1706
int matches_size = 5;
1707
1708
len = strlen(name);
1709
*howmany = 0;
1710
RESIZE(matches, char *, matches_size);
1711
1712
for (cnt = 0; cnt < cmd_alias.max; cnt++)
1713
{
1714
if (!(cmp = strncmp(name, cmd_alias.list[cnt]->name, len)))
1715
{
1716
if (strchr(cmd_alias.list[cnt]->name + len, '.'))
1717
continue;
1718
1719
matches[*howmany] = m_strdup(cmd_alias.list[cnt]->name);
1720
*howmany += 1;
1721
if (*howmany == matches_size)
1722
{
1723
matches_size += 5;
1724
RESIZE(matches, char *, matches_size);
1725
}
1726
}
1727
else if (cmp < 0)
1728
break;
1729
}
1730
1731
if (*howmany)
1732
matches[*howmany] = NULL;
1733
else
1734
new_free((char **)&matches);
1735
1736
return matches;
1737
}
1738
1739
/*
1740
* This function is strictly O(N). This should probably be addressed.
1741
*/
1742
char ** glob_assign_alias (char *name, int *howmany)
1743
{
1744
int cnt;
1745
int cmp;
1746
int len;
1747
char **matches = NULL;
1748
int matches_size = 5;
1749
1750
len = strlen(name);
1751
*howmany = 0;
1752
RESIZE(matches, char *, matches_size);
1753
1754
for (cnt = 0; cnt < var_alias.max; cnt++)
1755
{
1756
if (!(cmp = strncmp(name, var_alias.list[cnt]->name, len)))
1757
{
1758
if (strchr(var_alias.list[cnt]->name + len, '.'))
1759
continue;
1760
1761
matches[*howmany] = m_strdup(var_alias.list[cnt]->name);
1762
*howmany += 1;
1763
if (*howmany == matches_size)
1764
{
1765
matches_size += 5;
1766
RESIZE(matches, char *, matches_size);
1767
}
1768
}
1769
else if (cmp < 0)
1770
break;
1771
}
1772
1773
if (*howmany)
1774
matches[*howmany] = NULL;
1775
else
1776
new_free((char **)&matches);
1777
1778
return matches;
1779
}
1780
1781
/*
1782
* This function is strictly O(N). This should probably be addressed.
1783
*/
1784
char ** pmatch_cmd_alias (char *name, int *howmany)
1785
{
1786
int cnt;
1787
int len;
1788
char **matches = NULL;
1789
int matches_size = 5;
1790
1791
len = strlen(name);
1792
*howmany = 0;
1793
RESIZE(matches, char *, matches_size);
1794
1795
for (cnt = 0; cnt < cmd_alias.max; cnt++)
1796
{
1797
if (wild_match(name, cmd_alias.list[cnt]->name))
1798
{
1799
matches[*howmany] = m_strdup(cmd_alias.list[cnt]->name);
1800
*howmany += 1;
1801
if (*howmany == matches_size)
1802
{
1803
matches_size += 5;
1804
RESIZE(matches, char *, matches_size);
1805
}
1806
}
1807
}
1808
1809
if (*howmany)
1810
matches[*howmany] = NULL;
1811
else
1812
new_free((char **)&matches);
1813
1814
return matches;
1815
}
1816
1817
/*
1818
* This function is strictly O(N). This should probably be addressed.
1819
*/
1820
char ** pmatch_assign_alias (char *name, int *howmany)
1821
{
1822
int cnt;
1823
int len;
1824
char **matches = NULL;
1825
int matches_size = 5;
1826
1827
len = strlen(name);
1828
*howmany = 0;
1829
RESIZE(matches, char *, matches_size);
1830
1831
for (cnt = 0; cnt < var_alias.max; cnt++)
1832
{
1833
if (wild_match(name, var_alias.list[cnt]->name))
1834
{
1835
matches[*howmany] = m_strdup(var_alias.list[cnt]->name);
1836
*howmany += 1;
1837
if (*howmany == matches_size)
1838
{
1839
matches_size += 5;
1840
RESIZE(matches, char *, matches_size);
1841
}
1842
}
1843
}
1844
1845
if (*howmany)
1846
matches[*howmany] = NULL;
1847
else
1848
new_free((char **)&matches);
1849
1850
return matches;
1851
}
1852
1853
1854
/*
1855
* This function is strictly O(N). This should probably be addressed.
1856
*/
1857
char ** get_subarray_elements (char *root, int *howmany, int type)
1858
{
1859
AliasSet *as; /* XXXX */
1860
1861
register int len, len2;
1862
register int cnt;
1863
int cmp = 0;
1864
char **matches = NULL;
1865
int matches_size = 5;
1866
size_t end;
1867
char *last = NULL;
1868
1869
if (type == COMMAND_ALIAS)
1870
as = &cmd_alias;
1871
else
1872
as = &var_alias;
1873
1874
len = strlen(root);
1875
*howmany = 0;
1876
RESIZE(matches, char *, matches_size);
1877
for (cnt = 0; cnt < as->max; cnt++)
1878
{
1879
len2 = strlen(as->list[cnt]->name);
1880
if ( (len < len2) &&
1881
((cmp = streq(root, as->list[cnt]->name)) == len))
1882
{
1883
if (as->list[cnt]->name[cmp] == '.')
1884
{
1885
end = strcspn(as->list[cnt]->name + cmp + 1, ".");
1886
if (last && !my_strnicmp(as->list[cnt]->name, last, cmp + 1 + end))
1887
continue;
1888
matches[*howmany] = m_strndup(as->list[cnt]->name, cmp + 1 + end);
1889
last = matches[*howmany];
1890
*howmany += 1;
1891
if (*howmany == matches_size)
1892
{
1893
matches_size += 5;
1894
RESIZE(matches, char *, matches_size);
1895
}
1896
}
1897
}
1898
}
1899
1900
if (*howmany)
1901
matches[*howmany] = NULL;
1902
else
1903
new_free((char **)&matches);
1904
1905
return matches;
1906
}
1907
1908
char * parse_line_alias_special (char *name, char *what, char *args, int d1, int d2, void *arglist, int function)
1909
{
1910
int old_window_display = window_display;
1911
int old_last_function_call_level = last_function_call_level;
1912
char *result = NULL;
1913
1914
window_display = 0;
1915
1916
make_local_stack(name);
1917
prepare_alias_call(arglist, &args);
1918
if (function)
1919
{
1920
last_function_call_level = wind_index;
1921
add_local_alias("FUNCTION_RETURN", empty_string);
1922
}
1923
window_display = old_window_display;
1924
1925
will_catch_return_exceptions++;
1926
parse_line(NULL, what, args, d1, d2, 1);
1927
will_catch_return_exceptions--;
1928
return_exception = 0;
1929
1930
if (function)
1931
{
1932
result = get_variable("FUNCTION_RETURN");
1933
last_function_call_level = old_last_function_call_level;
1934
}
1935
destroy_local_stack();
1936
1937
return result;
1938
}
1939
1940
char * parse_line_with_return (char *name, char *what, char *args, int d1, int d2)
1941
{
1942
return parse_line_alias_special(name, what, args, d1, d2, NULL, 1);
1943
}
1944
1945
1946
/************************************************************************/
1947
/*
1948
* call_user_function: Executes a user alias (by way of parse_command.
1949
* The actual function ends up being routed through execute_alias (below)
1950
* and we just keep track of the retval and stuff. I dont know that anyone
1951
* depends on command completion with functions, so we can save a lot of
1952
* CPU time by just calling execute_alias() directly.
1953
*/
1954
char *call_user_function (char *alias_name, char *args)
1955
{
1956
char *result = NULL;
1957
char *sub_buffer;
1958
int cnt;
1959
void *arglist = NULL;
1960
1961
sub_buffer = get_cmd_alias(alias_name, &cnt, NULL, &arglist);
1962
if (cnt < 0)
1963
result = parse_line_alias_special(alias_name, sub_buffer, args, 0, 1, arglist, 1);
1964
else if (x_debug & DEBUG_UNKNOWN)
1965
debugyell("Function call to non-existant alias [%s]", alias_name);
1966
1967
if (!result)
1968
result = m_strdup(empty_string);
1969
1970
return result;
1971
}
1972
/* XXX Ugh. */
1973
void call_user_alias (char *alias_name, char *alias_stuff, char *args, void *arglist)
1974
{
1975
parse_line_alias_special(alias_name, alias_stuff, args, 0, 1, arglist, 0);
1976
}
1977
1978
1979
1980
/*
1981
* save_aliases: This will write all of the aliases to the FILE pointer fp in
1982
* such a way that they can be read back in using LOAD or the -l switch
1983
*/
1984
1985
void save_assigns (FILE *fp, int do_all)
1986
{
1987
int cnt = 0;
1988
1989
for (cnt = 0; cnt < var_alias.max; cnt++)
1990
{
1991
if (!var_alias.list[cnt]->global || do_all)
1992
{
1993
if (var_alias.list[cnt]->stub)
1994
fprintf(fp, "STUB ");
1995
fprintf(fp, "ASSIGN %s %s\n", var_alias.list[cnt]->name, var_alias.list[cnt]->stuff);
1996
}
1997
}
1998
}
1999
2000
void save_aliases (FILE *fp, int do_all)
2001
{
2002
int cnt = 0;
2003
2004
#if 0
2005
for (cnt = 0; cnt < var_alias.max; cnt++)
2006
{
2007
if (!var_alias.list[cnt]->global || do_all)
2008
{
2009
if (var_alias.list[cnt]->stub)
2010
fprintf(fp, "STUB ");
2011
fprintf(fp, "ASSIGN %s %s\n", var_alias.list[cnt]->name, var_alias.list[cnt]->stuff);
2012
}
2013
}
2014
#endif
2015
for (cnt = 0; cnt < cmd_alias.max; cnt++)
2016
{
2017
if (!cmd_alias.list[cnt]->global || do_all)
2018
{
2019
if (cmd_alias.list[cnt]->stub)
2020
fprintf(fp, "STUB ");
2021
fprintf(fp, "ALIAS %s %s\n", cmd_alias.list[cnt]->name, cmd_alias.list[cnt]->stuff);
2022
}
2023
}
2024
}
2025
2026
void destroy_aliases (int type)
2027
{
2028
int cnt = 0;
2029
AliasSet *my_array = NULL;
2030
2031
if (type == COMMAND_ALIAS)
2032
my_array = &cmd_alias;
2033
else if (type == VAR_ALIAS)
2034
my_array = &var_alias;
2035
else if (type == VAR_ALIAS_LOCAL)
2036
my_array = &call_stack[wind_index].alias;
2037
2038
for (cnt = 0; cnt < my_array->max; cnt++)
2039
{
2040
new_free(&(my_array->list[cnt]->stuff));
2041
new_free(&(my_array->list[cnt]->name));
2042
new_free(&(my_array->list[cnt]->stub));
2043
new_free(&(my_array->list[cnt]));
2044
new_free((void **)&(my_array->list[cnt])); /* XXX Hrm. */
2045
}
2046
for (cnt = 0; cnt < my_array->cache_size; cnt++)
2047
my_array->cache[cnt] = NULL;
2048
new_free(&my_array->list);
2049
my_array->max = my_array->max_alloc = 0;
2050
}
2051
2052
/******************* RUNTIME STACK SUPPORT **********************************/
2053
2054
void BX_make_local_stack (char *name)
2055
{
2056
wind_index++;
2057
2058
if (wind_index >= max_wind)
2059
{
2060
int tmp_wind = wind_index;
2061
2062
if (max_wind == -1)
2063
max_wind = 8;
2064
else
2065
max_wind <<= 1;
2066
2067
RESIZE(call_stack, RuntimeStack, max_wind+1);
2068
for (; wind_index <= max_wind; wind_index++)
2069
{
2070
call_stack[wind_index].alias.max = 0;
2071
call_stack[wind_index].alias.max_alloc = 0;
2072
call_stack[wind_index].alias.list = NULL;
2073
call_stack[wind_index].current = NULL;
2074
call_stack[wind_index].name = NULL;
2075
call_stack[wind_index].alias.func = strncmp;
2076
call_stack[wind_index].parent = -1;
2077
call_stack[wind_index].alias.cache = NULL;
2078
call_stack[wind_index].alias.cache_size = 0;
2079
call_stack[wind_index].alias.revoke_index = 0;
2080
}
2081
wind_index = tmp_wind;
2082
}
2083
2084
/* Just in case... */
2085
destroy_local_stack();
2086
wind_index++; /* XXXX - chicanery */
2087
2088
if (name)
2089
{
2090
call_stack[wind_index].name = name;
2091
call_stack[wind_index].parent = -1;
2092
}
2093
else
2094
{
2095
call_stack[wind_index].name = empty_string;
2096
call_stack[wind_index].parent = wind_index - 1;
2097
}
2098
call_stack[wind_index].locked = 0;
2099
}
2100
2101
int find_locked_stack_frame (void)
2102
{
2103
int i;
2104
for (i = 0; i < wind_index; i++)
2105
if (call_stack[i].locked)
2106
return i;
2107
2108
return -1;
2109
}
2110
2111
void bless_local_stack (void)
2112
{
2113
call_stack[wind_index].name = empty_string;
2114
call_stack[wind_index].parent = find_locked_stack_frame();
2115
}
2116
2117
char *return_this_alias(void)
2118
{
2119
int ind = wind_index;
2120
if (ind != -1)
2121
{
2122
if (call_stack[ind].name[0])
2123
return call_stack[ind].name;
2124
while (!(call_stack[ind].name[0]) && ind)
2125
ind--;
2126
return call_stack[ind].name;
2127
}
2128
return empty_string;
2129
}
2130
2131
void BX_destroy_local_stack (void)
2132
{
2133
/*
2134
* We clean up as best we can here...
2135
*/
2136
if (call_stack[wind_index].alias.list)
2137
destroy_aliases(VAR_ALIAS_LOCAL);
2138
if (call_stack[wind_index].current)
2139
call_stack[wind_index].current = 0;
2140
if (call_stack[wind_index].name)
2141
call_stack[wind_index].name = 0;
2142
2143
wind_index--;
2144
}
2145
2146
void set_current_command (char *line)
2147
{
2148
call_stack[wind_index].current = line;
2149
}
2150
2151
void unset_current_command (void)
2152
{
2153
call_stack[wind_index].current = NULL;
2154
}
2155
2156
void BX_lock_stack_frame (void)
2157
{
2158
call_stack[wind_index].locked = 1;
2159
}
2160
2161
void BX_unlock_stack_frame (void)
2162
{
2163
int lock = find_locked_stack_frame();
2164
if (lock >= 0)
2165
call_stack[lock].locked = 0;
2166
}
2167
2168
2169
void dump_call_stack (void)
2170
{
2171
int my_wind_index = wind_index;
2172
if (my_wind_index >= 0)
2173
{
2174
say("Call stack");
2175
while (my_wind_index--)
2176
say("[%3d] %s", my_wind_index, call_stack[my_wind_index].current);
2177
say("End of call stack");
2178
}
2179
}
2180
2181
void panic_dump_call_stack (void)
2182
{
2183
int my_wind_index = wind_index;
2184
printf("Call stack\n");
2185
if (wind_index >= 0)
2186
{
2187
while (my_wind_index--)
2188
printf("[%3d] %s\n", my_wind_index, call_stack[my_wind_index].current);
2189
} else
2190
printf("call stack corruption\n");
2191
printf("End of call stack\n");
2192
}
2193
2194
2195
/*
2196
* You may NOT call this unless youre about to exit.
2197
* If you do (call this when youre not about to exit), and you do it
2198
* very often, max_wind will get absurdly large. So dont do it.
2199
*
2200
* XXXX - this doesnt clean up everything -- but do i care?
2201
*/
2202
void destroy_call_stack (void)
2203
{
2204
wind_index = 0;
2205
new_free((char **)&call_stack);
2206
}
2207
2208
#if 0
2209
char *lookup_member(char *varname, char *var_args, char *ptr, char *args)
2210
{
2211
char *structs[] = { "WINDOW", "DCC", "CHANNEL", "NICK", NULL };
2212
int i;
2213
2214
for (i = 0; structs[i]; i++)
2215
if (!my_stricmp(varname, structs[i]))
2216
break;
2217
if (!structs[i])
2218
return NULL;
2219
switch (i)
2220
{
2221
case 0:
2222
case 1:
2223
case 2:
2224
case 3:
2225
default:
2226
break;
2227
}
2228
return NULL;
2229
}
2230
#endif
2231
2232
#include "expr2.c"
2233
#include "expr.c"
2234
2235
/****************************** ALIASCTL ************************************/
2236
#define EMPTY empty_string
2237
#define RETURN_EMPTY return m_strdup(EMPTY)
2238
#define RETURN_IF_EMPTY(x) if (empty( x )) RETURN_EMPTY
2239
#define GET_INT_ARG(x, y) {RETURN_IF_EMPTY(y); x = my_atol(safe_new_next_arg(y, &y));}
2240
#define GET_FLOAT_ARG(x, y) {RETURN_IF_EMPTY(y); x = atof(safe_new_next_arg(y, &y));}
2241
#define GET_STR_ARG(x, y) {RETURN_IF_EMPTY(y); x = new_next_arg(y, &y);RETURN_IF_EMPTY(x);}
2242
#define RETURN_STR(x) return m_strdup(x ? x : EMPTY)
2243
#define RETURN_INT(x) return m_strdup(ltoa(x));
2244
2245
/* Used by function_aliasctl */
2246
/* MUST BE FIXED */
2247
BUILT_IN_FUNCTION(aliasctl)
2248
{
2249
int list = -1;
2250
char *listc;
2251
enum { GET, SET, MATCH, PMATCH } op;
2252
2253
GET_STR_ARG(listc, input);
2254
if (!my_strnicmp(listc, "AS", 2))
2255
list = VAR_ALIAS;
2256
else if (!my_strnicmp(listc, "AL", 2))
2257
list = COMMAND_ALIAS;
2258
else if (!my_strnicmp(listc, "LO", 2))
2259
list = VAR_ALIAS_LOCAL;
2260
else if (!my_strnicmp(listc, "CO", 2))
2261
list = -1;
2262
else
2263
RETURN_EMPTY;
2264
2265
GET_STR_ARG(listc, input);
2266
if (!my_strnicmp(listc, "G", 1))
2267
op = GET;
2268
else if (!my_strnicmp(listc, "S", 1))
2269
op = SET;
2270
else if (!my_strnicmp(listc, "M", 1))
2271
op = MATCH;
2272
else if (!my_strnicmp(listc, "P", 1))
2273
op = PMATCH;
2274
else
2275
RETURN_EMPTY;
2276
2277
if (list == -1 && op != MATCH)
2278
RETURN_EMPTY;
2279
2280
GET_STR_ARG(listc, input);
2281
2282
switch (op)
2283
{
2284
case (GET) :
2285
{
2286
Alias *alias = NULL;
2287
AliasSet *a_list;
2288
int dummy;
2289
2290
upper(listc);
2291
if (list == VAR_ALIAS_LOCAL)
2292
alias = find_local_alias(listc, &a_list);
2293
else if (list == VAR_ALIAS)
2294
alias = find_var_alias(listc);
2295
else
2296
alias = find_cmd_alias(listc, &dummy);
2297
2298
if (alias)
2299
RETURN_STR(alias->stuff);
2300
else
2301
RETURN_EMPTY;
2302
}
2303
case (SET) :
2304
{
2305
upper(listc);
2306
if (list == VAR_ALIAS_LOCAL)
2307
add_local_alias(listc, input);
2308
else if (list == VAR_ALIAS)
2309
add_var_alias(listc, input);
2310
else
2311
add_cmd_alias(listc, NULL, input);
2312
2313
RETURN_INT(1)
2314
}
2315
case (MATCH) :
2316
{
2317
char **mlist = NULL;
2318
char *mylist = NULL;
2319
int num = 0, ctr;
2320
2321
if (!my_stricmp(listc, "*"))
2322
listc = empty_string;
2323
2324
upper(listc);
2325
2326
if (list == COMMAND_ALIAS)
2327
mlist = glob_cmd_alias(listc, &num);
2328
else if (list == VAR_ALIAS)
2329
mlist = glob_assign_alias(listc, &num);
2330
else if (list == -1)
2331
return glob_commands(listc, &num, 0);
2332
2333
for (ctr = 0; ctr < num; ctr++)
2334
{
2335
m_s3cat(&mylist, space, mlist[ctr]);
2336
new_free((char **)&mlist[ctr]);
2337
}
2338
new_free((char **)&mlist);
2339
if (mylist)
2340
return mylist;
2341
RETURN_EMPTY;
2342
}
2343
case (PMATCH) :
2344
{
2345
char ** mlist = NULL;
2346
char * mylist = NULL;
2347
int num = 0,
2348
ctr;
2349
2350
if (list == COMMAND_ALIAS)
2351
mlist = pmatch_cmd_alias(listc, &num);
2352
else if (list == VAR_ALIAS)
2353
mlist = pmatch_assign_alias(listc, &num);
2354
else if (list == -1)
2355
return glob_commands(listc, &num, 1);
2356
2357
for (ctr = 0; ctr < num; ctr++)
2358
{
2359
m_s3cat(&mylist, space, mlist[ctr]);
2360
new_free((char **)&mlist[ctr]);
2361
}
2362
new_free((char **)&mlist);
2363
if (mylist)
2364
return mylist;
2365
RETURN_EMPTY;
2366
}
2367
default :
2368
error("aliasctl: Error");
2369
RETURN_EMPTY;
2370
}
2371
RETURN_EMPTY;
2372
}
2373
2374
/*************************** stacks **************************************/
2375
typedef struct aliasstacklist
2376
{
2377
int which;
2378
char *name;
2379
Alias *list;
2380
struct aliasstacklist *next;
2381
} AliasStack;
2382
2383
static AliasStack * alias_stack = NULL;
2384
static AliasStack * assign_stack = NULL;
2385
2386
void do_stack_alias (int type, char *args, int which)
2387
{
2388
char *name;
2389
AliasStack *aptr, **aptrptr;
2390
Alias *alptr;
2391
int cnt;
2392
int my_which = 0;
2393
2394
if (which == STACK_DO_ALIAS)
2395
{
2396
name = "ALIAS";
2397
aptrptr = &alias_stack;
2398
my_which = COMMAND_ALIAS;
2399
}
2400
else
2401
{
2402
name = "ASSIGN";
2403
aptrptr = &assign_stack;
2404
my_which = VAR_ALIAS;
2405
}
2406
2407
if (!*aptrptr && (type == STACK_POP || type == STACK_LIST))
2408
{
2409
say("%s stack is empty!", name);
2410
return;
2411
}
2412
2413
if (type == STACK_PUSH)
2414
{
2415
if (which == STACK_DO_ALIAS)
2416
{
2417
if ((alptr = find_var_alias(args)))
2418
delete_var_alias(args, window_display);
2419
}
2420
else
2421
{
2422
if ((alptr = find_cmd_alias(args, &cnt)))
2423
delete_cmd_alias(args, window_display);
2424
}
2425
2426
aptr = (AliasStack *)new_malloc(sizeof(AliasStack));
2427
aptr->list = alptr;
2428
aptr->name = m_strdup(args);
2429
aptr->next = aptrptr ? *aptrptr : NULL;
2430
*aptrptr = aptr;
2431
return;
2432
}
2433
2434
if (type == STACK_POP)
2435
{
2436
AliasStack *prev = NULL;
2437
2438
for (aptr = *aptrptr; aptr; prev = aptr, aptr = aptr->next)
2439
{
2440
/* have we found it on the stack? */
2441
if (!my_stricmp(args, aptr->name))
2442
{
2443
/* remove it from the list */
2444
if (prev == NULL)
2445
*aptrptr = aptr->next;
2446
else
2447
prev->next = aptr->next;
2448
2449
/* throw away anything we already have */
2450
delete_cmd_alias(args, window_display);
2451
2452
/* put the new one in. */
2453
if (aptr->list)
2454
{
2455
if (which == STACK_DO_ALIAS)
2456
add_to_array((Array *)&cmd_alias, (Array_item *)(aptr->list));
2457
else
2458
add_to_array((Array *)&var_alias, (Array_item *)(aptr->list));
2459
}
2460
2461
/* free it */
2462
new_free((char **)&aptr->name);
2463
new_free((char **)&aptr);
2464
return;
2465
}
2466
}
2467
say("%s is not on the %s stack!", args, name);
2468
return;
2469
}
2470
if (STACK_LIST == type)
2471
{
2472
AliasStack *tmp;
2473
2474
say("%s STACK LIST", name);
2475
for (tmp = *aptrptr; tmp; tmp = tmp->next)
2476
{
2477
if (!tmp->list)
2478
say("\t%s\t<Placeholder>", tmp->name);
2479
2480
else if (tmp->list->stub)
2481
say("\t%s STUBBED TO %s", tmp->name, tmp->list->stub);
2482
2483
else
2484
say("\t%s\t%s", tmp->name, tmp->list->stuff);
2485
}
2486
return;
2487
}
2488
say("Unknown STACK type ??");
2489
}
2490
2491
2492