/* eval.c */ /* Expression parsing module created by Lawrence Foard */ #include "os.h" #include "copyright.h" #include "config.h" #include "db.h" #include "interface.h" #include "externs.h" #include "match.h" #include <math.h> #ifdef MEM_CHECK #include "mem_check.h" #endif static dbref next_con (dbref player, dbref this); /* functions for the string expressions */ dbref match_thing (dbref player, const char *name) { init_match (player, name, NOTYPE); match_everything (); return (noisy_match_result ()); } /* -------------------------------------------------------------------------- * Utility functions: RAND, TIME */ void fun_rand (char *buff, char *args[10], dbref dumm1, dbref 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 (char *buff, dbref dumm1, dbref dumm2, char *dumm3[10]) { 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 (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 (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 (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 (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 (char *buff, char *args[10], dbref dumm1, dbref 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 (char *buff, char *args[10], dbref dumm1, dbref 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 (char *buff, char *args[10], dbref dumm1, dbref 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 (char *buff, char *args[10], dbref dumm1, dbref 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 (char *buff, char *args[10], dbref dumm1, dbref 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 (char *buff, char *args[10], dbref dumm1, dbref 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 (char *buff, char *args[10], dbref dumm1, dbref 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 (char *buff, char *args[10], dbref dumm1, dbref 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 (char *buff, char *args[10], dbref dumm1, dbref 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 (char *buff, char *args[10], dbref dumm1, dbref 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 (char *buff, char *args[10], dbref dumm1, dbref 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 (char *buff, char *args[10], dbref dumm1, dbref 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 (char *buff, char *args[10], dbref dumm1, dbref 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 (char *buff, char *args[10], dbref dumm1, dbref 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 (char *buff, char *args[10], dbref dumm1, dbref 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 (char *buff, char *args[10], dbref dumm1, dbref 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 (char *buff, char *args[10], dbref dumm1, dbref 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 (char *buff, char *args[10], dbref dumm1, dbref 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 (char *buff, char *args[10], dbref dumm1, dbref 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 (char *buff, char *args[10], dbref dumm1, dbref 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 < (int) strlen (args[0])) strcpy (buff, args[0] + l); else *buff = 0; buff[len] = 0; } void fun_comp (char *buff, char *args[10], dbref dumm1, dbref 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 (char *buff, char *args[10], dbref dumm1, dbref 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 (char *buff, char *args[10], dbref dumm1, dbref 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 (char *buff, char *args[10], dbref dumm1, dbref 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 (char *buff, char *args[10], dbref dumm1, dbref 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'; } static int translate (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 ((int)*temp2)) temp2++; if ((*temp2 == '\0') && (temp2 == arg)) return 0; if (isdigit ((int)*temp2)) return atoi (temp2); return 1; } void fun_cat (char *buff, char *args[10], dbref dumm1, dbref 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 (char *buff, char *args[10], dbref dumm1, dbref 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 (char *buff, char *args[10], dbref dumm1, dbref 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 (char *buff, char *args[10], dbref dumm1, dbref 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 (char *buff, char *args[10], dbref dumm1, dbref dumm2) { char *ap; ap = args[0]; strcpy (buff, ""); while (*ap) { if (isupper ((int)*ap)) *buff++ = tolower ((int)*ap++); else *buff++ = *ap++; } *buff++ = '\0'; /* No need to check buffer length */ } void fun_ucstr (char *buff, char *args[10], dbref dumm1, dbref dumm2) { char *ap; ap = args[0]; strcpy (buff, ""); while (*ap) { if (islower ((int)*ap)) *buff++ = toupper ((int)*ap++); else *buff++ = *ap++; } *buff++ = '\0'; /* No need to check buffer length */ } void fun_words (char *buff, char *args[10], dbref dumm1, dbref 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 (char *buff, char *args[10], dbref dumm1, dbref dumm2) { strcpy (buff, args[0]); if (islower ((int)*buff)) *buff = toupper ((int)*buff); /* No need to check buffer length */ } /* checks a word and returns the appropriate article, "a" or "an" */ void fun_art (char *buff, char *args[10], dbref dumm1, dbref dumm2) { char c = tolower ((int)*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 */ static int find_sex (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 (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 (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 (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 (char *buff, char *args[10], dbref dumm1, dbref 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 (char *buff, char *args[10], dbref dumm1, dbref 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 (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 (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 (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 (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 (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 */ static dbref next_con (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 */ static dbref next_exit (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (char *buff, char *args[10], dbref dumm1, dbref 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 (char *buff, char *args[10], dbref dumm1, dbref 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 (char *buff, char *args[10], dbref dumm1, dbref 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 (char *buff, char *args[10], dbref dumm1, dbref 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 */ static void swap (char **p, char **q) /* swaps two pointers to strings */ { char *temp; temp = *p; *p = *q; *q = temp; } static 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 (char *buff, char *args[10], dbref dumm1, dbref 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} }; static void do_fun (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 ((int)*s) ? toupper ((int)*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]) { free ((char *) args[a]); #ifdef MEM_CHECK del_check ("expression_args"); #endif args[a] = NULL; } strcpy ((args[a] = (char *) malloc (strlen (obuff) + 1)), obuff); #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]) { free ((char *) args[a]); #ifdef MEM_CHECK del_check ("expression_args"); #endif } } } /* execute a string expression, return result in buff */ void exec (char **str, char *buff, dbref privs, dbref doer, int coma) { char *s, *e = buff; *buff = 0; /* eat preceding space */ for (s = *str; *s && isspace ((int)*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 ((int)*e)); e[1] = 0; *str = s; return; case '(': /* this is a function */ while ((--e >= buff) && isspace ((int)*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 ((int)*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 ((int)*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 (char **str, int 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); }