Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
BitchX
GitHub Repository: BitchX/BitchX1.3
Path: blob/master/source/if.c
1069 views
1
/*
2
* if.c: handles the IF command for IRCII
3
*
4
* Written By Michael Sandrof
5
*
6
* Copyright(c) 1990, 1991
7
*
8
* See the COPYRIGHT file, or do a HELP IRCII COPYRIGHT
9
*/
10
11
12
#include "irc.h"
13
static char cvsrevision[] = "$Id: if.c 32 2008-05-07 08:38:12Z keaston $";
14
CVS_REVISION(if_c)
15
#include "struct.h"
16
17
#include "alias.h"
18
#include "ircaux.h"
19
#include "window.h"
20
#include "vars.h"
21
#include "output.h"
22
#include "if.h"
23
#include "commands.h"
24
#include "misc.h"
25
#define MAIN_SOURCE
26
#include "modval.h"
27
28
/*
29
* next_expr finds the next expression delimited by brackets. The type
30
* of bracket expected is passed as a parameter. Returns NULL on error.
31
*/
32
char *my_next_expr(char **args, char type, int whine)
33
{
34
char *ptr,
35
*ptr2,
36
*ptr3;
37
38
if (!*args)
39
return NULL;
40
ptr2 = *args;
41
if (!*ptr2)
42
return 0;
43
if (*ptr2 != type)
44
{
45
if (whine)
46
say("Expression syntax");
47
return 0;
48
} /* { */
49
ptr = MatchingBracket(ptr2 + 1, type, (type == '(') ? ')' : '}');
50
if (!ptr)
51
{
52
say("Unmatched '%c'", type);
53
return 0;
54
}
55
*ptr = '\0';
56
57
do
58
ptr2++;
59
while (my_isspace(*ptr2));
60
61
ptr3 = ptr+1;
62
while (my_isspace(*ptr3))
63
ptr3++;
64
*args = ptr3;
65
if (*ptr2)
66
{
67
ptr--;
68
while (my_isspace(*ptr))
69
*ptr-- = '\0';
70
}
71
return ptr2;
72
}
73
74
extern char *next_expr_failok (char **args, char type)
75
{
76
return my_next_expr (args, type, 0);
77
}
78
79
extern char *next_expr (char **args, char type)
80
{
81
return my_next_expr (args, type, 1);
82
}
83
84
/*
85
* All new /if command -- (jfn, 1997)
86
*
87
* Here's the plan:
88
*
89
* if (expr) ......
90
* if (expr) {......}
91
* if (expr) {......} {......}
92
* if (expr) {......} else {......}
93
* if (expr) {......} elsif (expr2) {......}
94
* etc.
95
*/
96
97
BUILT_IN_COMMAND(ifcmd)
98
{
99
int unless_cmd;
100
char *current_expr;
101
char *current_expr_val;
102
int result;
103
char *current_line = NULL;
104
int flag = 0;
105
106
unless_cmd = (*command == 'U');
107
if (!subargs)
108
subargs = empty_string;
109
110
while (args && *args)
111
{
112
while (my_isspace(*args))
113
args++;
114
115
current_expr = next_expr(&args, '(');
116
if (!current_expr)
117
{
118
error("IF: Missing expression");
119
return;
120
}
121
current_expr_val = parse_inline(current_expr, subargs, &flag);
122
if (internal_debug & DEBUG_EXPANSIONS && !in_debug_yell)
123
debugyell("%s expression expands to: (%s)", command, current_expr_val);
124
result = check_val(current_expr_val);
125
new_free(&current_expr_val);
126
127
if (*args == '{')
128
{
129
current_line = next_expr(&args, '{');
130
}
131
else
132
current_line = args, args = NULL;
133
134
/* If the expression was FALSE for IF, and TRUE for UNLESS */
135
if (unless_cmd == result)
136
{
137
if (args)
138
{
139
if (!my_strnicmp(args, "elsif ", 6))
140
{
141
args += 6;
142
continue;
143
}
144
else if (!my_strnicmp(args, "else ", 5))
145
args += 5;
146
147
while (my_isspace(*args))
148
args++;
149
150
if (*args == '{')
151
current_line = next_expr(&args, '{');
152
else
153
current_line = args, args = NULL;
154
155
}
156
else
157
current_line = NULL;
158
}
159
160
if (current_line)
161
parse_line(NULL, current_line, subargs, 0, 0, 1);
162
163
break;
164
}
165
}
166
167
BUILT_IN_COMMAND(docmd)
168
{
169
char *body, *expr, *cmd, *ptr;
170
char *newexp = NULL;
171
int args_used = 0;
172
int result;
173
174
if (*args == '{')
175
{
176
if (!(body = next_expr(&args, '{')))
177
{
178
error("DO: unbalanced {");
179
return;
180
}
181
if (args && *args && (cmd = next_arg(args, &args)) &&
182
!my_stricmp (cmd, "while"))
183
{
184
if (!(expr = next_expr(&args, '(')))
185
{
186
error("DO: unbalanced (");
187
return;
188
}
189
will_catch_break_exceptions++;
190
will_catch_return_exceptions++;
191
192
while (1)
193
{
194
parse_line (NULL, body, subargs ? subargs : empty_string, 0, 0, 1);
195
if (break_exception)
196
{
197
break_exception = 0;
198
break;
199
}
200
if (continue_exception)
201
{
202
continue_exception = 0;
203
continue;
204
}
205
206
if (return_exception)
207
break;
208
malloc_strcpy(&newexp, expr);
209
ptr = parse_inline(newexp, subargs ? subargs : empty_string,
210
&args_used);
211
result = check_val(ptr);
212
new_free(&ptr);
213
if (!result)
214
break;
215
}
216
new_free(&newexp);
217
will_catch_break_exceptions--;
218
will_catch_continue_exceptions--;
219
return;
220
}
221
/* falls through to here if its /do {...} */
222
parse_line (NULL, body, subargs ? subargs : empty_string, 0, 0, 1);
223
}
224
/* falls through to here if it its /do ... */
225
parse_line (NULL, args, subargs ? subargs : empty_string, 0, 0, 1);
226
}
227
228
/*ARGSUSED*/
229
BUILT_IN_COMMAND(whilecmd)
230
{
231
char *exp = NULL,
232
*ptr = NULL,
233
*body = NULL,
234
*newexp = NULL;
235
int args_used; /* this isn't used here, but is passed
236
* to expand_alias() */
237
int whileval = !strcmp(command, "WHILE");
238
239
if (!(ptr = next_expr(&args, '(')))
240
{
241
error("WHILE: missing boolean expression");
242
return;
243
}
244
exp = LOCAL_COPY(ptr);
245
if ((ptr = next_expr_failok(&args, '{')) == (char *) 0)
246
ptr = args;
247
248
body = LOCAL_COPY(ptr);
249
250
will_catch_break_exceptions++;
251
will_catch_continue_exceptions++;
252
make_local_stack(NULL);
253
while (1)
254
{
255
newexp = LOCAL_COPY(exp);
256
ptr = parse_inline(newexp, subargs ? subargs : empty_string, &args_used);
257
if (check_val(ptr) != whileval)
258
break;
259
new_free(&ptr);
260
parse_line(NULL, body, subargs ? subargs : empty_string, 0, 0, 0);
261
if (continue_exception)
262
{
263
continue_exception = 0;
264
continue;
265
}
266
if (break_exception)
267
{
268
break_exception = 0;
269
break;
270
}
271
if (return_exception)
272
break;
273
}
274
will_catch_break_exceptions--;
275
will_catch_continue_exceptions--;
276
destroy_local_stack();
277
new_free(&ptr);
278
}
279
280
BUILT_IN_COMMAND(foreach)
281
{
282
char *struc = NULL,
283
*ptr,
284
*body = NULL,
285
*var = NULL;
286
char **sublist;
287
int total;
288
int i;
289
int slen;
290
int old_display;
291
int list = VAR_ALIAS;
292
int af;
293
294
while (args && my_isspace(*args))
295
args++;
296
297
if (*args == '-')
298
args++, list = COMMAND_ALIAS;
299
300
if ((ptr = new_next_arg(args, &args)) == NULL)
301
{
302
error("FOREACH: missing structure expression");
303
return;
304
}
305
struc = upper(remove_brackets(ptr, subargs, &af));
306
307
if ((var = next_arg(args, &args)) == NULL)
308
{
309
new_free(&struc);
310
error("FOREACH: missing variable");
311
return;
312
}
313
while (my_isspace(*args))
314
args++;
315
316
if ((body = next_expr(&args, '{')) == NULL) /* } */
317
{
318
new_free(&struc);
319
error("FOREACH: missing statement");
320
return;
321
}
322
323
if ((sublist = get_subarray_elements(struc, &total, list)) == NULL)
324
{
325
new_free(&struc);
326
return; /* Nothing there. */
327
}
328
329
slen=strlen(struc);
330
old_display=window_display;
331
make_local_stack(NULL);
332
for (i=0;i<total;i++)
333
{
334
window_display=0;
335
add_local_alias(var, sublist[i]+slen+1);
336
window_display=old_display;
337
parse_line(NULL, body, subargs ? subargs:empty_string, 0, 0, 0);
338
new_free(&sublist[i]);
339
}
340
destroy_local_stack();
341
new_free((char **)&sublist);
342
new_free(&struc);
343
}
344
345
/*
346
* FE: Written by Jeremy Nelson ([email protected])
347
*
348
* FE: replaces recursion
349
*
350
* The thing about it is that you can nest variables, as this command calls
351
* expand_alias until the list doesnt change. So you can nest lists in
352
* lists, and hopefully that will work. However, it also makes it
353
* impossible to have $s anywhere in the list. Maybe ill change that
354
* some day.
355
*/
356
357
BUILT_IN_COMMAND(fe)
358
{
359
char *list = NULL,
360
*templist = NULL,
361
*placeholder,
362
*sa,
363
*vars,
364
*varmem = NULL,
365
*var[255],
366
*word = NULL,
367
*todo = NULL,
368
fec_buffer[2] = { 0 };
369
int ind, y, args_flag;
370
int old_display;
371
int doing_fe = !my_stricmp(command, "FE");
372
373
list = next_expr(&args, '(');
374
375
if (!list)
376
{
377
error("%s: Missing List for /%s", command, command);
378
return;
379
}
380
381
sa = subargs ? subargs : space;
382
383
templist = expand_alias(list, sa, &args_flag, NULL);
384
if (!templist || !*templist)
385
{
386
new_free(&templist);
387
return;
388
}
389
390
vars = args;
391
if (!(args = strchr(args, '{'))) /* } */
392
{
393
error("%s: Missing commands", command);
394
new_free(&templist);
395
return;
396
}
397
398
/* This is subtle - we have to create a duplicate of the string
399
* containing the var names, in case there's no space between
400
* it and the commands. */
401
args[0] = '\0';
402
malloc_strcpy(&varmem, vars);
403
vars = varmem;
404
args[0] = '{';
405
406
ind = 0;
407
while ((var[ind] = next_arg(vars, &vars)))
408
{
409
ind++;
410
411
if (ind == 255)
412
{
413
error("%s: Too many variables", command);
414
new_free(&templist);
415
new_free(&varmem);
416
return;
417
}
418
}
419
420
if (ind < 1)
421
{
422
error("%s: You did not specify any variables", command);
423
new_free(&templist);
424
new_free(&varmem);
425
return;
426
}
427
428
if (!(todo = next_expr(&args, '{'))) /* } { */
429
{
430
error("%s: Missing }", command);
431
new_free(&templist);
432
new_free(&varmem);
433
return;
434
}
435
436
old_display = window_display;
437
438
placeholder = templist;
439
440
will_catch_break_exceptions++;
441
will_catch_continue_exceptions++;
442
443
make_local_stack(NULL);
444
445
if (doing_fe) {
446
/* FE */
447
word = new_next_arg(templist, &templist);
448
} else {
449
/* FEC */
450
word = fec_buffer;
451
word[0] = *templist++;
452
if (word[0] == '\0')
453
word = NULL;
454
}
455
456
while (word)
457
{
458
window_display = 0;
459
for ( y = 0 ; y < ind ; y++ )
460
{
461
if (word) {
462
add_local_alias(var[y], word);
463
464
if (doing_fe) {
465
/* FE */
466
word = new_next_arg(templist, &templist);
467
} else {
468
/* FEC */
469
word[0] = *templist++;
470
if (word[0] == '\0')
471
word = NULL;
472
}
473
} else {
474
add_local_alias(var[y], empty_string);
475
}
476
}
477
window_display = old_display;
478
parse_line(NULL, todo, subargs?subargs:empty_string, 0, 0, 0);
479
if (continue_exception)
480
{
481
continue_exception = 0;
482
continue;
483
}
484
if (break_exception)
485
{
486
break_exception = 0;
487
break;
488
}
489
if (return_exception)
490
break;
491
}
492
493
destroy_local_stack();
494
will_catch_break_exceptions--;
495
will_catch_continue_exceptions--;
496
497
window_display = old_display;
498
new_free(&placeholder);
499
new_free(&varmem);
500
}
501
502
/* FOR command..... prototype:
503
* for (commence,evaluation,iteration)
504
* in the same style of C's for, the for loop is just a specific
505
* type of WHILE loop.
506
*
507
* IMPORTANT: Since ircII uses ; as a delimeter between commands,
508
* commas were chosen to be the delimiter between expressions,
509
* so that semicolons may be used in the expressions (think of this
510
* as the reverse as C, where commas seperate commands in expressions,
511
* and semicolons end expressions.
512
*/
513
/* I suppose someone could make a case that since the
514
* foreach_handler() routine weeds out any for command that doesnt have
515
* two commans, that checking for those 2 commas is a waste. I suppose.
516
*/
517
BUILT_IN_COMMAND(forcmd)
518
{
519
char *working = NULL;
520
char *commence = NULL;
521
char *evaluation = NULL;
522
char *lameeval = NULL;
523
char *iteration = NULL;
524
char *sa = NULL;
525
int argsused = 0;
526
char *blah = NULL;
527
char *commands = NULL;
528
529
/* Get the whole () thing */
530
if ((working = next_expr(&args, '(')) == NULL) /* ) */
531
{
532
error("FOR: missing closing parenthesis");
533
return;
534
}
535
commence = LOCAL_COPY(working);
536
537
/* Find the beginning of the second expression */
538
539
evaluation = strchr(commence, ',');
540
if (!evaluation)
541
{
542
error("FOR: no components!");
543
return;
544
}
545
do
546
*evaluation++ = '\0';
547
while (my_isspace(*evaluation));
548
549
/* Find the beginning of the third expression */
550
iteration = strchr(evaluation, ',');
551
if (!iteration)
552
{
553
error("FOR: Only two components!");
554
return;
555
}
556
do
557
{
558
*iteration++ = '\0';
559
}
560
while (my_isspace(*iteration));
561
562
working = args;
563
while (my_isspace(*working))
564
*working++ = '\0';
565
566
if ((working = next_expr(&working, '{')) == NULL) /* } */
567
{
568
error("FOR: badly formed commands");
569
return;
570
}
571
572
make_local_stack(NULL);
573
574
commands = LOCAL_COPY(working);
575
576
sa = subargs?subargs:empty_string;
577
parse_line(NULL, commence, sa, 0, 0, 0);
578
579
will_catch_break_exceptions++;
580
will_catch_continue_exceptions++;
581
582
while (1)
583
{
584
lameeval = LOCAL_COPY(evaluation);
585
586
blah = parse_inline(lameeval,sa,&argsused);
587
if (!check_val(blah))
588
{
589
new_free(&blah);
590
break;
591
}
592
593
new_free(&blah);
594
parse_line(NULL, commands, sa, 0, 0, 0);
595
if (break_exception)
596
{
597
break_exception = 0;
598
break;
599
}
600
if (continue_exception)
601
continue_exception = 0; /* Dont continue here! */
602
if (return_exception)
603
break;
604
parse_line(NULL, iteration, sa, 0, 0, 0);
605
}
606
607
destroy_local_stack();
608
will_catch_break_exceptions--;
609
will_catch_continue_exceptions--;
610
611
new_free(&blah);
612
}
613
614
/*
615
616
Need to support something like this:
617
618
switch (text to be matched)
619
{
620
(sample text)
621
{
622
...
623
}
624
(sample text2)
625
(sample text3)
626
{
627
...
628
}
629
...
630
}
631
632
How it works:
633
634
The command is technically made up a single (...) expression and
635
a single {...} expression. The (...) expression is taken to be
636
regular expando-text (much like the (...) body of /fe.
637
638
The {...} body is taken to be a series of [(...)] {...} pairs.
639
The [(...)] expression is taken to be one or more consecutive
640
(...) structures, which are taken to be text expressions to match
641
against the header text. If any of the (...) expressions are found
642
to match, then the commands in the {...} body are executed.
643
644
There may be as many such [(...)] {...} pairs as you need. However,
645
only the *first* pair found to be matching is actually executed,
646
and the others are ignored, so placement of your switches are
647
rather important: Put your most general ones last.
648
649
*/
650
BUILT_IN_COMMAND(switchcmd)
651
{
652
char *control, *body, *header, *commands;
653
int af;
654
int found_def = 0;
655
char *def = NULL;
656
657
if (!(control = next_expr(&args, '(')))
658
{
659
error("SWITCH: String to be matched not found where expected");
660
return;
661
}
662
663
control = expand_alias(control, subargs, &af, NULL);
664
if (internal_debug & DEBUG_EXPANSIONS && !in_debug_yell)
665
debugyell("%s expression expands to: (%s)", command, control);
666
667
if (!(body = next_expr(&args, '{')))
668
error("SWITCH: Execution body not found where expected");
669
670
make_local_stack(NULL);
671
while (body && *body)
672
{
673
int hooked = 0;
674
675
while (*body == '(')
676
{
677
if (!(header = next_expr(&body, '(')))
678
{
679
error("SWITCH: Case label not found where expected");
680
new_free(&control);
681
return;
682
}
683
if (!strcmp(header, "default"))
684
{
685
if (def)
686
{
687
error("SWITCH: No more than one \"default\" case");
688
new_free(&control);
689
return;
690
}
691
found_def = 1;
692
}
693
header = expand_alias(header, subargs, &af, NULL);
694
if (internal_debug & DEBUG_EXPANSIONS && !in_debug_yell)
695
debugyell("%s expression expands to: (%s)", command, header);
696
if (wild_match(header, control))
697
hooked = 1;
698
new_free(&header);
699
if (*body == ';')
700
body++; /* ugh. */
701
}
702
703
if (!(commands = next_expr(&body, '{')))
704
{
705
error("SWITCH: case body not found where expected");
706
break;
707
}
708
709
if (hooked)
710
{
711
parse_line(NULL, commands, subargs, 0, 0, 0);
712
def = NULL;
713
break;
714
}
715
else if (!def && found_def)
716
{
717
def = LOCAL_COPY(commands);
718
found_def = 0;
719
}
720
721
if (*body == ';')
722
body++; /* grumble */
723
}
724
if (def && *def)
725
parse_line(NULL, def, subargs, 0, 0, 0);
726
destroy_local_stack();
727
new_free(&control);
728
}
729
730
BUILT_IN_COMMAND(repeatcmd)
731
{
732
char *num_expr = NULL;
733
int value;
734
735
while (isspace((unsigned char)*args))
736
args++;
737
738
if (*args == '(')
739
{
740
char *tmp_val;
741
char *dumb_copy;
742
int argsused;
743
char *sa = subargs ? subargs : empty_string;
744
745
num_expr = next_expr(&args, '(');
746
dumb_copy = LOCAL_COPY(num_expr);
747
tmp_val = parse_inline(dumb_copy,sa,&argsused);
748
value = my_atol(tmp_val);
749
new_free(&tmp_val);
750
}
751
else
752
{
753
char *tmp_val;
754
int af;
755
756
num_expr = new_next_arg(args, &args);
757
tmp_val = expand_alias(num_expr, subargs, &af, NULL);
758
value = my_atol(tmp_val);
759
new_free(&tmp_val);
760
}
761
762
if (value <= 0)
763
return;
764
while (value--)
765
parse_line(NULL, args, subargs ? subargs : empty_string, 0, 0, 1);
766
767
return;
768
}
769
770