/* * if.c: handles the IF command for IRCII * * Written By Michael Sandrof * * Copyright (c) 1990 Michael Sandrof. * Copyright (c) 1991, 1992 Troy Rollo. * Copyright (c) 1992-2004 Matthew R. Green. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "irc.h" IRCII_RCSID("@(#)$eterna: if.c,v 1.29 2004/01/06 08:14:09 mrg Exp $"); #include "alias.h" #include "ircaux.h" #include "window.h" #include "vars.h" #include "output.h" #include "if.h" static int charcount(u_char *, int); /* * next_expr finds the next expression delimited by brackets. The type * of bracket expected is passed as a parameter. Returns NULL on error. */ u_char * next_expr(args, itype) u_char **args; int itype; { u_char *ptr, *ptr2, *ptr3; u_char type = (u_char)itype; if (!*args) return NULL; ptr2 = *args; if (!*ptr2) return 0; if (*ptr2 != type) { say("Expression syntax"); return 0; } /* { */ ptr = MatchingBracket(ptr2 + 1, type, (type == '(') ? ')' : '}'); if (!ptr) { say("Unmatched '%c'", type); return 0; } *ptr = '\0'; do { ptr2++; } while (isspace(*ptr2)); ptr3 = ptr+1; while (isspace(*ptr3)) ptr3++; *args = ptr3; if (*ptr2) { ptr--; while (isspace(*ptr)) *ptr-- = '\0'; } return ptr2; } /*ARGSUSED*/ void ifcmd(command, args, subargs) u_char *command, *args; u_char *subargs; { u_char *expr; u_char *sub; int flag = 0; int result; if (!(expr = next_expr(&args, '('))) { yell("Missing CONDITION in IF"); return; } sub = parse_inline(expr, subargs?subargs:empty_string, &flag); if (get_int_var(DEBUG_VAR) & DEBUG_EXPANSIONS) yell("If expression expands to: (%s)", sub); if (!*sub || *sub == '0') result = 0; else result = 1; new_free(&sub); if (!(expr = next_expr(&args, '{'))) { yell("Missing THEN portion in IF"); return; } if (!result && !(expr = next_expr(&args, '{'))) return; parse_line((u_char *) 0, expr, subargs ? subargs : empty_string, 0, 0, 0); return; } /*ARGSUSED*/ void whilecmd(command, args, subargs) u_char *command, *args; u_char *subargs; { u_char *expr = (u_char *) 0, *ptr, *body = (u_char *) 0, *newexp = (u_char *) 0; int args_used; /* this isn't used here, but is passed * to expand_alias() */ if ((ptr = next_expr(&args, '(')) == (u_char *) 0) { yell("WHILE: missing boolean expression"); return; } malloc_strcpy(&expr, ptr); if ((ptr = next_expr(&args, '{')) == (u_char *) 0) { say("WHILE: missing expression"); new_free(&expr); return; } malloc_strcpy(&body, ptr); while (1) { malloc_strcpy(&newexp, expr); ptr = parse_inline(newexp, subargs ? subargs : empty_string, &args_used); if (*ptr && *ptr !='0') { new_free(&ptr); parse_line((u_char *) 0, body, subargs ? subargs : empty_string, 0, 0, 0); } else break; } new_free(&newexp); new_free(&ptr); new_free(&expr); new_free(&body); } static int charcount(string, what) u_char *string; int what; { int x = 0; u_char *place = string - 1; while ((place = my_index(place + 1, what))) x++; return x; } /* * How it works -- if There are no parenthesis, it must be a * foreach array command. If there are parenthesis, and there are * exactly two commas, it must be a C-like for command, else it must * must be an foreach word command */ void foreach_handler(command,args,subargs) u_char *command, *args, *subargs; { u_char *temp = (u_char *) 0; u_char *placeholder; u_char *temp2 = (u_char *) 0; malloc_strcpy(&temp, args); placeholder = temp; if (*temp == '(') { if ((temp2 = next_expr(&temp,'(')) == (u_char *) 0) { new_free(&placeholder); return; } if (charcount(temp2, ',') == 2) forcmd(command,args,subargs); else fe(command,args,subargs); } else foreach(command,args,subargs); new_free(&placeholder); } /*ARGSUSED*/ void foreach(command, args, subargs) u_char *command, *args; u_char *subargs; { u_char *struc = (u_char *) 0, *ptr, *body = (u_char *) 0, *var = (u_char *) 0; u_char **sublist; int total; int i; int slen; int old_display; if ((ptr = new_next_arg(args, &args)) == (u_char *) 0) { yell("FOREACH: missing structure expression"); return; } malloc_strcpy(&struc, ptr); malloc_strcat(&struc, UP(".")); upper(struc); if ((var = next_arg(args, &args)) == (u_char *) 0) { new_free(&struc); yell("FOREACH: missing variable"); return; } while (isspace(*args)) args++; if ((body = next_expr(&args, '{')) == (u_char *) 0) /* } */ { new_free(&struc); yell("FOREACH: missing statement"); return; } sublist = match_alias(struc, &total, VAR_ALIAS); slen = my_strlen(struc); old_display = window_display; for (i = 0; i < total; i++) { window_display = 0; add_alias(VAR_ALIAS, var, sublist[i]+slen); window_display = old_display; parse_line((u_char *) 0, body, subargs ? subargs : empty_string, 0, 0, 0); new_free(&sublist[i]); } new_free(&sublist); new_free(&struc); } /* * FE: Written by Jeremy Nelson (jnelson@iastate.edu) * * FE: replaces recursion * * The thing about it is that you can nest variables, as this command calls * expand_alias until the list doesnt change. So you can nest lists in * lists, and hopefully that will work. However, it also makes it * impossible to have $s anywhere in the list. Maybe ill change that * some day. */ void fe(command, args, subargs) u_char *command, *args, *subargs; { u_char *list = (u_char *) 0, *templist = (u_char *) 0, *placeholder, *oldlist = (u_char *) 0, *sa, *vars, *var[255], *word = (u_char *) 0, *todo = (u_char *) 0; int ind, x, y, blah, args_flag; int old_display; for (x = 0; x < 255; var[x++] = (u_char *) 0) ; list = next_expr(&args, '('); /* ) */ if (!list) { yell ("FE: Missing List for /FE"); return; } sa = subargs ? subargs : (u_char *) " "; malloc_strcpy(&templist, list); do { malloc_strcpy(&oldlist, templist); new_free(&templist); templist = expand_alias((u_char *) 0,oldlist,sa,&args_flag, (u_char **) 0); } while (my_strcmp(templist, oldlist)); new_free(&oldlist); if (*templist == '\0') { new_free(&templist); return; } vars = args; if (!(args = my_index(args, '{'))) /* } */ { yell ("FE: Missing commands"); new_free(&templist); return; } *(args-1) = '\0'; ind = 0; while ((var[ind++] = next_arg(vars, &vars))) { if (ind == 255) { yell ("FE: Too many variables"); new_free(&templist); return; } } ind = ind ? ind - 1: 0; if (!(todo = next_expr(&args, '{'))) /* } { */ { yell ("FE: Missing }"); new_free(&templist); return; } blah = word_count(templist); old_display = window_display; placeholder = templist; for ( x = 0 ; x < blah ; ) { window_display = 0; for ( y = 0 ; y < ind ; y++ ) { word = ((x+y)<blah) ? next_arg(templist, &templist) : (u_char *) 0; add_alias(VAR_ALIAS, var[y], word); } window_display = old_display; x += ind; parse_line((u_char *) 0, todo, subargs ? subargs : empty_string, 0, 0, 0); } window_display = 0; for (y=0;y<ind;y++) { delete_alias(VAR_ALIAS,var[y]); } window_display = old_display; new_free(&placeholder); } /* FOR command..... prototype: * for (commence,evaluation,iteration) * in the same style of C's for, the for loop is just a specific * type of WHILE loop. * * IMPORTANT: Since ircII uses ; as a delimeter between commands, * commas were chosen to be the delimiter between expressions, * so that semicolons may be used in the expressions (think of this * as the reverse as C, where commas seperate commands in expressions, * and semicolons end expressions. */ /* I suppose someone could make a case that since the * foreach_handler() routine weeds out any for command that doesnt have * two commans, that checking for those 2 commas is a waste. I suppose. */ void forcmd(command, args, subargs) u_char *command; u_char *args; u_char *subargs; { u_char *working = (u_char *) 0; u_char *commence = (u_char *) 0; u_char *evaluation = (u_char *) 0; u_char *lameeval = (u_char *) 0; u_char *iteration = (u_char *) 0; u_char *sa = (u_char *) 0; int argsused = 0; u_char *blah = (u_char *) 0; u_char *commands = (u_char *) 0; /* Get the whole () thing */ if ((working = next_expr(&args, '(')) == (u_char *) 0) /* ) */ { yell("FOR: missing closing parenthesis"); return; } malloc_strcpy(&commence, working); /* Find the beginning of the second expression */ evaluation = my_index(commence, ','); if (!evaluation) { yell("FOR: no components!"); new_free(&commence); return; } do *evaluation++ = '\0'; while (isspace(*evaluation)); /* Find the beginning of the third expression */ iteration = my_index(evaluation, ','); if (!iteration) { yell("FOR: Only two components!"); new_free(&commence); return; } do { *iteration++ = '\0'; } while (isspace(*iteration)); working = args; while (isspace(*working)) *working++ = '\0'; if ((working = next_expr(&working, '{')) == (u_char *) 0) /* } */ { yell("FOR: badly formed commands"); new_free(&commence); return; } malloc_strcpy(&commands, working); sa = subargs?subargs:empty_string; parse_line((u_char *) 0, commence, sa, 0, 0, 0); while (1) { malloc_strcpy(&lameeval, evaluation); blah = parse_inline(lameeval,sa,&argsused); if (*blah && *blah != '0') { new_free(&blah); parse_line((u_char *) 0, commands, sa, 0, 0, 0); parse_line((u_char *) 0, iteration, sa, 0, 0, 0); } else break; } new_free(&blah); new_free(&lameeval); new_free(&commence); new_free(&commands); } /* fec - iterate over a list of characters */ extern void fec(command, args, subargs) u_char *command, *args, *subargs; { u_char *pointer; u_char *list = (u_char *) 0; u_char *var = (u_char *) 0; u_char booya[2]; int args_flag = 0, old_display; u_char *sa, *todo; list = next_expr(&args, '('); /* ) */ if (list == (u_char *) 0) { yell ("FEC: Missing List for /FEC"); return; } sa = subargs ? subargs : empty_string; list = expand_alias((u_char *) 0, list, sa, &args_flag, (u_char **) 0); pointer = list; var = next_arg(args, &args); args = my_index(args, '{'); /* } */ if ((todo = next_expr(&args, '{')) == (u_char *) 0) { yell ("FE: Missing }"); return; } booya[1] = '\0'; old_display = window_display; while (*pointer) { window_display = 0; booya[0] = *pointer++; add_alias(VAR_ALIAS, var, booya); window_display = old_display; parse_line((u_char *) 0, todo, subargs ? subargs : empty_string, 0, 0, 0); } window_display = 0; delete_alias(VAR_ALIAS,var); window_display = old_display; new_free(&list); }