/* 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);
}