/* eval.c */ /* Expression parsing module created by Lawrence Foard */ #include "copyright.h" #include <ctype.h> #include <string.h> #include <math.h> #include <sys/time.h> #include <sys/types.h> #include "config.h" #include "db.h" #include "interface.h" #include "externs.h" #ifdef MEM_CHECK #include "mem_check.h" #endif #ifdef USE_NALLOC #include "nalloc.h" extern NALLOC *glurp; #endif /* functions not found in this file */ extern void fun_lwho(); /* bsd.c */ extern void fun_lsearch(); /* wiz.c */ /* functions for the string expressions */ void exec(); dbref match_thing(player, name) dbref player; const char *name; { init_match(player, name, NOTYPE); match_everything(); return (noisy_match_result()); } /* -------------------------------------------------------------------------- * Utility functions: RAND, TIME */ void fun_rand(buff, args, dumm1, dumm2) char *buff; char *args[10]; dbref dumm1, dumm2; { /* * Uses Sh'dow's random number generator, found in utils.c. Better * distribution than original, w/ minimal speed losses. */ sprintf(buff, "%d", getrandom(atoi(args[0]))); } void fun_time(buff, dumm1, dumm2, dumm3) char *buff; char *dumm3[10]; dbref dumm1, dumm2; { time_t tt; tt = time((time_t *) 0); /* * There is NO WAY this string could every be longer than BUFFER_LEN. * therefore, no checking is required. */ sprintf(buff, "%s", ctime(&tt)); buff[strlen(buff)-1] = '\0'; } /* -------------------------------------------------------------------------- * Attribute functions: GET, XGET, V, S */ void fun_get(buff, args, player, dummy) char *buff; char *args[10]; dbref player; dbref dummy; { dbref thing; char *s; ATTR *a; char tbuf1[BUFFER_LEN]; strcpy(tbuf1, args[0]); for(s = tbuf1; *s && (*s != '/'); s++); if(!*s) { /* * There is NO WAY this string could every be longer than BUFFER_LEN. * therefore, no checking is required. */ strcpy(buff, "#-1 BAD ARGUMENT FORMAT TO GET"); return; } *s++ = 0; thing = match_thing(player, tbuf1); if(thing == NOTHING) { /* * There is NO WAY this string could every be longer than BUFFER_LEN. * therefore, no checking is required. */ strcpy(buff, "#-1 NO SUCH OBJECT VISIBLE"); return; } if(*s == '_') s++; if(!*s) { /* * There is NO WAY this string could every be longer than BUFFER_LEN. * therefore, no checking is required. */ strcpy(buff, "#-1 BAD ARGUMENT FORMAT TO GET"); return; } a = atr_get(thing, s); if(!a) { /* * There is NO WAY this string could every be longer than BUFFER_LEN. * therefore, no checking is required. */ strcpy(buff, "#-1 NO SUCH ATTRIBUTE"); return; } if (Hasprivs(player) || (db[player].owner == db[a->creator].owner) || ((controls(player, thing) || Visual(thing)) && !((a->flags & AF_WIZARD) || (a->flags & AF_DARK))) || !(a->flags & AF_ODARK)) { if(strlen(uncompress(a->value)) < BUFFER_LEN) strcpy(buff, uncompress(a->value)); else /* * There is NO WAY this string could every be longer than BUFFER_LEN. * therefore, no checking is required. */ strcpy(buff, "#-1 ATTRIBUTE LENGTH TOO LONG"); } else /* * There is NO WAY this number could every be longer than BUFFER_LEN. * therefore, no checking is required. */ strcpy(buff, "#-1 NO PERMISSION TO GET ATTRIBUTE"); } /* Functions like get, but uses the standard way of passing arguments */ /* to a function, and thus doesn't choke on nested functions within. */ void fun_xget(buff, args, player, dumm1) char *buff; char *args[10]; dbref player; dbref dumm1; { dbref thing; char *attrib; char *obj; ATTR *a; obj = args[0]; thing = match_thing(player, obj); if (thing == NOTHING) { strcpy(buff, "#-1 NO SUCH OBJECT VISIBLE"); return; } attrib = args[1]; a = atr_get(thing, attrib); if (!a) { strcpy(buff, "#-1 NO SUCH ATTRIBUTE"); return; } if (Hasprivs(player) || (db[player].owner == db[a->creator].owner) || ((controls(player, thing) || Visual(thing)) && !((a->flags & AF_WIZARD) || (a->flags & AF_DARK))) || !(a->flags & AF_ODARK)) { if (strlen(uncompress(a->value)) < BUFFER_LEN) strcpy(buff, uncompress(a->value)); else strcpy(buff, "#-1 ATTRIBUTE LENGTH TOO LONG"); } else strcpy(buff, "#-1 NO PERMISSION TO GET ATTRIBUTE"); } /* handle 0-9,va-vz,n,# */ void fun_v(buff, args, privs, doer) char *buff; char *args[10]; dbref privs; dbref doer; { int c; ATTR *a; switch (c = args[0][0]) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (!wptr[c - '0']) { buff[0] = '\0'; return; } if(strlen(wptr[c - '0']) < BUFFER_LEN) strcpy(buff, wptr[c - '0']); else buff[0] = '\0'; break; case 'n': case 'N': if(args[0][1]) { a = atr_get(privs, args[0]); if(a) { if((a->flags & AF_DARK) || ((a->flags & AF_WIZARD) && !Hasprivs(privs))) /* * There is NO WAY this number could every be longer than * BUFFER_LEN. therefore, no checking is required. */ buff[0] = '\0'; else { if(strlen(uncompress(a->value)) < BUFFER_LEN) strcpy(buff, uncompress(a->value)); else buff[0] = '\0'; } } else buff[0] = '\0'; } else /* * There is NO WAY this string could every be longer than BUFFER_LEN. * therefore, no checking is required. */ strcpy(buff, db[doer].name); break; case '#': /* * There is NO WAY this number could every be longer than BUFFER_LEN. * therefore, no checking is required. */ sprintf(buff, "#%d", doer); break; /* info about location and stuff */ /* objects # */ case '!': /* * There is NO WAY this number could every be longer than BUFFER_LEN. * therefore, no checking is required. */ sprintf(buff, "#%d", privs); break; default: if(*args[0] == '_') a = atr_get(privs, args[0]+1); else a = atr_get(privs, args[0]); if(a) { if((a->flags & AF_DARK) || ((a->flags & AF_WIZARD) && !Hasprivs(privs))) buff[0] = '\0'; else { if(strlen(uncompress(a->value)) < BUFFER_LEN) strcpy(buff, uncompress(a->value)); else buff[0] = '\0'; } } else buff[0] = '\0'; } } void fun_s(buff, args, privs, doer) char *buff; char *args[10]; dbref privs; dbref doer; { char *s = pronoun_substitute(doer, args[0], privs); if(strlen(s) < BUFFER_LEN) strcpy(buff, s); else buff[0] = '\0'; } /* -------------------------------------------------------------------------- * Arithmetic functions: ADD, SUB, MUL, DIV, MOD, GT, GTE, LT, LTE, * EQ, NEQ, MAX, MIN, DIST2D, DIST3D, LNUM */ void fun_add(buff, args, dumm1, dumm2) char *buff; char *args[10]; dbref dumm1, dumm2; { /* * There is NO WAY this number could every be longer than BUFFER_LEN. * therefore, no checking is required. */ sprintf(buff, "%d", atoi(args[0]) + atoi(args[1])); } void fun_sub(buff, args, dumm1, dumm2) char *buff; char *args[10]; dbref dumm1, dumm2; { /* * There is NO WAY this number could every be longer than BUFFER_LEN. * therefore, no checking is required. */ sprintf(buff, "%d", atoi(args[0]) - atoi(args[1])); } void fun_mul(buff, args, dumm1, dumm2) char *buff; char *args[10]; dbref dumm1, dumm2; { /* * There is NO WAY this number could every be longer than BUFFER_LEN. * therefore, no checking is required. */ sprintf(buff, "%d", atoi(args[0]) * atoi(args[1])); } void fun_div(buff, args, dumm1, dumm2) char *buff; char *args[10]; dbref dumm1, dumm2; { int bot = atoi(args[1]); if (bot == 0) bot = 1; /* * There is NO WAY this number could every be longer than BUFFER_LEN. * therefore, no checking is required. */ sprintf(buff, "%d", atoi(args[0]) / bot); } void fun_mod(buff, args, dumm1, dumm2) char *buff; char *args[10]; dbref dumm1, dumm2; { int bot = atoi(args[1]); if (bot == 0) bot = 1; /* * There is NO WAY this number could every be longer than BUFFER_LEN. * therefore, no checking is required. */ sprintf(buff, "%d", atoi(args[0]) % bot); } void fun_gt(buff, args, dumm1, dumm2) char *buff; char *args[10]; dbref dumm1, dumm2; { /* * There is NO WAY this number could every be longer than BUFFER_LEN. * therefore, no checking is required. */ sprintf(buff,"%d", (atoi(args[0]) > atoi(args[1]))); } void fun_gte(buff, args, dumm1, dumm2) char *buff; char *args[10]; dbref dumm1, dumm2; { /* * There is NO WAY this number could every be longer than BUFFER_LEN. * therefore, no checking is required. */ sprintf(buff,"%d", (atoi(args[0]) >= atoi(args[1]))); } void fun_lt(buff, args, dumm1, dumm2) char *buff; char *args[10]; dbref dumm1, dumm2; { /* * There is NO WAY this number could every be longer than BUFFER_LEN. * therefore, no checking is required. */ sprintf(buff,"%d", (atoi(args[0]) < atoi(args[1]))); } void fun_lte(buff, args, dumm1, dumm2) char *buff; char *args[10]; dbref dumm1, dumm2; { /* * There is NO WAY this number could every be longer than BUFFER_LEN. * therefore, no checking is required. */ sprintf(buff,"%d", (atoi(args[0]) <= atoi(args[1]))); } void fun_eq(buff, args, dumm1, dumm2) char *buff; char *args[10]; dbref dumm1, dumm2; { /* * There is NO WAY this number could every be longer than BUFFER_LEN. * therefore, no checking is required. */ sprintf(buff,"%d", (atoi(args[0]) == atoi(args[1]))); } void fun_neq(buff, args, dumm1, dumm2) char *buff; char *args[10]; dbref dumm1, dumm2; { /* * There is NO WAY this number could every be longer than BUFFER_LEN. * therefore, no checking is required. */ sprintf(buff,"%d", (atoi(args[0]) != atoi(args[1]))); } void fun_max(buff, args, dumm1, dumm2) char *buff; char *args[10]; dbref dumm1, dumm2; { int max; int i = 1; if (!args[0]) { strcpy(buff, "#-1 TOO FEW ARGUMENTS"); return; } else max = atoi(args[0]); while (i < 10 && args[i]) { max = (atoi(args[i]) > max) ? atoi(args[i]) : max; i++; } sprintf(buff, "%d", max); } void fun_min(buff, args, dumm1, dumm2) char *buff; char *args[10]; dbref dumm1, dumm2; { int min; int i = 1; if (!args[0]) { strcpy(buff, "#-1 TOO FEW ARGUMENTS"); return; } else min = atoi(args[0]); while (i < 10 && args[i]) { min = (atoi(args[i]) < min) ? atoi(args[i]) : min; i++; } sprintf(buff, "%d", min); } /* this function and dist3d are taken from the 2.0 code */ void fun_dist2d(buff, args, dumm1, dumm2) char *buff; char *args[10]; dbref dumm1, dumm2; { int d; double r; d = atoi(args[0]) - atoi(args[2]); r = (double) (d * d); d = atoi(args[1]) - atoi(args[3]); r += (double) (d * d); d = (int) (sqrt(r) + 0.5); sprintf(buff, "%d", d); } void fun_dist3d(buff, args, dumm1, dumm2) char *buff; char *args[10]; dbref dumm1, dumm2; { int d; double r; d = atoi(args[0]) - atoi(args[3]); r = (double) (d * d); d = atoi(args[1]) - atoi(args[4]); r += (double) (d * d); d = atoi(args[2]) - atoi(args[5]); r += (double) (d * d); d = (int) (sqrt(r) + 0.5); sprintf(buff, "%d", d); } void fun_lnum(buff, args, dumm1, dumm2) char *buff; char *args[10]; dbref dumm1, dumm2; { int x, i; x = atoi(args[0]); if ((x > 100) || (x < 0)) { strcpy(buff, "#-1 NUMBER OUT OF RANGE"); return; } else { strcpy(buff,"0"); for (i = 1; i < x; i++) sprintf(buff, "%s %d", buff, i); } } /* -------------------------------------------------------------------------- * String functions: FIRST, REST, STRLEN, COMP, POS, MID, EXTRACT, WORDPOS, * MATCH, CAT, REMOVE, MEMBER, FLIP, UCSTR, LCSTR, WORDS */ /* read first word from a string */ void fun_first(buff, args, dumm1, dumm2) char *buff; char *args[10]; dbref dumm1, dumm2; { char *s = args[0]; char *b; /* get rid of leading space */ while (*s && (*s == ' ')) s++; b = s; while (*s && (*s != ' ')) s++; *s++ = 0; if(strlen(b) < BUFFER_LEN) strcpy(buff, b); else buff[0] = '\0'; } void fun_rest(buff, args, dumm1, dumm2) char *buff; char *args[10]; dbref dumm1, dumm2; { char *s = args[0]; /* skip leading space */ while (*s && (*s == ' ')) s++; /* skip firsts word */ while (*s && (*s != ' ')) s++; /* skip leading space */ while (*s && (*s == ' ')) s++; if(strlen(s) < BUFFER_LEN) strcpy(buff, s); else buff[0] = '\0'; } void fun_strlen(buff, args, dumm1, dumm2) char *buff; char *args[10]; dbref dumm1, dumm2; { /* * There is NO WAY this number could every be longer than BUFFER_LEN. * therefore, no checking is required. */ sprintf(buff, "%d", strlen(args[0])); } void fun_mid(buff, args, dumm1, dumm2) char *buff; char *args[10]; dbref dumm1, dumm2; { int l = atoi(args[1]), len = atoi(args[2]); if ((l < 0) || (len < 0) || ((len + l) > BUFFER_LEN)) { strcpy(buff, "#-1 OUT OF RANGE"); return; } if (l < strlen(args[0])) strcpy(buff, args[0] + l); else *buff = 0; buff[len] = 0; } void fun_comp(buff, args, dumm1, dumm2) char *buff; char *args[10]; dbref dumm1, dumm2; { int x; x = strcmp(args[0], args[1]); if (x > 0) /* * There is NO WAY this number could every be longer than BUFFER_LEN. * therefore, no checking is required. */ strcpy(buff, "1"); else if (x < 0) /* * There is NO WAY this number could every be longer than BUFFER_LEN. * therefore, no checking is required. */ strcpy(buff, "-1"); else /* * There is NO WAY this number could every be longer than BUFFER_LEN. * therefore, no checking is required. */ strcpy(buff, "0"); } void fun_pos(buff, args, dumm1, dumm2) char *buff; char *args[10]; dbref dumm1, dumm2; { int i = 1; char *t, *u, *s = args[1]; while (*s) { u = s; t = args[0]; while (*t && *t == *u) ++t, ++u; if (*t == '\0') { /* * There is NO WAY this number could every be longer than BUFFER_LEN. * therefore, no checking is required. */ sprintf(buff, "%d", i); return; } ++i, ++s; } /* * There is NO WAY this number could every be longer than BUFFER_LEN. * therefore, no checking is required. */ strcpy(buff, "#-1"); return; } void fun_match(buff, args, dumm1, dumm2) char *buff; char *args[10]; dbref dumm1, dumm2; { int a; int wcount = 1; char *s = args[0]; char *ptrsrv[10]; for (a = 0; a < 10; a++) ptrsrv[a] = wptr[a]; do { char *r; /* trim off leading space */ while (*s && (*s == ' ')) s++; r = s; /* scan to next space and truncate if necessary */ while (*s && (*s != ' ')) s++; if (*s) *s++ = 0; if (wild_match(args[1], r)) { /* * There is NO WAY this number could every be longer than BUFFER_LEN. * therefore, no checking is required. */ sprintf(buff, "%d", wcount); for (a = 0; a < 10; a++) wptr[a] = ptrsrv[a]; return; } wcount++; } while (*s); strcpy(buff, "#-1"); for (a = 0; a < 10; a++) wptr[a] = ptrsrv[a]; } /* taken from the 2.0 code */ void fun_wordpos(buff, args, dumm1, dumm2) char *buff; char *args[10]; dbref dumm1, dumm2; { char *cp; char done, inspace; int charpos = atoi(args[1]); int word = 1; for (inspace = 0, done = 0, cp = args[0]; cp && *cp && !done; cp++) { if ((*cp == ' ') && (!inspace)) { word++; inspace = 1; } if ((*cp != ' ') && (inspace)) inspace = 0; if ((cp - args[0] + 1) == charpos) done = 1; } if (!done) strcpy(buff, "#-1"); else sprintf(buff, "%d", word); } void fun_extract(buff, args, dumm1, dumm2) char *buff; char *args[10]; dbref dumm1, dumm2; { int start = atoi(args[1]), len = atoi(args[2]); char *s = args[0], *r; if ((start < 1) || (len < 1)) { *buff = 0; return; } start--; while (start && *s) { while (*s && (*s == ' ')) s++; while (*s && (*s != ' ')) s++; start--; } while (*s && (*s == ' ')) s++; r = s; while (len && *s) { while (*s && (*s == ' ')) s++; while (*s && (*s != ' ')) s++; len--; } *s = 0; if(strlen(r) < BUFFER_LEN) strcpy(buff, r); else buff[0] = '\0'; } int translate(arg) char *arg; { int temp; char *temp2; if (arg[0] == '#') if ((temp = atoi(arg+1)) == -1) return 0; else return temp; else temp2 = arg; while (isspace(*temp2)) temp2++; if ((*temp2 == '\0') && (temp2 == arg)) return 0; if (isdigit(*temp2)) return atoi(temp2); return 1; } void fun_cat(buff,args, dumm1, dumm2) char *buff; char *args[10]; dbref dumm1, dumm2; { if(strlen(args[0]) + strlen(args[1]) < BUFFER_LEN) sprintf(buff,"%s %s",args[0],args[1]); else sprintf(buff, "%s", args[0]); } void fun_remove(buff, args, dumm1, dumm2) char *buff; char *args[10]; dbref dumm1, dumm2; { char *s, *t, *p; int done = 0; /* * This function is 'safe' since it is impossible that any of the arg[] * elements will be larger than BUFFER_LEN, and in the worst case, this * does nothing to the the length, thereby it's still < BUFFER_LEN */ if(index(args[1],' ')) { strcpy(buff,"#-1 CAN ONLY DELETE ONE ELEMENT"); return; } s = p = args[0]; t = args[1]; while (*s && !done) { if (*t) if (*s == *t) t++; else { t = args[1]; while (*(s+1) && *s != ' ') s++; p = s; } else done = 1; s++; } if ((*t == '\0') && ((*(s-1) == ' ') || (*s == '\0'))) { if (p == args[0]) strcpy(buff,s); else { *p = '\0'; if (*s == '\0') strcpy(buff,args[0]); else sprintf(buff,"%s %s",args[0],s); } return; } strcpy(buff,args[0]); } void fun_member(buff,args, dumm1, dumm2) char *buff; char *args[10]; dbref dumm1, dumm2; { char *s, *t; int done = 0; int element = 1; if (index(args[1],' ')) { strcpy(buff,"#-1 CAN ONLY TEST ONE ELEMENT"); return; } s = args[0]; t = args[1]; while (*s && !done) { if (*t) if (*s == *t) t++; else { element++; t = args[1]; while (*(s+1) && *s != ' ') s++; } else done = 1; s++; } if ((*t == '\0') && ((*(s-1) == ' ') || (*s == '\0'))) { /* * There is NO WAY this number could every be longer than BUFFER_LEN. * therefore, no checking is required. */ sprintf(buff,"%d",element); return; } /* * There is NO WAY this number could every be longer than BUFFER_LEN. * therefore, no checking is required. */ strcpy(buff,"0"); } void fun_flip(buff, args, dumm1, dumm2) char *buff; char *args[10]; dbref dumm1, dumm2; { char *s = args[0]; char *p, *q, temp; int n; n = strlen(s); q = (n > 0) ? s + n - 1 : s; for (p = s; p < q; ++p, --q) { temp = *p; *p = *q; *q = temp; } strcpy(buff, s); } void fun_lcstr(buff, args, dumm1, dumm2) char *buff; char *args[10]; dbref dumm1, dumm2; { char *ap; ap = args[0]; strcpy(buff, ""); while (*ap) { if (isupper(*ap)) *buff++ = tolower(*ap++); else *buff++ = *ap++; } *buff++ = '\0'; /* No need to check buffer length */ } void fun_ucstr(buff, args, dumm1, dumm2) char *buff; char *args[10]; dbref dumm1, dumm2; { char *ap; ap = args[0]; strcpy(buff, ""); while (*ap) { if (islower(*ap)) *buff++ = toupper(*ap++); else *buff++ = *ap++; } *buff++ = '\0'; /* No need to check buffer length */ } void fun_words(buff, args, dumm1, dumm2) char *buff; char *args[10]; dbref dumm1, dumm2; { char *s = args[0]; int wcount = 0; while(*s && *s == ' ') s++; while(*s) { wcount++; while(*s && *s != ' ') s++; while(*s && *s == ' ') s++; } /* * There is NO WAY this number could every be longer than BUFFER_LEN. * therefore, no checking is required. */ sprintf(buff,"%d",wcount); } /* -------------------------------------------------------------------------- * Word functions: CAPSTR, ART, SUBJ, OBJ, POSS, ALPHAMAX, ALPHAMIN */ void fun_capstr(buff, args, dumm1, dumm2) char *buff; char *args[10]; dbref dumm1, dumm2; { strcpy(buff, args[0]); if (islower(*buff)) *buff = toupper(*buff); /* No need to check buffer length */ } /* checks a word and returns the appropriate article, "a" or "an" */ void fun_art(buff, args, dumm1, dumm2) char *buff; char *args[10]; dbref dumm1, dumm2; { char c = tolower(*args[0]); if (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u') strcpy(buff, "an"); else strcpy(buff, "a"); } /* utility function to find sex of object, used by SUBJ, OBJ, and POSS. * Returns 0 for none, 1 for female, 2 for male */ int find_sex(thing) dbref thing; { ATTR *a; int gender; a = atr_get(thing, "SEX"); if (!a) gender = 0; else { switch (*uncompress(a->value)) { case 'M': case 'm': gender = 2; break; case 'W': case 'w': case 'F': case 'f': gender = 1; break; default: gender = 0; } } return gender; } void fun_subj(buff, args, player, dumm1) char *buff; char *args[10]; dbref player; dbref dumm1; { dbref thing; int gender; thing = match_thing(player, args[0]); if (thing == NOTHING) { strcpy(buff, "#-1 NO MATCH"); return; } gender = find_sex(thing); switch (gender) { case 1: strcpy(buff, "she"); break; case 2: strcpy(buff, "he"); break; default: strcpy(buff, "it"); } } void fun_obj(buff, args, player, dumm1) char *buff; char *args[10]; dbref player; dbref dumm1; { dbref thing; int gender; thing = match_thing(player, args[0]); if (thing == NOTHING) { strcpy(buff, "#-1 NO MATCH"); return; } gender = find_sex(thing); switch (gender) { case 1: strcpy(buff, "her"); break; case 2: strcpy(buff, "him"); break; default: strcpy(buff, "it"); } } void fun_poss(buff, args, player, dumm1) char *buff; char *args[10]; dbref player; dbref dumm1; { dbref thing; int gender; thing = match_thing(player, args[0]); if (thing == NOTHING) { strcpy(buff, "#-1 NO MATCH"); return; } gender = find_sex(thing); switch (gender) { case 1: strcpy(buff, "her"); break; case 2: strcpy(buff, "his"); break; default: strcpy(buff, "its"); } } void fun_alphamax(buff, args, dumm1, dumm2) char *buff; char *args[10]; dbref dumm1, dumm2; { char *amax; int i = 1; if (!args[0]) { strcpy(buff, "#-1 TOO FEW ARGUMENTS"); return; } else amax = args[0]; while ((i < 10) && args[i]) { amax = (strcmp(amax, args[i]) > 0) ? amax : args[i]; i++; } sprintf(buff, "%s", amax); } void fun_alphamin(buff, args, dumm1, dumm2) char *buff; char *args[10]; dbref dumm1, dumm2; { char *amin; int i = 1; if (!args[0]) { strcpy(buff, "#-1 TOO FEW ARGUMENTS"); return; } else amin = args[0]; while ((i < 10) && args[i]) { amin = (strcmp(amin, args[i]) < 0) ? amin : args[i]; i++; } sprintf(buff, "%s", amin); } /* -------------------------------------------------------------------------- * MUSH utilities: FLAGS, NUM, RNUM, LEXITS, EXITS, LCON, CON, NEXT, MAIL, * NEARBY, TYPE, HASFLAG, LOCK, ELOCK, LOC, HOME, OWNER, NAME */ void fun_flags(buff, args, player, dumm1) char *buff; char *args[10]; dbref player; dbref dumm1; { dbref thing; thing = match_thing(player, args[0]); if (thing == NOTHING) { strcpy(buff,"#-1"); return; } /* * There is NO WAY this string could every be longer than BUFFER_LEN. * therefore, no checking is required. */ strcpy(buff, unparse_flags(thing)); } void fun_num(buff, args, privs, dumm1) char *buff; char *args[10]; dbref privs; dbref dumm1; { /* * There is NO WAY this number could every be longer than BUFFER_LEN. * therefore, no checking is required. */ sprintf(buff, "#%d", match_thing(privs, args[0])); } #ifdef DO_GLOBALS void fun_rnum(buff, args, privs, dumm1) char *buff; char *args[10]; dbref privs; dbref dumm1; { dbref place = match_thing(privs, args[0]); char *name = args[1]; dbref thing; init_match_remote(place, name, NOTYPE); match_remote(); switch (thing = match_result()) { case NOTHING: strcpy(buff, "#-1 NO MATCH"); break; case AMBIGUOUS: strcpy(buff, "#-1 AMBIGUOUS MATCH"); break; default: sprintf(buff, "#%d", thing); } } #endif /* * fun_lcon, fun_lexits, fun_con, fun_exit, fun_next, and next_exit were all * re-coded by d'mike, 7/12/91. next_con was added at this time as well. * the functions now check for several things before returning a result to the * caller. new checks : will only return the number of the exit/object if : * - you're a wizard ( of course ) * - you control the object/exit in question (you always know where your * stuff is!) * - you control the room in which the object/exit is located * - the obj/exit is not dark, and the room it's in is not dark/opaque * either. (exits are still returned in opaque rooms. I'm planning on * changing look/examine/etc. to reflect this state as well.) */ void fun_lcon(buff, args, privs, dumm1) char *buff; char *args[10]; dbref privs; dbref dumm1; { dbref it = match_thing(privs, args[0]); dbref thing; char tbuf1[BUFFER_LEN]; buff[0] = '\0'; if (it != NOTHING) { DOLIST(thing, db[it].contents) { if (Hasprivs(privs) || controls(privs, thing) || controls(privs, it) || (!Dark(thing) && !Dark(it) && !(db[it].flags & OPAQUE))) { if (buff[0] == '\0') /* * There is NO WAY this number could every be longer than BUFFER_LEN. * therefore, no checking is required. */ sprintf(buff, "#%d", thing); else { if ((strlen(buff)+15) < BUFFER_LEN) { sprintf(tbuf1, "%s #%d", buff, thing); strcpy(buff, tbuf1); } } } } } else /* * There is NO WAY this number could every be longer than BUFFER_LEN. * therefore, no checking is required. */ strcpy(buff, "#-1"); } /* fun_con is a wrapper for next_con now. */ void fun_con(buff, args, privs, dumm1) char *buff; char *args[10]; dbref privs; dbref dumm1; { dbref it = match_thing(privs, args[0]); if (it != NOTHING) /* * There is NO WAY this number could every be longer than BUFFER_LEN. * therefore, no checking is required. */ sprintf(buff, "#%d", next_con(privs, db[it].contents)); else /* * There is NO WAY this number could every be longer than BUFFER_LEN. * therefore, no checking is required. */ strcpy(buff, "#-1"); return; } /* return nect contents that is ok to see */ dbref next_con(player, this) dbref player; dbref this; { while((this !=NOTHING) && !(Hasprivs(player) || controls(player, this) || controls(player, db[this].location) || (!Dark(db[this].location) && !(db[db[this].location].flags & OPAQUE) && !Dark(this)))) { this = db[this].next; } return(this); } /* return next exit that is ok to see */ dbref next_exit(player, this) dbref player; dbref this; { while ((this != NOTHING) && !(Hasprivs(player) || controls(player, this) || controls(player, db[this].exits) || (!Dark(db[this].exits) && /* WHY is this check here.. it's useless */ !Dark(this)))) { this = db[this].next; } return(this); } void fun_lexits(buff,args, privs, dumm1) char *buff; char *args[10]; dbref privs; dbref dumm1; { dbref it = match_thing(privs, args[0]); dbref thing; char tbuf1[BUFFER_LEN]; buff[0] = '\0'; if (it != NOTHING) { DOLIST(thing,db[it].exits) { if (Hasprivs(privs) || controls(privs, thing) || controls(privs, it) || (!Dark(thing) && !Dark(it))) { if (buff[0] == '\0') /* * There is NO WAY this number could every be longer than BUFFER_LEN. * therefore, no checking is required. */ sprintf(buff,"#%d",thing); else { if ((strlen(buff)+15) < BUFFER_LEN) { sprintf(tbuf1,"%s #%d",buff,thing); strcpy(buff,tbuf1); } } } } } else /* * There is NO WAY this number could every be longer than BUFFER_LEN. * therefore, no checking is required. */ strcpy(buff,"#-1"); } /* fun_exit is really just a wrapper for next_exit now... */ void fun_exit(buff, args, privs, dumm1) char *buff; char *args[10]; dbref privs; dbref dumm1; { dbref it = match_thing(privs, args[0]); if (it != NOTHING) /* * There is NO WAY this number could every be longer than BUFFER_LEN. * therefore, no checking is required. */ sprintf(buff, "#%d", next_exit(privs, db[it].exits)); else /* * There is NO WAY this number could every be longer than BUFFER_LEN. * therefore, no checking is required. */ strcpy(buff, "#-1"); return; } void fun_next(buff, args, privs, dumm1) char *buff; char *args[10]; dbref privs; dbref dumm1; { dbref it = match_thing(privs, args[0]); if (it != NOTHING) { if (Typeof(it) != TYPE_EXIT) { /* * There is NO WAY this number could every be longer than BUFFER_LEN. * therefore, no checking is required. */ sprintf(buff, "#%d", next_con(privs, db[it].next)); return; } else { /* * There is NO WAY this number could every be longer than BUFFER_LEN. * therefore, no checking is required. */ sprintf(buff, "#%d", next_exit(privs, db[it].next)); return; } } /* * There is NO WAY this number could every be longer than BUFFER_LEN. * therefore, no checking is required. */ strcpy(buff, "#-1"); return; } #ifdef USE_MAILER void fun_mail(buff, args, player, dummy) char *buff; char *args[10]; dbref player; dbref dummy; { mdbref thing; if (thing = search_mail(player, atol(args[0]))) strcpy(buff, mdb[thing].message); else strcpy(buff, "#-1 INVALID MAIL NUMBER"); return; } #endif void fun_nearby(buff, args, privs, dumm1) char *buff; char *args[10]; dbref privs; dbref dumm1; { int n; dbref obj1 = match_thing(privs, args[0]); dbref obj2 = match_thing(privs, args[1]); if (!controls(privs, obj1) && !controls(privs, obj2) && !nearby(privs, obj1) && !nearby(privs, obj2)) { strcpy(buff, "#-1 NO OBJECTS CONTROLLED"); return; } if ((n = nearby(obj1, obj2)) == -1) { strcpy(buff, "#-1"); return; } else sprintf(buff, "%d", n); } void fun_type(buff, args, privs, dumm1) char *buff; char *args[10]; dbref privs; dbref dumm1; { dbref it = match_thing(privs, args[0]); if (it == NOTHING) { strcpy(buff, "#-1"); return; } switch (Typeof(it)) { case TYPE_PLAYER: strcpy(buff, "PLAYER"); break; case TYPE_THING: strcpy(buff, "THING"); break; case TYPE_EXIT: strcpy(buff, "EXIT"); break; case TYPE_ROOM: strcpy(buff, "ROOM"); break; default: strcpy(buff, "WEIRD OBJECT"); fprintf(stderr, "PANIC Weird object #%d (type %d)", it, Typeof(it)); } } void fun_hasflag(buff, args, privs, dumm1) char *buff; char *args[10]; dbref privs; dbref dumm1; { int f = 0; dbref it = match_thing(privs, args[0]); char *p = args[1]; if (it == NOTHING) { strcpy(buff, "#-1"); return; } f = find_flag(p, it); if (db[it].flags & f) strcpy(buff, "1"); else strcpy(buff, "0"); } void fun_lock(buff, args, privs, dumm1) char *buff; char *args[10]; dbref privs; dbref dumm1; { dbref it = match_thing(privs, args[0]); const char *s; if((it != NOTHING) && controls(privs, it)) { s = unparse_boolexp(privs, db[it].key, 1); if(strlen(s) < BUFFER_LEN) { sprintf(buff, "%s", s); return; } } /* * There is NO WAY this number could every be longer than BUFFER_LEN. * therefore, no checking is required. */ strcpy(buff, "#-1"); return; } void fun_elock(buff, args, privs, dumm1) char *buff; char *args[10]; dbref privs; dbref dumm1; { dbref it = match_thing(privs, args[0]); dbref victim = match_thing(privs, args[1]); if (it != NOTHING) { /* * We do not check for control because this can be bypassed by using * an indirect lock. * * There is NO WAY this number could every be longer than BUFFER_LEN. * therefore, no checking is required. */ sprintf(buff, "%d", eval_boolexp(victim, db[it].key, it, 0, BASICLOCK)); return; } /* * There is NO WAY this number could every be longer than BUFFER_LEN. * therefore, no checking is required. */ strcpy(buff, "#-1"); return; } void fun_loc(buff, args, privs, dumm1) char *buff; char *args[10]; dbref privs; dbref dumm1; { dbref it = match_thing(privs, args[0]); if (it != NOTHING && (controls(privs, it) || nearby(privs, it) #ifdef PLAYER_LOCATE || (Typeof(it) == TYPE_PLAYER && (db[it].flags & PLAYER_DARK) == 0) #endif )) { /* * There is NO WAY this number could every be longer than BUFFER_LEN. * therefore, no checking is required. */ sprintf(buff, "#%d", db[it].location); return; } /* * There is NO WAY this number could every be longer than BUFFER_LEN. * therefore, no checking is required. */ strcpy(buff, "#-1"); return; } void fun_zone(buff, args, privs, dumm1) char *buff; char *args[10]; dbref privs; dbref dumm1; { dbref it = match_thing(privs, args[0]); if (it == NOTHING || !controls(privs, it) || (Typeof(it) == TYPE_ROOM)) { strcpy(buff, "#-1"); return; } sprintf(buff, "#%d", db[it].zone); } void fun_home(buff, args, privs, dumm1) char *buff; char *args[10]; dbref privs; dbref dumm1; { dbref it = match_thing(privs, args[0]); if(it == NOTHING || !controls(privs, it) || (Typeof(it) == TYPE_ROOM)) { /* * There is NO WAY this number could every be longer than BUFFER_LEN. * therefore, no checking is required. */ strcpy(buff,"#-1"); return; } /* * There is NO WAY this number could every be longer than BUFFER_LEN. * therefore, no checking is required. */ sprintf(buff, "#%d", db[it].exits); } void fun_money(buff, args, privs, dumm1) char *buff; char *args[10]; dbref privs; dbref dumm1; { dbref it = match_thing(privs, args[0]); if(it == NOTHING) { /* * There is NO WAY this number could every be longer than BUFFER_LEN. * therefore, no checking is required. */ strcpy(buff,"#-1"); return; } /* * There is NO WAY this number could every be longer than BUFFER_LEN. * therefore, no checking is required. */ sprintf(buff,"%d",db[it].penn); } void fun_owner(buff, args, privs, dumm1) char *buff; char *args[10]; dbref privs; dbref dumm1; { dbref it = match_thing(privs, args[0]); if (it != NOTHING) it = db[it].owner; /* * There is NO WAY this number could every be longer than BUFFER_LEN. * therefore, no checking is required. */ sprintf(buff, "#%d", it); } void fun_name(buff, args, privs, dumm1) char *buff; char *args[10]; dbref privs; dbref dumm1; { dbref it = match_thing(privs, args[0]); if (it == NOTHING) strcpy(buff, ""); else if (Typeof(it) == TYPE_EXIT) { char *s; if(strlen(db[it].name) < BUFFER_LEN) { strcpy(buff, db[it].name); for (s = buff; *s && (*s != ';'); s++) ; *s = 0; } else buff[0] = '\0'; } else { if(strlen(db[it].name) < BUFFER_LEN) strcpy(buff, db[it].name); else buff[0] = '\0'; } } /* -------------------------------------------------------------------------- * Booleans: AND, OR, XOR, NOT */ void fun_and(buff, args, dumm1, dumm2) char *buff; char *args[10]; dbref dumm1, dumm2; { /* * There is NO WAY this number could every be longer than BUFFER_LEN. * therefore, no checking is required. */ sprintf(buff, "%d", translate(args[0]) && translate(args[1])); } void fun_or(buff, args, dumm1, dumm2) char *buff; char *args[10]; dbref dumm1, dumm2; { /* * There is NO WAY this number could every be longer than BUFFER_LEN. * therefore, no checking is required. */ sprintf(buff, "%d", translate(args[0]) || translate(args[1])); } void fun_not(buff, args, dumm1, dumm2) char *buff; char *args[10]; dbref dumm1, dumm2; { /* * There is NO WAY this number could every be longer than BUFFER_LEN. * therefore, no checking is required. */ sprintf(buff, "%d", !translate(args[0])); } void fun_xor(buff, args, dumm1, dumm2) char *buff; char *args[10]; dbref dumm1, dumm2; { /* * There is NO WAY this number could every be longer than BUFFER_LEN. * therefore, no checking is required. */ sprintf(buff, "%d", ((translate(args[0]) && !translate(args[1])) || (!translate(args[0]) && translate(args[1])))); } /* -------------------------------------------------------------------------- * SORT function and its auxiliaries */ void swap(char **p, char **q) /* swaps two pointers to strings */ { char *temp; temp = *p; *p = *q; *q = temp; } void do_sort(char *s[], int n) /* uses a transposition sort to sort an array of words */ { int i, j; /* utility */ for (i = 0; i < n; i++) for (j = i + 1; j < n; j++) if (strcmp(*(s + i), *(s + j)) > 0) swap(s + i, s + j); } void fun_sort(buff, args, dumm1, dumm2) char *buff; char *args[10]; dbref dumm1, dumm2; { int i = 0; int nargs = 0; /* find number of arguments */ while (i < 10 && (args[i++] != '\0')) nargs++; if (nargs < 1) { strcpy(buff, "#-1 TOO FEW ARGUMENTS"); return; } if (nargs == 1) { strcpy(buff, args[0]); return; } /* this case should never happen */ if (nargs > 10) { strcpy(buff, "#-1 TOO MANY ARGUMENTS"); return; } do_sort(args, nargs); /* copy the sort into buffer, checking to make sure that it doesn't */ /* overflow the buffer */ i = 0; strcpy(buff, args[i++]); while (i < nargs) { if ((strlen(buff) + strlen(args[i])) < BUFFER_LEN) sprintf(buff, "%s %s", buff, args[i++]); else { strcpy(buff, "#-1 STRING TOO LONG"); return; } } sprintf(buff, "%s%c", buff, '\0'); } /* -------------------------------------------------------------------------- * The actual function handlers */ typedef struct fun FUN; struct fun { const char *name; void (*fun) (); int nargs; }; FUN flist[] = { {"RAND", fun_rand, 1}, {"TIME", fun_time, 0}, {"LWHO", fun_lwho, 0}, {"GET", fun_get, 1}, {"XGET", fun_xget, 2}, {"MID", fun_mid, 3}, {"ADD", fun_add, 2}, {"SUB", fun_sub, 2}, {"MUL", fun_mul, 2}, {"DIV", fun_div, 2}, {"MOD", fun_mod, 2}, {"MAX", fun_max, -1}, {"MIN", fun_min, -1}, {"ALPHAMAX", fun_alphamax, -1}, {"ALPHAMIN", fun_alphamin, -1}, {"DIST2D", fun_dist2d, 4}, {"DIST3D", fun_dist3d, 6}, {"FIRST", fun_first, 1}, {"REST", fun_rest, 1}, {"FLAGS", fun_flags, 1}, {"STRLEN", fun_strlen, 1}, {"COMP", fun_comp, 2}, {"SUBJ", fun_subj, 1}, {"OBJ", fun_obj, 1}, {"POSS", fun_poss, 1}, {"V", fun_v, 1}, {"S", fun_s, 1}, {"POS", fun_pos, 2}, {"MATCH", fun_match, 2}, {"WORDPOS", fun_wordpos, 2}, {"EXTRACT", fun_extract, 3}, {"NUM", fun_num, 1}, {"CON", fun_con, 1}, {"NEXT", fun_next, 1}, {"OWNER", fun_owner, 1}, {"LOC", fun_loc, 1}, {"ZONE", fun_zone, 1}, {"EXIT", fun_exit, 1}, {"NAME", fun_name, 1}, {"AND",fun_and, 2}, {"OR", fun_or, 2}, {"NOT", fun_not, 1}, {"XOR", fun_xor, 2}, {"GT", fun_gt, 2}, {"GTE", fun_gte, 2}, {"LT", fun_lt, 2}, {"LTE", fun_lte, 2}, {"EQ", fun_eq, 2}, {"NEQ", fun_neq, 2}, {"CAT", fun_cat, 2}, {"MEMBER", fun_member, 2}, {"REMOVE", fun_remove, 2}, {"HOME", fun_home, 1}, {"MONEY", fun_money, 1}, {"FLIP", fun_flip, 1}, {"LCSTR", fun_lcstr, 1}, {"UCSTR", fun_ucstr, 1}, {"CAPSTR", fun_capstr, 1}, {"ART", fun_art, 1}, {"WORDS", fun_words, 1}, {"SORT", fun_sort, -1}, {"LSEARCH", fun_lsearch, 3}, {"LCON", fun_lcon, 1}, {"LEXITS", fun_lexits, 1}, #ifdef USE_MAILER {"MAIL", fun_mail, 1}, #endif #ifdef DO_GLOBALS {"RNUM", fun_rnum, 2}, #endif {"LNUM", fun_lnum, 1}, {"NEARBY", fun_nearby, 2}, {"TYPE", fun_type, 1}, {"HASFLAG", fun_hasflag, 2}, {"LOCK", fun_lock, 1}, {"ELOCK", fun_elock, 2}, {NULL, NULL, 0} }; void do_fun(str, buff, privs, doer) char **str; char *buff; dbref privs; dbref doer; { char *s; FUN *fp; char *args[10]; char obuff[BUFFER_LEN]; int a; for(a = 0; a < 10; a++) args[a] = NULL; /* look for buff in flist */ strcpy(obuff, buff); for (s = buff; *s; s++) *s = islower(*s) ? toupper(*s) : *s; for (fp = flist; fp->name && strcmp(fp->name, buff); fp++) ; /* if not found return all stuff up to next matching ) */ if (!fp->name) { int deep = 2; char *t = buff + strlen(obuff); strcpy(buff, obuff); *t++ = '('; while (**str && deep) switch (*t++ = *(*str)++) { case '(': deep++; break; case ')': deep--; break; } if (**str) { (*str)--; t--; } *t = 0; return; } /* now get the arguments to the function */ for (a = 0; (a < 10) && **str && (**str != ')'); a++) { if (**str == ',') (*str)++; exec(str, obuff, privs, doer, 1); if(args[a]) { #ifdef USE_NALLOC na_unalloc(glurp, (char *) args[a]); #else free((char *) args[a]); #endif #ifdef MEM_CHECK del_check("expression_args"); #endif args[a] = NULL; } #ifdef USE_NALLOC strcpy((args[a] = (char *) na_ualloc(glurp, strlen(obuff) + 1)), obuff); #else strcpy((args[a] = (char *)malloc(strlen(obuff)+1)), obuff); #endif #ifdef MEM_CHECK add_check("expression_args"); #endif } if (**str) (*str)++; if ((fp->nargs != -1) && (fp->nargs != a)) strcpy(buff, tprintf("#-1 Function (%s) only expects %d arguments", fp->name, fp->nargs)); else fp->fun(buff, args, privs, doer); for(a = 0; a < 10; a++) { if(args[a]) { #ifdef USE_NALLOC na_unalloc(glurp, (char *)args[a]); #else free((char *)args[a]); #endif #ifdef MEM_CHECK del_check("expression_args"); #endif } } } /* execute a string expression, return result in buff */ void exec(str, buff, privs, doer, coma) char **str; char *buff; dbref privs; dbref doer; int coma; { char *s, *e = buff; *buff = 0; /* eat preceding space */ for (s = *str; *s && isspace(*s); s++) ; /* parse until (, ],) or , */ for (; *s; s++) switch (*s) { case ',': /* comma in list of function arguments */ case ')': /* end of arguments */ if (!coma) goto cont; case ']': /* end of expression */ /* eat trailing space */ while ((--e >= buff) && isspace(*e)) ; e[1] = 0; *str = s; return; case '(': /* this is a function */ while ((--e >= buff) && isspace(*e)) ; e[1] = 0; *str = s + 1; /* if just ()'s by them self then it is quoted */ if (*buff) do_fun(str, buff, privs, doer); return; case '{': if (e == buff) { int deep = 1; e = buff; s++; while (deep && *s) switch (*e++ = *s++) { case '{': deep++; break; case '}': deep--; break; } if ((e > buff) && (e[-1] == '}')) e--; while ((--e >= buff) && isspace(*e)) ; e[1] = 0; *str = s; return; } else /* otherwise is a quote in middle, search for other end */ { int deep = 1; *e++ = *s++; while (deep && *s) switch (*e++ = *s++) { case '{': deep++; break; case '}': deep--; break; } s--; } break; default: cont: *e++ = *s; break; } while ((--e >= buff) && isspace(*e)) ; e[1] = 0; *str = s; return; } /* function to split up a list given a seperator */ /* note str will get hacked up */ char *parse_up(str, delimit) char **str; char delimit; { int deep = 0; char *s = *str, *os = *str; if (!*s) return (NULL); while (*s && (*s != delimit)) { if (*s++ == '{') { deep = 1; while (deep && *s) switch (*s++) { case '{': deep++; break; case '}': deep--; break; } } } if (*s) *s++ = 0; *str = s; return (os); }