src/funceval.c

Go to the documentation of this file.
00001 /*
00002  * funceval.c - MUX function handlers 
00003  */
00004 
00005 #include "copyright.h"
00006 #include "config.h"
00007 
00008 #include <limits.h>
00009 #include <math.h>
00010 #include <regex.h>
00011 
00012 #include "mudconf.h"
00013 #include "config.h"
00014 #include "db.h"
00015 #include "flags.h"
00016 #include "powers.h"
00017 #include "attrs.h"
00018 #include "externs.h"
00019 #include "match.h"
00020 #include "command.h"
00021 #include "functions.h"
00022 #include "misc.h"
00023 #include "alloc.h"
00024 #include "ansi.h"
00025 #include "comsys.h"
00026 
00027 #define NSUBEXP 10
00028 
00029 /*
00030  * Note: Many functions in this file have been taken, whole or in part, from
00031  * PennMUSH 1.50, and TinyMUSH 2.2, for softcode compatibility. The
00032  * maintainers of MUX would like to thank those responsible for PennMUSH 1.50
00033  * and TinyMUSH 2.2, and hope we have adequately noted in the source where
00034  * credit is due.
00035  */
00036 
00037 extern NAMETAB indiv_attraccess_nametab[];
00038 extern char *trim_space_sep(char *, char);
00039 extern char *next_token(char *, char);
00040 extern char *split_token(char **, char);
00041 extern dbref match_thing(dbref, char *);
00042 extern int countwords(char *, char);
00043 extern int check_read_perms(dbref, dbref, ATTR *, int, int, char *, char **);
00044 extern void arr2list(char **, int, char *, char **, char);
00045 extern void make_portlist(dbref, dbref, char *, char **);
00046 extern INLINE char *get_mail_message(int);
00047 extern struct channel *select_channel(char *channel);
00048 extern void do_pemit_list(dbref, char *, const char *);
00049 extern int fn_range_check(const char *, int, int, int, char *, char **);
00050 extern int delim_check(char *[], int, int, char *, char *, char **, int,
00051                                            dbref, dbref, char *[], int);
00052 extern char *upcasestr(char *s);
00053 extern void count_mail(dbref, int, int *, int *, int *);
00054 extern int list2arr(char *[], int, char *, int);
00055 extern struct comuser *select_user(struct channel *, dbref);
00056 
00057 /*
00058  * This is for functions that take an optional delimiter character 
00059  */
00060 
00061 #define varargs_preamble(xname,xnargs)                                  \
00062     if (!fn_range_check(xname, nfargs, xnargs-1, xnargs, buff, bufc))   \
00063 return;                                                 \
00064 if (!delim_check(fargs, nfargs, xnargs, &sep, buff, bufc, 0,    \
00065             player, cause, cargs, ncargs))                              \
00066 return;
00067 
00068 #define evarargs_preamble(xname,xnargs)                                 \
00069     if (!fn_range_check(xname, nfargs, xnargs-1, xnargs, buff, bufc))   \
00070 return;                                                 \
00071 if (!delim_check(fargs, nfargs, xnargs, &sep, buff, bufc, 1,    \
00072             player, cause, cargs, ncargs))                              \
00073 return;
00074 
00075 #define mvarargs_preamble(xname,xminargs,xnargs)                        \
00076     if (!fn_range_check(xname, nfargs, xminargs, xnargs, buff, bufc))   \
00077 return;                                                 \
00078 if (!delim_check(fargs, nfargs, xnargs, &sep, buff, bufc, 0,            \
00079             player, cause, cargs, ncargs))                              \
00080 return;
00081 
00082 /* Returns the dbref of the specified channel's channel object. */
00083 void fun_cobj(char *buff, char **bufc, dbref player, dbref cause,
00084                           char *fargs[], int nfargs, char *cargs[], int ncargs)
00085 {
00086         struct channel *ch;
00087         struct comuser *user;
00088         static char smbuf[SBUF_SIZE];
00089 
00090         if(!(ch = select_channel(fargs[0]))) {
00091                 safe_str("#-1 CHANNEL NOT FOUND", buff, bufc);
00092                 return;
00093         }
00094         if(!mudconf.have_comsys || (!Comm_All(player) &&
00095                                                                 (player != ch->charge_who))) {
00096                 safe_str("#-1 NO PERMISSION TO USE", buff, bufc);
00097                 return;
00098         }
00099         if(ch->chan_obj == -1) {
00100                 safe_str("#-1 NO CHANNEL OBJECT", buff, bufc);
00101                 return;
00102         }
00103         safe_tprintf_str(buff, bufc, "#%d", ch->chan_obj);
00104 
00105 }
00106 
00107 /* Lists who is on a channel. */
00108 void fun_cwho(char *buff, char **bufc, dbref player, dbref cause,
00109                           char *fargs[], int nfargs, char *cargs[], int ncargs)
00110 {
00111         struct channel *ch;
00112         struct comuser *user;
00113         int len = 0;
00114         static char smbuf[SBUF_SIZE];
00115 
00116         if(!(ch = select_channel(fargs[0]))) {
00117                 safe_str("#-1 CHANNEL NOT FOUND", buff, bufc);
00118                 return;
00119         }
00120         if(!mudconf.have_comsys || (!Comm_All(player) &&
00121                                                                 (player != ch->charge_who))) {
00122                 safe_str("#-1 NO PERMISSION TO USE", buff, bufc);
00123                 return;
00124         }
00125         for(user = ch->on_users; user; user = user->on_next) {
00126 
00127                 /*      if (Connected(user->who)) */
00128                 {
00129                         if(len) {
00130                                 sprintf(smbuf, " #%d", user->who);
00131                                 if((strlen(smbuf) + len) > (LBUF_SIZE - SBUF_SIZE)) {
00132                                         safe_str(" #-1", buff, bufc);
00133                                         return;
00134                                 }
00135                                 safe_str(smbuf, buff, bufc);
00136                                 len += strlen(smbuf);
00137                         } else {
00138                                 safe_tprintf_str(buff, bufc, "#%d", user->who);
00139                                 len = strlen(buff);
00140                         }
00141                 }
00142         }
00143 }
00144 
00145 /* Returns a list of all channels. */
00146 void fun_clist(char *buff, char **bufc, dbref player, dbref cause,
00147                            char *fargs[], int nfargs, char *cargs[], int ncargs)
00148 {
00149         struct channel *ch;
00150         struct comuser *user;
00151         int thing;
00152         int len = 0;
00153 
00154         static char smbuf[SBUF_SIZE];
00155 
00156         if(!(ch = select_channel(fargs[0]))) {
00157                 safe_str("#-1 CHANNEL NOT FOUND", buff, bufc);
00158                 return;
00159         }
00160         if(!mudconf.have_comsys || (!Comm_All(player) &&
00161                                                                 (player != ch->charge_who))) {
00162                 safe_str("#-1 NO PERMISSION TO USE", buff, bufc);
00163                 return;
00164         }
00165 
00166         for(ch = (struct channel *) hash_firstentry(&mudstate.channel_htab);
00167                 ch; ch = (struct channel *) hash_nextentry(&mudstate.channel_htab)) {
00168                 safe_tprintf_str(buff, bufc, "%s ", ch->name);
00169                 }
00170 
00171 
00172 
00173 
00174 
00175 
00176 
00177 
00178 
00179 
00180 
00181 
00182 
00183 
00184 
00185 
00186 
00187 
00188 
00189 
00190 
00191 
00192 }
00193 
00194 void fun_beep(char *buff, char **bufc, dbref player, dbref cause,
00195                           char *fargs[], int nfargs, char *cargs[], int ncargs)
00196 {
00197         safe_chr(BEEP_CHAR, buff, bufc);
00198 }
00199 
00200 /*
00201  * This function was originally taken from PennMUSH 1.50 
00202  */
00203 
00204 void fun_ansi(char *buff, char **bufc, dbref player, dbref cause,
00205                           char *fargs[], int nfargs, char *cargs[], int ncargs)
00206 {
00207         char *s = fargs[0];
00208 
00209         while (*s) {
00210                 switch (*s) {
00211                 case 'h':                               /*
00212                                                                  * hilite 
00213                                                                  */
00214                         safe_str(ANSI_HILITE, buff, bufc);
00215                         break;
00216                 case 'i':                               /*
00217                                                                  * inverse 
00218                                                                  */
00219                         safe_str(ANSI_INVERSE, buff, bufc);
00220                         break;
00221                 case 'f':                               /*
00222                                                                  * flash 
00223                                                                  */
00224                         safe_str(ANSI_BLINK, buff, bufc);
00225                         break;
00226                 case 'u':                               /* underline */
00227                         safe_str(ANSI_UNDER, buff, bufc);
00228                         break;
00229                 case 'n':                               /*
00230                                                                  * normal 
00231                                                                  */
00232                         safe_str(ANSI_NORMAL, buff, bufc);
00233                         break;
00234                 case 'x':                               /*
00235                                                                  * black fg 
00236                                                                  */
00237                         safe_str(ANSI_BLACK, buff, bufc);
00238                         break;
00239                 case 'r':                               /*
00240                                                                  * red fg 
00241                                                                  */
00242                         safe_str(ANSI_RED, buff, bufc);
00243                         break;
00244                 case 'g':                               /*
00245                                                                  * green fg 
00246                                                                  */
00247                         safe_str(ANSI_GREEN, buff, bufc);
00248                         break;
00249                 case 'y':                               /*
00250                                                                  * yellow fg 
00251                                                                  */
00252                         safe_str(ANSI_YELLOW, buff, bufc);
00253                         break;
00254                 case 'b':                               /*
00255                                                                  * blue fg 
00256                                                                  */
00257                         safe_str(ANSI_BLUE, buff, bufc);
00258                         break;
00259                 case 'm':                               /*
00260                                                                  * magenta fg 
00261                                                                  */
00262                         safe_str(ANSI_MAGENTA, buff, bufc);
00263                         break;
00264                 case 'c':                               /*
00265                                                                  * cyan fg 
00266                                                                  */
00267                         safe_str(ANSI_CYAN, buff, bufc);
00268                         break;
00269                 case 'w':                               /*
00270                                                                  * white fg 
00271                                                                  */
00272                         safe_str(ANSI_WHITE, buff, bufc);
00273                         break;
00274                 case 'X':                               /*
00275                                                                  * black bg 
00276                                                                  */
00277                         safe_str(ANSI_BBLACK, buff, bufc);
00278                         break;
00279                 case 'R':                               /*
00280                                                                  * red bg 
00281                                                                  */
00282                         safe_str(ANSI_BRED, buff, bufc);
00283                         break;
00284                 case 'G':                               /*
00285                                                                  * green bg 
00286                                                                  */
00287                         safe_str(ANSI_BGREEN, buff, bufc);
00288                         break;
00289                 case 'Y':                               /*
00290                                                                  * yellow bg 
00291                                                                  */
00292                         safe_str(ANSI_BYELLOW, buff, bufc);
00293                         break;
00294                 case 'B':                               /*
00295                                                                  * blue bg 
00296                                                                  */
00297                         safe_str(ANSI_BBLUE, buff, bufc);
00298                         break;
00299                 case 'M':                               /*
00300                                                                  * magenta bg 
00301                                                                  */
00302                         safe_str(ANSI_BMAGENTA, buff, bufc);
00303                         break;
00304                 case 'C':                               /*
00305                                                                  * cyan bg 
00306                                                                  */
00307                         safe_str(ANSI_BCYAN, buff, bufc);
00308                         break;
00309                 case 'W':                               /*
00310                                                                  * white bg 
00311                                                                  */
00312                         safe_str(ANSI_BWHITE, buff, bufc);
00313                         break;
00314                 }
00315                 s++;
00316         }
00317         safe_str(fargs[1], buff, bufc);
00318         safe_str(ANSI_NORMAL, buff, bufc);
00319 }
00320 
00321 void fun_zone(char *buff, char **bufc, dbref player, dbref cause,
00322                           char *fargs[], int nfargs, char *cargs[], int ncargs)
00323 {
00324         dbref it;
00325 
00326         if(!mudconf.have_zones) {
00327                 return;
00328         }
00329         it = match_thing(player, fargs[0]);
00330         if(it == NOTHING || !Examinable(player, it)) {
00331                 safe_str("#-1", buff, bufc);
00332                 return;
00333         }
00334         safe_tprintf_str(buff, bufc, "#%d", Zone(it));
00335 }
00336 
00337 #ifdef SIDE_EFFECT_FUNCTIONS
00338 
00339 void fun_link(char *buff, char **bufc, dbref player, dbref cause,
00340                           char *fargs[], int nfargs, char *cargs[], int ncargs)
00341 {
00342         do_link(player, cause, 0, fargs[0], fargs[1]);
00343 }
00344 
00345 void fun_tel(char *buff, char **bufc, dbref player, dbref cause,
00346                          char *fargs[], int nfargs, char *cargs[], int ncargs)
00347 {
00348         do_teleport(player, cause, 0, fargs[0], fargs[1]);
00349 }
00350 
00351 void fun_pemit(char *buff, char **bufc, dbref player, dbref cause,
00352                            char *fargs[], int nfargs, char *cargs[], int ncargs)
00353 {
00354         do_pemit_list(player, fargs[0], fargs[1]);
00355 }
00356 
00357 /*------------------------------------------------------------------------
00358  * fun_create: Creates a room, thing or exit
00359  */
00360 
00361 static int check_command(player, name, buff, bufc)
00362          dbref player;
00363          char *name, *buff, **bufc;
00364 {
00365         CMDENT *cmd;
00366 
00367         if((cmd = (CMDENT *) hashfind(name, &mudstate.command_htab)))
00368                 if(!check_access(player, cmd->perms)) {
00369                         safe_str("#-1 PERMISSION DENIED", buff, bufc);
00370                         return (1);
00371                 }
00372         return (0);
00373 }
00374 
00375 void fun_create(char *buff, char **bufc, dbref player, dbref cause,
00376                                 char *fargs[], int nfargs, char *cargs[], int ncargs)
00377 {
00378         dbref thing;
00379         int cost;
00380         char sep, *name;
00381 
00382         varargs_preamble("CREATE", 3);
00383         name = fargs[0];
00384 
00385         if(!name || !*name) {
00386                 safe_str("#-1 ILLEGAL NAME", buff, bufc);
00387                 return;
00388         }
00389         if(fargs[2] && *fargs[2])
00390                 sep = *fargs[2];
00391         else
00392                 sep = 't';
00393 
00394         switch (sep) {
00395         case 'r':
00396                 if(check_command(player, "@dig", buff, bufc)) {
00397                         safe_str("#-1 PERMISSION DENIED", buff, bufc);
00398                         return;
00399                 }
00400                 thing = create_obj(player, TYPE_ROOM, name, 0);
00401                 break;
00402         case 'e':
00403                 if(check_command(player, "@open", buff, bufc)) {
00404                         safe_str("#-1 PERMISSION DENIED", buff, bufc);
00405                         return;
00406                 }
00407                 thing = create_obj(player, TYPE_EXIT, name, 0);
00408                 if(thing != NOTHING) {
00409                         s_Exits(thing, player);
00410                         s_Next(thing, Exits(player));
00411                         s_Exits(player, thing);
00412                 }
00413                 break;
00414         default:
00415                 if(check_command(player, "@create", buff, bufc)) {
00416                         safe_str("#-1 PERMISSION DENIED", buff, bufc);
00417                         return;
00418                 }
00419                 if(fargs[1] && *fargs[1]) {
00420                         cost = atoi(fargs[1]);
00421                         if(cost < mudconf.createmin || cost > mudconf.createmax) {
00422                                 safe_str("#-1 COST OUT OF RANGE", buff, bufc);
00423                                 return;
00424                         }
00425                 } else
00426                         cost = mudconf.createmin;
00427                 thing = create_obj(player, TYPE_THING, name, cost);
00428                 if(thing != NOTHING) {
00429                         move_via_generic(thing, player, NOTHING, 0);
00430                         s_Home(thing, new_home(player));
00431                 }
00432                 break;
00433         }
00434         safe_tprintf_str(buff, bufc, "#%d", thing);
00435 }
00436 
00437 /*---------------------------------------------------------------------------
00438  * fun_set: sets an attribute on an object
00439  */
00440 
00441 static void set_attr_internal(dbref player, dbref thing, int attrnum,
00442                                                           char *attrtext, int key, char *buff,
00443                                                           char **bufc)
00444 {
00445         dbref aowner;
00446         int aflags, could_hear;
00447         ATTR *attr;
00448 
00449         attr = atr_num(attrnum);
00450         atr_pget_info(thing, attrnum, &aowner, &aflags);
00451         if(attr && Set_attr(player, thing, attr, aflags)) {
00452                 if((attr->check != NULL) &&
00453                    (!(*attr->check) (0, player, thing, attrnum, attrtext))) {
00454                         safe_str("#-1 PERMISSION DENIED", buff, bufc);
00455                         return;
00456                 }
00457                 could_hear = Hearer(thing);
00458                 atr_add(thing, attrnum, attrtext, Owner(player), aflags);
00459                 handle_ears(thing, could_hear, Hearer(thing));
00460                 if(!(key & SET_QUIET) && !Quiet(player) && !Quiet(thing))
00461                         notify_quiet(player, "Set.");
00462         } else {
00463                 safe_str("#-1 PERMISSION DENIED.", buff, bufc);
00464         }
00465 }
00466 
00467 void fun_set(char *buff, char **bufc, dbref player, dbref cause,
00468                          char *fargs[], int nfargs, char *cargs[], int ncargs)
00469 {
00470         dbref thing, thing2, aowner;
00471         char *p, *buff2;
00472         int atr, atr2, aflags, clear, flagvalue, could_hear;
00473         ATTR *attr, *attr2;
00474 
00475         /*
00476          * obj/attr form? 
00477          */
00478 
00479         if(parse_attrib(player, fargs[0], &thing, &atr)) {
00480                 if(atr != NOTHING) {
00481 
00482                         /*
00483                          * must specify flag name 
00484                          */
00485 
00486                         if(!fargs[1] || !*fargs[1]) {
00487 
00488                                 safe_str("#-1 UNSPECIFIED PARAMETER", buff, bufc);
00489                         }
00490                         /*
00491                          * are we clearing? 
00492                          */
00493 
00494                         clear = 0;
00495                         if(*fargs[0] == NOT_TOKEN) {
00496                                 fargs[0]++;
00497                                 clear = 1;
00498                         }
00499                         /*
00500                          * valid attribute flag? 
00501                          */
00502 
00503                         flagvalue =
00504                                 search_nametab(player, indiv_attraccess_nametab, fargs[1]);
00505                         if(flagvalue < 0) {
00506                                 safe_str("#-1 CAN NOT SET", buff, bufc);
00507                                 return;
00508                         }
00509                         /*
00510                          * make sure attribute is present 
00511                          */
00512 
00513                         if(!atr_get_info(thing, atr, &aowner, &aflags)) {
00514                                 safe_str("#-1 ATTRIBUTE NOT PRESENT ON OBJECT", buff, bufc);
00515                                 return;
00516                         }
00517                         /*
00518                          * can we write to attribute? 
00519                          */
00520 
00521                         attr = atr_num(atr);
00522                         if(!attr || !Set_attr(player, thing, attr, aflags)) {
00523                                 safe_str("#-1 PERMISSION DENIED", buff, bufc);
00524                                 return;
00525                         }
00526                         /*
00527                          * just do it! 
00528                          */
00529 
00530                         if(clear)
00531                                 aflags &= ~flagvalue;
00532                         else
00533                                 aflags |= flagvalue;
00534                         could_hear = Hearer(thing);
00535                         atr_set_flags(thing, atr, aflags);
00536 
00537                         return;
00538                 }
00539         }
00540         /*
00541          * find thing 
00542          */
00543 
00544         if((thing = match_controlled(player, fargs[0])) == NOTHING) {
00545                 safe_str("#-1", buff, bufc);
00546                 return;
00547         }
00548         /*
00549          * check for attr set first 
00550          */
00551         for(p = fargs[1]; *p && (*p != ':'); p++);
00552 
00553         if(*p) {
00554                 *p++ = 0;
00555                 atr = mkattr(fargs[1]);
00556                 if(atr <= 0) {
00557                         safe_str("#-1 UNABLE TO CREATE ATTRIBUTE", buff, bufc);
00558                         return;
00559                 }
00560                 attr = atr_num(atr);
00561                 if(!attr) {
00562                         safe_str("#-1 PERMISSION DENIED", buff, bufc);
00563                         return;
00564                 }
00565                 atr_get_info(thing, atr, &aowner, &aflags);
00566                 if(!Set_attr(player, thing, attr, aflags)) {
00567                         safe_str("#-1 PERMISSION DENIED", buff, bufc);
00568                         return;
00569                 }
00570                 buff2 = alloc_lbuf("fun_set");
00571 
00572                 /*
00573                  * check for _ 
00574                  */
00575                 if(*p == '_') {
00576                         StringCopy(buff2, p + 1);
00577                         if(!parse_attrib(player, p + 1, &thing2, &atr2) ||
00578                            (atr == NOTHING)) {
00579                                 free_lbuf(buff2);
00580                                 safe_str("#-1 NO MATCH", buff, bufc);
00581                                 return;
00582                         }
00583                         attr2 = atr_num(atr);
00584                         p = buff2;
00585                         atr_pget_str(buff2, thing2, atr2, &aowner, &aflags);
00586 
00587                         if(!attr2 || !See_attr(player, thing2, attr2, aowner, aflags)) {
00588                                 free_lbuf(buff2);
00589                                 safe_str("#-1 PERMISSION DENIED", buff, bufc);
00590                                 return;
00591                         }
00592                 }
00593                 /*
00594                  * set it 
00595                  */
00596 
00597                 set_attr_internal(player, thing, atr, p, 0, buff, bufc);
00598                 free_lbuf(buff2);
00599                 return;
00600         }
00601         /*
00602          * set/clear a flag 
00603          */
00604         flag_set(thing, player, fargs[1], 0);
00605 }
00606 #endif
00607 
00608 /*
00609  * Code for encrypt() and decrypt() was taken from the DarkZone server 
00610  */
00611 
00612 /*
00613  * Copy over only alphanumeric chars 
00614  */
00615 static char *crunch_code(char *code)
00616 {
00617         char *in;
00618         char *out;
00619         static char output[LBUF_SIZE];
00620 
00621         out = output;
00622         in = code;
00623         while (*in) {
00624                 if((*in >= 32) || (*in <= 126)) {
00625                         printf("%c", *in);
00626                         *out++ = *in;
00627                 }
00628                 in++;
00629         }
00630         *out = '\0';
00631         return (output);
00632 }
00633 
00634 static char *crypt_code(char *code, char *text, int type)
00635 {
00636         static char textbuff[LBUF_SIZE];
00637         char codebuff[LBUF_SIZE];
00638         int start = 32;
00639         int end = 126;
00640         int mod = end - start + 1;
00641         char *p, *q, *r;
00642 
00643         if(!text && !*text)
00644                 return ((char *) "");
00645         StringCopy(codebuff, crunch_code(code));
00646         if(!code || !*code || !codebuff || !*codebuff)
00647                 return (text);
00648         StringCopy(textbuff, "");
00649 
00650         p = text;
00651         q = codebuff;
00652         r = textbuff;
00653         /*
00654          * Encryption: Simply go through each character of the text, get its
00655          * * * * ascii value, subtract start, add the ascii value (less
00656          * start) * of * * the code, mod the result, add start. Continue  
00657          */
00658         while (*p) {
00659                 if((*p < start) || (*p > end)) {
00660                         p++;
00661                         continue;
00662                 }
00663                 if(type)
00664                         *r++ = (((*p++ - start) + (*q++ - start)) % mod) + start;
00665                 else
00666                         *r++ = (((*p++ - *q++) + 2 * mod) % mod) + start;
00667                 if(!*q)
00668                         q = codebuff;
00669         }
00670         *r = '\0';
00671         return (textbuff);
00672 }
00673 
00674 /*
00675  * Borrowed from DarkZone 
00676  */
00677 void fun_zwho(char *buff, char **bufc, dbref player, dbref cause,
00678                           char *fargs[], int nfargs, char *cargs[], int ncargs)
00679 {
00680         dbref it = match_thing(player, fargs[0]);
00681         dbref i;
00682         int len = 0;
00683 
00684         if(!mudconf.have_zones || (!Controls(player, it) && !WizRoy(player))) {
00685                 safe_str("#-1 NO PERMISSION TO USE", buff, bufc);
00686                 return;
00687         }
00688         for(i = 0; i < mudstate.db_top; i++)
00689                 if(Typeof(i) == TYPE_PLAYER) {
00690                         if(Zone(i) == it) {
00691                                 if(len) {
00692                                         static char smbuf[SBUF_SIZE];
00693 
00694                                         sprintf(smbuf, " #%d", i);
00695                                         if((strlen(smbuf) + len) > (LBUF_SIZE - SBUF_SIZE)) {
00696                                                 safe_str(" #-1", buff, bufc);
00697                                                 return;
00698                                         }
00699                                         safe_str(smbuf, buff, bufc);
00700                                         len += strlen(smbuf);
00701                                 } else {
00702                                         safe_tprintf_str(buff, bufc, "#%d", i);
00703                                         len = strlen(buff);
00704                                 }
00705                         }
00706                 }
00707 }
00708 
00709 void fun_zplayers(char *buff, char **bufc, dbref player, dbref cause,
00710                                   char *fargs[], int nfargs, char *cargs[], int ncargs)
00711 {
00712         dbref it = match_thing(player, fargs[0]);
00713         dbref i;
00714         int len = 0;
00715 
00716         if(!mudconf.have_zones || (!Controls(player, it) && !WizRoy(player))) {
00717                 safe_str("#-1 NO PERMISSION TO USE", buff, bufc);
00718                 return;
00719         }
00720         for(i = 0; i < mudstate.db_top; i++)
00721                 if(Typeof(i) == TYPE_PLAYER)
00722                         if(Zone(i) == it) {
00723                                 if(!(Connected(i)))
00724                                         continue;
00725                                 if(len) {
00726                                         static char smbuf[SBUF_SIZE];
00727 
00728                                         sprintf(smbuf, " #%d", i);
00729                                         if((strlen(smbuf) + len) > (LBUF_SIZE - SBUF_SIZE)) {
00730                                                 safe_str(" #-1", buff, bufc);
00731                                                 return;
00732                                         }
00733                                         safe_str(smbuf, buff, bufc);
00734                                         len += strlen(smbuf);
00735                                 } else {
00736                                         safe_tprintf_str(buff, bufc, "#%d", i);
00737                                         len = strlen(buff);
00738                                 }
00739                         }
00740 }
00741 
00742 /*
00743  * Borrowed from DarkZone 
00744  */
00745 void fun_inzone(char *buff, char **bufc, dbref player, dbref cause,
00746                                 char *fargs[], int nfargs, char *cargs[], int ncargs)
00747 {
00748         dbref it = match_thing(player, fargs[0]);
00749         dbref i;
00750         int len = 0;
00751 
00752         if(!mudconf.have_zones || !(Controls(player, it) || !WizRoy(player))) {
00753                 safe_str("#-1 NO PERMISSION TO USE", buff, bufc);
00754                 return;
00755         }
00756         for(i = 0; i < mudstate.db_top; i++)
00757                 if(Typeof(i) == TYPE_ROOM)
00758                         if(db[i].zone == it) {
00759                                 if(len) {
00760                                         static char smbuf[SBUF_SIZE];
00761 
00762                                         sprintf(smbuf, " #%d", i);
00763                                         if((strlen(smbuf) + len) > (LBUF_SIZE - SBUF_SIZE)) {
00764                                                 safe_str(" #-1", buff, bufc);
00765                                                 return;
00766                                         }
00767                                         safe_str(smbuf, buff, bufc);
00768                                         len += strlen(smbuf);
00769                                 } else {
00770                                         safe_tprintf_str(buff, bufc, "#%d", i);
00771                                         len = strlen(buff);
00772                                 }
00773                         }
00774 }
00775 
00776 /*
00777  * Borrowed from DarkZone 
00778  */
00779 void fun_children(char *buff, char **bufc, dbref player, dbref cause,
00780                                   char *fargs[], int nfargs, char *cargs[], int ncargs)
00781 {
00782         dbref it = match_thing(player, fargs[0]);
00783         dbref i;
00784         int len = 0;
00785 
00786         if(!(Controls(player, it)) || !(WizRoy(player))) {
00787                 safe_str("#-1 NO PERMISSION TO USE", buff, bufc);
00788                 return;
00789         }
00790         for(i = 0; i < mudstate.db_top; i++)
00791                 if(Parent(i) == it) {
00792                         if(len) {
00793                                 static char smbuf[SBUF_SIZE];
00794 
00795                                 sprintf(smbuf, " #%d", i);
00796                                 if((strlen(smbuf) + len) > (LBUF_SIZE - SBUF_SIZE)) {
00797                                         safe_str(" #-1", buff, bufc);
00798                                         return;
00799                                 }
00800                                 safe_str(smbuf, buff, bufc);
00801                                 len += strlen(smbuf);
00802                         } else {
00803                                 safe_tprintf_str(buff, bufc, "#%d", i);
00804                                 len = strlen(buff);
00805                         }
00806                 }
00807 }
00808 
00809 void fun_encrypt(char *buff, char **bufc, dbref player, dbref cause,
00810                                  char *fargs[], int nfargs, char *cargs[], int ncargs)
00811 {
00812         safe_str(crypt_code(fargs[1], fargs[0], 1), buff, bufc);
00813 }
00814 
00815 void fun_decrypt(char *buff, char **bufc, dbref player, dbref cause,
00816                                  char *fargs[], int nfargs, char *cargs[], int ncargs)
00817 {
00818         safe_str(crypt_code(fargs[1], fargs[0], 0), buff, bufc);
00819 }
00820 
00821 #if 0                                                   /* Currently not used. */
00822 static void noquotes(clean, dirty)
00823          char *clean;
00824          char *dirty;
00825 {
00826         while (*dirty != '\0') {
00827                 if(*dirty == '"')
00828                         *clean++ = '\\';
00829                 *clean++ = *dirty++;
00830         }
00831         *clean = '\0';
00832 }
00833 #endif
00834 
00835 void fun_objeval(char *buff, char **bufc, dbref player, dbref cause,
00836                                  char *fargs[], int nfargs, char *cargs[], int ncargs)
00837 {
00838         dbref obj;
00839         char *name, *bp, *str;
00840 
00841         if(!*fargs[0]) {
00842                 return;
00843         }
00844         name = bp = alloc_lbuf("fun_objeval");
00845         str = fargs[0];
00846         exec(name, &bp, 0, player, cause, EV_FCHECK | EV_STRIP | EV_EVAL, &str,
00847                  cargs, ncargs);
00848         *bp = '\0';
00849         obj = match_thing(player, name);
00850 
00851         if((obj == NOTHING) || ((Owner(obj) != player) && (!(Wizard(player))))
00852            || (obj == GOD))
00853                 obj = player;
00854 
00855         str = fargs[1];
00856         exec(buff, bufc, 0, obj, obj, EV_FCHECK | EV_STRIP | EV_EVAL, &str,
00857                  cargs, ncargs);
00858         free_lbuf(name);
00859 }
00860 
00861 void fun_squish(char *buff, char **bufc, dbref player, dbref cause,
00862                                 char *fargs[], int nfargs, char *cargs[], int ncargs)
00863 {
00864         char *p, *q, *bp;
00865         bp = alloc_lbuf("fun_squish");
00866         StringCopy(bp, fargs[0]);
00867         p = q = bp;
00868         while (*p) {
00869                 while (*p && (*p != ' '))
00870                         *q++ = *p++;
00871                 while (*p && (*p == ' '))
00872                         p++;
00873                 if(*p)
00874                         *q++ = ' ';
00875         }
00876         *q = '\0';
00877 
00878         safe_str(bp, buff, bufc);
00879         free_lbuf(bp);
00880 }
00881 
00882 void fun_stripansi(char *buff, char **bufc, dbref player, dbref cause,
00883                                    char *fargs[], int nfargs, char *cargs[], int ncargs)
00884 {
00885         char new[LBUF_SIZE];
00886 
00887         strncpy(new, fargs[0], LBUF_SIZE-1);
00888         safe_str((char *) strip_ansi_r(new,fargs[0],strlen(fargs[0])), buff, bufc);
00889 }
00890 
00891 /*
00892  * Borrowed from PennMUSH 1.50 
00893  */
00894 void fun_zfun(char *buff, char **bufc, dbref player, dbref cause,
00895                           char *fargs[], int nfargs, char *cargs[], int ncargs)
00896 {
00897         dbref aowner;
00898         int aflags;
00899         int attrib;
00900         char *tbuf1, *str;
00901 
00902         dbref zone = Zone(player);
00903 
00904         if(!mudconf.have_zones) {
00905                 safe_str("#-1 ZONES DISABLED", buff, bufc);
00906                 return;
00907         }
00908         if(zone == NOTHING) {
00909                 safe_str("#-1 INVALID ZONE", buff, bufc);
00910                 return;
00911         }
00912         if(!fargs[0] || !*fargs[0])
00913                 return;
00914 
00915         /*
00916          * find the user function attribute 
00917          */
00918         attrib = get_atr(upcasestr(fargs[0]));
00919         if(!attrib) {
00920                 safe_str("#-1 NO SUCH USER FUNCTION", buff, bufc);
00921                 return;
00922         }
00923         tbuf1 = atr_pget(zone, attrib, &aowner, &aflags);
00924         if(!See_attr(player, zone, (ATTR *) atr_num(attrib), aowner, aflags)) {
00925                 safe_str("#-1 NO PERMISSION TO GET ATTRIBUTE", buff, bufc);
00926                 free_lbuf(tbuf1);
00927                 return;
00928         }
00929         str = tbuf1;
00930         exec(buff, bufc, 0, zone, player, EV_EVAL | EV_STRIP | EV_FCHECK, &str,
00931                  &(fargs[1]), nfargs - 1);
00932         free_lbuf(tbuf1);
00933 }
00934 
00935 void fun_columns(char *buff, char **bufc, dbref player, dbref cause,
00936                                  char *fargs[], int nfargs, char *cargs[], int ncargs)
00937 {
00938         int spaces, number, ansinumber, count, i;
00939         static char buf[LBUF_SIZE];
00940         char *p, *q;
00941         int isansi = 0, rturn = 1;
00942         char *curr, *objstring, *bp, *cp, sep, *str;
00943         char new[MBUF_SIZE];
00944 
00945         evarargs_preamble("COLUMNS", 3);
00946 
00947         number = atoi(fargs[1]);
00948         if((number < 1) || (number > 78)) {
00949                 safe_str("#-1 OUT OF RANGE", buff, bufc);
00950                 return;
00951         }
00952         cp = curr = bp = alloc_lbuf("fun_columns");
00953         str = fargs[0];
00954         exec(curr, &bp, 0, player, cause, EV_STRIP | EV_FCHECK | EV_EVAL, &str,
00955                  cargs, ncargs);
00956         *bp = '\0';
00957         cp = trim_space_sep(cp, sep);
00958         if(!*cp) {
00959                 free_lbuf(curr);
00960                 return;
00961         }
00962         safe_chr(' ', buff, bufc);
00963 
00964         while (cp) {
00965                 objstring = split_token(&cp, sep);
00966                 strncpy(new, objstring, MBUF_SIZE-1);
00967                 ansinumber = number;
00968                 if(ansinumber > strlen((char *) strip_ansi_r(new,objstring,strlen(objstring))))
00969                         ansinumber = strlen((char *) strip_ansi_r(new,objstring,strlen(objstring)));
00970 
00971                 p = objstring;
00972                 q = buf;
00973                 count = 0;
00974                 while (p && *p) {
00975                         if(count == number) {
00976                                 break;
00977                         }
00978                         if(*p == ESC_CHAR) {
00979                                 /*
00980                                  * Start of ANSI code. Skip to end. 
00981                                  */
00982                                 isansi = 1;
00983                                 while (*p && !isalpha(*p))
00984                                         *q++ = *p++;
00985                                 if(*p)
00986                                         *q++ = *p++;
00987                         } else {
00988                                 *q++ = *p++;
00989                                 count++;
00990                         }
00991                 }
00992                 if(isansi)
00993                         safe_str(ANSI_NORMAL, buf, &q);
00994                 *q = '\0';
00995                 isansi = 0;
00996 
00997                 spaces = number - strlen((char *) strip_ansi_r(new,objstring,strlen(objstring)));
00998 
00999                 /*
01000                  * Sanitize number of spaces 
01001                  */
01002 
01003                 if(spaces > LBUF_SIZE) {
01004                         spaces = LBUF_SIZE;
01005                 }
01006                 safe_str(buf, buff, bufc);
01007                 for(i = 0; i < spaces; i++)
01008                         safe_chr(' ', buff, bufc);
01009 
01010                 if(!(rturn % (int) (78 / number)))
01011                         safe_str((char *) "\r\n ", buff, bufc);
01012 
01013                 rturn++;
01014         }
01015         free_lbuf(curr);
01016 }
01017 
01018 /*
01019  * Code for objmem and playmem borrowed from PennMUSH 1.50 
01020  */
01021 static int mem_usage(dbref thing)
01022 {
01023         int k;
01024         int ca;
01025         char *as, *str;
01026         ATTR *attr;
01027 
01028         k = sizeof(struct object);
01029 
01030         k += strlen(Name(thing)) + 1;
01031         for(ca = atr_head(thing, &as); ca; ca = atr_next(&as)) {
01032                 str = atr_get_raw(thing, ca);
01033                 if(str && *str)
01034                         k += strlen(str);
01035                 attr = atr_num(ca);
01036                 if(attr) {
01037                         str = (char *) attr->name;
01038                         if(str && *str)
01039                                 k += strlen(((ATTR *) atr_num(ca))->name);
01040                 }
01041         }
01042         return k;
01043 }
01044 
01045 void fun_objmem(char *buff, char **bufc, dbref player, dbref cause,
01046                                 char *fargs[], int nfargs, char *cargs[], int ncargs)
01047 {
01048         dbref thing;
01049 
01050         thing = match_thing(player, fargs[0]);
01051         if(thing == NOTHING || !Examinable(player, thing)) {
01052                 safe_str("#-1 PERMISSION DENIED", buff, bufc);
01053                 return;
01054         }
01055         safe_tprintf_str(buff, bufc, "%d", mem_usage(thing));
01056 }
01057 
01058 void fun_playmem(char *buff, char **bufc, dbref player, dbref cause,
01059                                  char *fargs[], int nfargs, char *cargs[], int ncargs)
01060 {
01061         int tot = 0;
01062         dbref thing;
01063         dbref j;
01064 
01065         thing = match_thing(player, fargs[0]);
01066         if(thing == NOTHING || !Examinable(player, thing)) {
01067                 safe_str("#-1 PERMISSION DENIED", buff, bufc);
01068                 return;
01069         }
01070         DO_WHOLE_DB(j)
01071                 if(Owner(j) == thing)
01072                 tot += mem_usage(j);
01073         safe_tprintf_str(buff, bufc, "%d", tot);
01074 }
01075 
01076 /*
01077  * Code for andflags() and orflags() borrowed from PennMUSH 1.50.
01078  * type = 0 for orflags, 1 for andflags. 
01079  */
01080 static int handle_flaglists(dbref player, char *name, char *fstr, int type)
01081 {
01082         char *s;
01083         char flagletter[2];
01084         FLAGSET fset;
01085         FLAG p_type;
01086         int negate, temp;
01087         int ret = type;
01088         dbref it = match_thing(player, name);
01089 
01090         negate = temp = 0;
01091 
01092         if(it == NOTHING)
01093                 return 0;
01094 
01095         for(s = fstr; *s; s++) {
01096 
01097                 /*
01098                  * Check for a negation sign. If we find it, we note it and 
01099                  * * * * * increment the pointer to the next character. 
01100                  */
01101 
01102                 if(*s == '!') {
01103                         negate = 1;
01104                         s++;
01105                 } else {
01106                         negate = 0;
01107                 }
01108 
01109                 if(!*s) {
01110                         return 0;
01111                 }
01112                 flagletter[0] = *s;
01113                 flagletter[1] = '\0';
01114 
01115                 if(!convert_flags(player, flagletter, &fset, &p_type)) {
01116 
01117                         /*
01118                          * Either we got a '!' that wasn't followed by a * *
01119                          * * letter, or * we couldn't find that flag. For
01120                          * AND, * * * since we've failed * a check, we can
01121                          * return * * false.  * Otherwise we just go on. 
01122                          */
01123 
01124                         if(type == 1)
01125                                 return 0;
01126                         else
01127                                 continue;
01128 
01129                 } else {
01130 
01131                         /*
01132                          * does the object have this flag? 
01133                          */
01134 
01135                         if((Flags(it) & fset.word1) || (Flags2(it) & fset.word2) ||
01136                            (Typeof(it) == p_type)) {
01137                                 if(isPlayer(it) && (fset.word2 == CONNECTED) &&
01138                                    ((Flags(it) & (WIZARD | DARK)) == (WIZARD | DARK)) &&
01139                                    !Wizard(player))
01140                                         temp = 0;
01141                                 else
01142                                         temp = 1;
01143                         } else {
01144                                 temp = 0;
01145                         }
01146 
01147                         if((type == 1) && ((negate && temp) || (!negate && !temp))) {
01148 
01149                                 /*
01150                                  * Too bad there's no NXOR function... * At * 
01151                                  * 
01152                                  * *  * * this point we've either got a flag
01153                                  * and * we * * don't want * it, or we don't
01154                                  * have a  * flag * * and we want it. Since
01155                                  * it's * AND,  * we * * return false. 
01156                                  */
01157                                 return 0;
01158 
01159                         } else if((type == 0) && ((!negate && temp) || (negate && !temp))) {
01160 
01161                                 /*
01162                                  * We've found something we want, in an OR. * 
01163                                  * 
01164                                  * *  * * We OR a * true with the current
01165                                  * value. 
01166                                  */
01167 
01168                                 ret |= 1;
01169                         }
01170                         /*
01171                          * Otherwise, we don't need to do anything. 
01172                          */
01173                 }
01174         }
01175         return (ret);
01176 }
01177 
01178 void fun_orflags(char *buff, char **bufc, dbref player, dbref cause,
01179                                  char *fargs[], int nfargs, char *cargs[], int ncargs)
01180 {
01181         safe_tprintf_str(buff, bufc, "%d", handle_flaglists(player, fargs[0],
01182                                                                                                                 fargs[1], 0));
01183 }
01184 
01185 void fun_andflags(char *buff, char **bufc, dbref player, dbref cause,
01186                                   char *fargs[], int nfargs, char *cargs[], int ncargs)
01187 {
01188         safe_tprintf_str(buff, bufc, "%d", handle_flaglists(player, fargs[0],
01189                                                                                                                 fargs[1], 1));
01190 }
01191 
01192 void fun_strtrunc(char *buff, char **bufc, dbref player, dbref cause,
01193                                   char *fargs[], int nfargs, char *cargs[], int ncargs)
01194 {
01195         int number, count = 0;
01196         static char buf[LBUF_SIZE];
01197         char *p = (char *) fargs[0];
01198         char *q = buf;
01199         int isansi = 0;
01200         char new[LBUF_SIZE];
01201         
01202         number = atoi(fargs[1]);
01203         strncpy(new, fargs[0], LBUF_SIZE-1);
01204         if(number > strlen((char *) strip_ansi_r(new,fargs[0],strlen(fargs[0]))))
01205                 number = strlen((char *) strip_ansi_r(new,fargs[0],strlen(fargs[0])));
01206 
01207         if(number < 0) {
01208                 safe_str("#-1 OUT OF RANGE", buff, bufc);
01209                 return;
01210         }
01211         while (p && *p) {
01212                 if(count == number) {
01213                         break;
01214                 }
01215                 if(*p == ESC_CHAR) {
01216                         /*
01217                          * Start of ANSI code. Skip to end. 
01218                          */
01219                         isansi = 1;
01220                         while (*p && !isalpha(*p))
01221                                 *q++ = *p++;
01222                         if(*p)
01223                                 *q++ = *p++;
01224                 } else {
01225                         *q++ = *p++;
01226                         count++;
01227                 }
01228         }
01229         if(isansi)
01230                 safe_str(ANSI_NORMAL, buf, &q);
01231         *q = '\0';
01232         safe_str(buf, buff, bufc);
01233 }
01234 
01235 void fun_ifelse(char *buff, char **bufc, dbref player, dbref cause,
01236                                 char *fargs[], int nfargs, char *cargs[], int ncargs)
01237 {
01238         /* This function now assumes that its arguments have not been
01239            evaluated. */
01240 
01241         char *str, *mbuff, *bp;
01242 
01243         mbuff = bp = alloc_lbuf("fun_ifelse");
01244         str = fargs[0];
01245         exec(mbuff, &bp, 0, player, cause, EV_STRIP | EV_FCHECK | EV_EVAL,
01246                  &str, cargs, ncargs);
01247         *bp = '\0';
01248 
01249         if(!xlate(mbuff)) {
01250                 str = fargs[2];
01251                 exec(buff, bufc, 0, player, cause, EV_STRIP | EV_FCHECK | EV_EVAL,
01252                          &str, cargs, ncargs);
01253         } else {
01254                 str = fargs[1];
01255                 exec(buff, bufc, 0, player, cause, EV_STRIP | EV_FCHECK | EV_EVAL,
01256                          &str, cargs, ncargs);
01257         }
01258         free_lbuf(mbuff);
01259 }
01260 
01261 void fun_inc(char *buff, char **bufc, dbref player, dbref cause,
01262                          char *fargs[], int nfargs, char *cargs[], int ncargs)
01263 {
01264         int number;
01265 
01266         if(!is_number(fargs[0])) {
01267                 safe_str("#-1 ARGUMENT MUST BE A NUMBER", buff, bufc);
01268                 return;
01269         }
01270         number = atoi(fargs[0]);
01271         safe_tprintf_str(buff, bufc, "%d", (++number));
01272 }
01273 
01274 void fun_dec(char *buff, char **bufc, dbref player, dbref cause,
01275                          char *fargs[], int nfargs, char *cargs[], int ncargs)
01276 {
01277         int number;
01278 
01279         if(!is_number(fargs[0])) {
01280                 safe_str("#-1 ARGUMENT MUST BE A NUMBER", buff, bufc);
01281                 return;
01282         }
01283         number = atoi(fargs[0]);
01284         safe_tprintf_str(buff, bufc, "%d", (--number));
01285 }
01286 
01287 /*
01288  * Mail functions borrowed from DarkZone 
01289  */
01290 void fun_mail(char *buff, char **bufc, dbref player, dbref cause,
01291                           char *fargs[], int nfargs, char *cargs[], int ncargs)
01292 {
01293         /*
01294          * This function can take one of three formats: 1.  mail(num)  --> *
01295          * * * returns * message <num> for privs. 2.  mail(player)  -->
01296          * returns  * *  * number of * messages for <player>. 3.
01297          * mail(player, num)  -->  * * * returns message <num> * for
01298          * <player>. 
01299          */
01300         /*
01301          * It can now take one more format: 4.  mail() --> returns number of
01302          * * * * * messages for executor 
01303          */
01304 
01305         struct mail *mp;
01306         dbref playerask;
01307         int num, rc, uc, cc;
01308 
01309         /*
01310          * make sure we have the right number of arguments 
01311          */
01312         if((nfargs != 0) && (nfargs != 1) && (nfargs != 2)) {
01313                 safe_str("#-1 FUNCTION (MAIL) EXPECTS 0 OR 1 OR 2 ARGUMENTS", buff,
01314                                  bufc);
01315                 return;
01316         }
01317         if((nfargs == 0) || !fargs[0] || !fargs[0][0]) {
01318                 count_mail(player, 0, &rc, &uc, &cc);
01319                 safe_tprintf_str(buff, bufc, "%d", rc + uc);
01320                 return;
01321         }
01322         if(nfargs == 1) {
01323                 if(!is_number(fargs[0])) {
01324                         /*
01325                          * handle the case of wanting to count the number of
01326                          * * * * messages 
01327                          */
01328                         if((playerask = lookup_player(player, fargs[0], 1)) == NOTHING) {
01329                                 safe_str("#-1 NO SUCH PLAYER", buff, bufc);
01330                                 return;
01331                         } else if((player != playerask) && !Wizard(player)) {
01332                                 safe_str("#-1 PERMISSION DENIED", buff, bufc);
01333                                 return;
01334                         } else {
01335                                 count_mail(playerask, 0, &rc, &uc, &cc);
01336                                 safe_tprintf_str(buff, bufc, "%d %d %d", rc, uc, cc);
01337                                 return;
01338                         }
01339                 } else {
01340                         playerask = player;
01341                         num = atoi(fargs[0]);
01342                 }
01343         } else {
01344                 if((playerask = lookup_player(player, fargs[0], 1)) == NOTHING) {
01345                         safe_str("#-1 NO SUCH PLAYER", buff, bufc);
01346                         return;
01347                 } else if((player != playerask) && !God(player)) {
01348                         safe_str("#-1 PERMISSION DENIED", buff, bufc);
01349                         return;
01350                 }
01351                 num = atoi(fargs[1]);
01352         }
01353 
01354         if((num < 1) || (Typeof(playerask) != TYPE_PLAYER)) {
01355                 safe_str("#-1 NO SUCH MESSAGE", buff, bufc);
01356                 return;
01357         }
01358         mp = mail_fetch(playerask, num);
01359         if(mp != NULL) {
01360                 safe_str(get_mail_message(mp->number), buff, bufc);
01361                 return;
01362         }
01363         /*
01364          * ran off the end of the list without finding anything 
01365          */
01366         safe_str("#-1 NO SUCH MESSAGE", buff, bufc);
01367 }
01368 
01369 void fun_mailfrom(char *buff, char **bufc, dbref player, dbref cause,
01370                                   char *fargs[], int nfargs, char *cargs[], int ncargs)
01371 {
01372         /*
01373          * This function can take these formats: 1) mailfrom(<num>) 2) * * *
01374          * * mailfrom(<player>,<num>) It returns the dbref of the player the
01375          * * * * mail is * from 
01376          */
01377         struct mail *mp;
01378         dbref playerask;
01379         int num;
01380 
01381         /*
01382          * make sure we have the right number of arguments 
01383          */
01384         if((nfargs != 1) && (nfargs != 2)) {
01385                 safe_str("#-1 FUNCTION (MAILFROM) EXPECTS 1 OR 2 ARGUMENTS", buff,
01386                                  bufc);
01387                 return;
01388         }
01389         if(nfargs == 1) {
01390                 playerask = player;
01391                 num = atoi(fargs[0]);
01392         } else {
01393                 if((playerask = lookup_player(player, fargs[0], 1)) == NOTHING) {
01394                         safe_str("#-1 NO SUCH PLAYER", buff, bufc);
01395                         return;
01396                 } else if((player != playerask) && !Wizard(player)) {
01397                         safe_str("#-1 PERMISSION DENIED", buff, bufc);
01398                         return;
01399                 }
01400                 num = atoi(fargs[1]);
01401         }
01402 
01403         if((num < 1) || (Typeof(playerask) != TYPE_PLAYER)) {
01404                 safe_str("#-1 NO SUCH MESSAGE", buff, bufc);
01405                 return;
01406         }
01407         mp = mail_fetch(playerask, num);
01408         if(mp != NULL) {
01409                 safe_tprintf_str(buff, bufc, "#%d", mp->from);
01410                 return;
01411         }
01412         /*
01413          * ran off the end of the list without finding anything 
01414          */
01415         safe_str("#-1 NO SUCH MESSAGE", buff, bufc);
01416 }
01417 
01418 /*
01419  * ---------------------------------------------------------------------------
01420  * * fun_hasattr: does object X have attribute Y.
01421  */
01422 
01423 /*
01424  * Hasattr (and hasattrp, which is derived from hasattr) borrowed from
01425  * * TinyMUSH 2.2. 
01426  */
01427 
01428 void fun_hasattr(char *buff, char **bufc, dbref player, dbref cause,
01429                                  char *fargs[], int nfargs, char *cargs[], int ncargs)
01430 {
01431         dbref thing, aowner;
01432         int aflags;
01433         ATTR *attr;
01434         char *tbuf;
01435 
01436         thing = match_thing(player, fargs[0]);
01437         if(thing == NOTHING) {
01438                 safe_str("#-1 NO MATCH", buff, bufc);
01439                 return;
01440         } else if(!Examinable(player, thing)) {
01441                 safe_str("#-1 PERMISSION DENIED", buff, bufc);
01442                 return;
01443         }
01444         attr = atr_str(fargs[1]);
01445         if(!attr) {
01446                 safe_str("0", buff, bufc);
01447                 return;
01448         }
01449         atr_get_info(thing, attr->number, &aowner, &aflags);
01450         if(!See_attr(player, thing, attr, aowner, aflags))
01451                 safe_str("0", buff, bufc);
01452         else {
01453                 tbuf = atr_get(thing, attr->number, &aowner, &aflags);
01454                 if(*tbuf)
01455                         safe_str("1", buff, bufc);
01456                 else
01457                         safe_str("0", buff, bufc);
01458                 free_lbuf(tbuf);
01459         }
01460 }
01461 
01462 void fun_hasattrp(char *buff, char **bufc, dbref player, dbref cause,
01463                                   char *fargs[], int nfargs, char *cargs[], int ncargs)
01464 {
01465         dbref thing, aowner;
01466         int aflags;
01467         ATTR *attr;
01468         char *tbuf;
01469 
01470         thing = match_thing(player, fargs[0]);
01471         if(thing == NOTHING) {
01472                 safe_str("#-1 NO MATCH", buff, bufc);
01473                 return;
01474         } else if(!Examinable(player, thing)) {
01475                 safe_str("#-1 PERMISSION DENIED", buff, bufc);
01476                 return;
01477         }
01478         attr = atr_str(fargs[1]);
01479         if(!attr) {
01480                 safe_str("0", buff, bufc);
01481                 return;
01482         }
01483         atr_pget_info(thing, attr->number, &aowner, &aflags);
01484         if(!See_attr(player, thing, attr, aowner, aflags))
01485                 safe_str("0", buff, bufc);
01486         else {
01487                 tbuf = atr_pget(thing, attr->number, &aowner, &aflags);
01488                 if(*tbuf)
01489                         safe_str("1", buff, bufc);
01490                 else
01491                         safe_str("0", buff, bufc);
01492                 free_lbuf(tbuf);
01493         }
01494 }
01495 
01496 /*
01497  * ---------------------------------------------------------------------------
01498  * * fun_default, fun_edefault, and fun_udefault:
01499  * * These check for the presence of an attribute. If it exists, then it
01500  * * is gotten, via the equivalent of get(), get_eval(), or u(), respectively.
01501  * * Otherwise, the default message is used.
01502  * * In the case of udefault(), the remaining arguments to the function
01503  * * are used as arguments to the u().
01504  */
01505 
01506 /*
01507  * default(), edefault(), and udefault() borrowed from TinyMUSH 2.2 
01508  */
01509 void fun_default(char *buff, char **bufc, dbref player, dbref cause,
01510                                  char *fargs[], int nfargs, char *cargs[], int ncargs)
01511 {
01512         dbref thing, aowner;
01513         int attrib, aflags;
01514         ATTR *attr;
01515         char *objname, *atr_gotten, *bp, *str;
01516 
01517         objname = bp = alloc_lbuf("fun_default");
01518         str = fargs[0];
01519         exec(objname, &bp, 0, player, cause, EV_EVAL | EV_STRIP | EV_FCHECK,
01520                  &str, cargs, ncargs);
01521         *bp = '\0';
01522 
01523         /*
01524          * First we check to see that the attribute exists on the object. * * 
01525          * 
01526          * *  * * If so, we grab it and use it. 
01527          */
01528 
01529         if(objname != NULL) {
01530                 if(parse_attrib(player, objname, &thing, &attrib) &&
01531                    (attrib != NOTHING)) {
01532                         attr = atr_num(attrib);
01533                         if(attr && !(attr->flags & AF_IS_LOCK)) {
01534                                 atr_gotten = atr_pget(thing, attrib, &aowner, &aflags);
01535                                 if(*atr_gotten &&
01536                                    check_read_perms(player, thing, attr, aowner, aflags,
01537                                                                         buff, bufc)) {
01538                                         safe_str(atr_gotten, buff, bufc);
01539                                         free_lbuf(atr_gotten);
01540                                         free_lbuf(objname);
01541                                         return;
01542                                 }
01543                                 free_lbuf(atr_gotten);
01544                         }
01545                 }
01546                 free_lbuf(objname);
01547         }
01548         /*
01549          * If we've hit this point, we've not gotten anything useful, so * we 
01550          * 
01551          * *  * *  * * go and evaluate the default. 
01552          */
01553 
01554         str = fargs[1];
01555         exec(buff, bufc, 0, player, cause, EV_EVAL | EV_STRIP | EV_FCHECK,
01556                  &str, cargs, ncargs);
01557 }
01558 
01559 void fun_edefault(char *buff, char **bufc, dbref player, dbref cause,
01560                                   char *fargs[], int nfargs, char *cargs[], int ncargs)
01561 {
01562         dbref thing, aowner;
01563         int attrib, aflags;
01564         ATTR *attr;
01565         char *objname, *atr_gotten, *bp, *str;
01566 
01567         objname = bp = alloc_lbuf("fun_edefault");
01568         str = fargs[0];
01569         exec(objname, &bp, 0, player, cause, EV_EVAL | EV_STRIP | EV_FCHECK,
01570                  &str, cargs, ncargs);
01571         *bp = '\0';
01572 
01573         /*
01574          * First we check to see that the attribute exists on the object. * * 
01575          * 
01576          * *  * * If so, we grab it and use it. 
01577          */
01578 
01579         if(objname != NULL) {
01580                 if(parse_attrib(player, objname, &thing, &attrib) &&
01581                    (attrib != NOTHING)) {
01582                         attr = atr_num(attrib);
01583                         if(attr && !(attr->flags & AF_IS_LOCK)) {
01584                                 atr_gotten = atr_pget(thing, attrib, &aowner, &aflags);
01585                                 if(*atr_gotten &&
01586                                    check_read_perms(player, thing, attr, aowner, aflags,
01587                                                                         buff, bufc)) {
01588                                         str = atr_gotten;
01589                                         exec(buff, bufc, 0, thing, player,
01590                                                  EV_FIGNORE | EV_EVAL, &str, (char **) NULL, 0);
01591                                         free_lbuf(atr_gotten);
01592                                         free_lbuf(objname);
01593                                         return;
01594                                 }
01595                                 free_lbuf(atr_gotten);
01596                         }
01597                 }
01598                 free_lbuf(objname);
01599         }
01600         /*
01601          * If we've hit this point, we've not gotten anything useful, so * we 
01602          * 
01603          * *  * *  * * go and evaluate the default. 
01604          */
01605 
01606         str = fargs[1];
01607         exec(buff, bufc, 0, player, cause, EV_EVAL | EV_STRIP | EV_FCHECK,
01608                  &str, cargs, ncargs);
01609 }
01610 
01611 void fun_udefault(char *buff, char **bufc, dbref player, dbref cause,
01612                                   char *fargs[], int nfargs, char *cargs[], int ncargs)
01613 {
01614         dbref thing, aowner;
01615         int aflags, anum;
01616         ATTR *ap;
01617         char *objname, *atext, *bp, *str;
01618 
01619         if(nfargs < 2)                          /*
01620                                                                  * must have at least two arguments 
01621                                                                  */
01622                 return;
01623 
01624         str = fargs[0];
01625         objname = bp = alloc_lbuf("fun_udefault");
01626         exec(objname, &bp, 0, player, cause, EV_EVAL | EV_STRIP | EV_FCHECK,
01627                  &str, cargs, ncargs);
01628         *bp = '\0';
01629 
01630         /*
01631          * First we check to see that the attribute exists on the object. * * 
01632          * 
01633          * *  * * If so, we grab it and use it. 
01634          */
01635 
01636         if(objname != NULL) {
01637                 if(parse_attrib(player, objname, &thing, &anum)) {
01638                         if((anum == NOTHING) || (!Good_obj(thing)))
01639                                 ap = NULL;
01640                         else
01641                                 ap = atr_num(anum);
01642                 } else {
01643                         thing = player;
01644                         ap = atr_str(objname);
01645                 }
01646                 if(ap) {
01647                         atext = atr_pget(thing, ap->number, &aowner, &aflags);
01648                         if(atext) {
01649                                 if(*atext &&
01650                                    check_read_perms(player, thing, ap, aowner, aflags,
01651                                                                         buff, bufc)) {
01652                                         str = atext;
01653                                         exec(buff, bufc, 0, thing, cause, EV_FCHECK | EV_EVAL,
01654                                                  &str, &(fargs[2]), nfargs - 1);
01655                                         free_lbuf(atext);
01656                                         free_lbuf(objname);
01657                                         return;
01658                                 }
01659                                 free_lbuf(atext);
01660                         }
01661                 }
01662                 free_lbuf(objname);
01663         }
01664         /*
01665          * If we've hit this point, we've not gotten anything useful, so * we 
01666          * 
01667          * *  * *  * * go and evaluate the default. 
01668          */
01669 
01670         str = fargs[1];
01671         exec(buff, bufc, 0, player, cause, EV_EVAL | EV_STRIP | EV_FCHECK,
01672                  &str, cargs, ncargs);
01673 }
01674 
01675 /*
01676  * ---------------------------------------------------------------------------
01677  * * fun_findable: can X locate Y
01678  */
01679 
01680 /*
01681  * Borrowed from PennMUSH 1.50 
01682  */
01683 void fun_findable(char *buff, char **bufc, dbref player, dbref cause,
01684                                   char *fargs[], int nfargs, char *cargs[], int ncargs)
01685 {
01686         dbref obj = match_thing(player, fargs[0]);
01687         dbref victim = match_thing(player, fargs[1]);
01688 
01689         if(obj == NOTHING)
01690                 safe_str("#-1 ARG1 NOT FOUND", buff, bufc);
01691         else if(victim == NOTHING)
01692                 safe_str("#-1 ARG2 NOT FOUND", buff, bufc);
01693         else
01694                 safe_tprintf_str(buff, bufc, "%d", locatable(obj, victim, obj));
01695 }
01696 
01697 /*
01698  * ---------------------------------------------------------------------------
01699  * * isword: is every character in the argument a letter?
01700  */
01701 
01702 /*
01703  * Borrowed from PennMUSH 1.50 
01704  */
01705 void fun_isword(char *buff, char **bufc, dbref player, dbref cause,
01706                                 char *fargs[], int nfargs, char *cargs[], int ncargs)
01707 {
01708         char *p;
01709 
01710         for(p = fargs[0]; *p; p++) {
01711                 if(!isalpha(*p)) {
01712                         safe_str("0", buff, bufc);
01713                         return;
01714                 }
01715         }
01716         safe_str("1", buff, bufc);
01717 }
01718 
01719 /*
01720  * ---------------------------------------------------------------------------
01721  * * fun_visible:  Can X examine Y. If X does not exist, 0 is returned.
01722  * *               If Y, the object, does not exist, 0 is returned. If
01723  * *               Y the object exists, but the optional attribute does
01724  * *               not, X's ability to return Y the object is returned.
01725  */
01726 
01727 /*
01728  * Borrowed from PennMUSH 1.50 
01729  */
01730 void fun_visible(char *buff, char **bufc, dbref player, dbref cause,
01731                                  char *fargs[], int nfargs, char *cargs[], int ncargs)
01732 {
01733         dbref it, thing, aowner;
01734         int aflags, atr;
01735         ATTR *ap;
01736 
01737         if((it = match_thing(player, fargs[0])) == NOTHING) {
01738                 safe_str("0", buff, bufc);
01739                 return;
01740         }
01741         if(parse_attrib(player, fargs[1], &thing, &atr)) {
01742                 if(atr == NOTHING) {
01743                         safe_tprintf_str(buff, bufc, "%d", Examinable(it, thing));
01744                         return;
01745                 }
01746                 ap = atr_num(atr);
01747                 atr_pget_info(thing, atr, &aowner, &aflags);
01748                 safe_tprintf_str(buff, bufc, "%d", See_attr(it, thing, ap, aowner,
01749                                                                                                         aflags));
01750                 return;
01751         }
01752         thing = match_thing(player, fargs[1]);
01753         if(!Good_obj(thing)) {
01754                 safe_str("0", buff, bufc);
01755                 return;
01756         }
01757         safe_tprintf_str(buff, bufc, "%d", Examinable(it, thing));
01758 }
01759 
01760 /*
01761  * ---------------------------------------------------------------------------
01762  * * fun_elements: given a list of numbers, get corresponding elements from
01763  * * the list.  elements(ack bar eep foof yay,2 4) ==> bar foof
01764  * * The function takes a separator, but the separator only applies to the
01765  * * first list.
01766  */
01767 
01768 /*
01769  * Borrowed from PennMUSH 1.50 
01770  */
01771 void fun_elements(char *buff, char **bufc, dbref player, dbref cause,
01772                                   char *fargs[], int nfargs, char *cargs[], int ncargs)
01773 {
01774         int nwords, cur;
01775         char *ptrs[LBUF_SIZE / 2];
01776         char *wordlist, *s, *r, sep, *oldp;
01777 
01778         varargs_preamble("ELEMENTS", 3);
01779         oldp = *bufc;
01780 
01781         /*
01782          * Turn the first list into an array. 
01783          */
01784 
01785         wordlist = alloc_lbuf("fun_elements.wordlist");
01786         StringCopy(wordlist, fargs[0]);
01787         nwords = list2arr(ptrs, LBUF_SIZE / 2, wordlist, sep);
01788 
01789         s = trim_space_sep(fargs[1], ' ');
01790 
01791         /*
01792          * Go through the second list, grabbing the numbers and finding the * 
01793          * 
01794          * *  * *  * * corresponding elements. 
01795          */
01796 
01797         do {
01798                 r = split_token(&s, ' ');
01799                 cur = atoi(r) - 1;
01800                 if((cur >= 0) && (cur < nwords) && ptrs[cur]) {
01801                         if(oldp != *bufc)
01802                                 safe_chr(sep, buff, bufc);
01803                         safe_str(ptrs[cur], buff, bufc);
01804                 }
01805         } while (s);
01806         free_lbuf(wordlist);
01807 }
01808 
01809 /*
01810  * ---------------------------------------------------------------------------
01811  * * fun_grab: a combination of extract() and match(), sortof. We grab the
01812  * *           single element that we match.
01813  * *
01814  * *   grab(Test:1 Ack:2 Foof:3,*:2)    => Ack:2
01815  * *   grab(Test-1+Ack-2+Foof-3,*o*,+)  => Ack:2
01816  */
01817 
01818 /*
01819  * Borrowed from PennMUSH 1.50 
01820  */
01821 void fun_grab(char *buff, char **bufc, dbref player, dbref cause,
01822                           char *fargs[], int nfargs, char *cargs[], int ncargs)
01823 {
01824         char *r, *s, sep;
01825 
01826         varargs_preamble("GRAB", 3);
01827 
01828         /*
01829          * Walk the wordstring, until we find the word we want. 
01830          */
01831 
01832         s = trim_space_sep(fargs[0], sep);
01833         do {
01834                 r = split_token(&s, sep);
01835                 if(quick_wild(fargs[1], r)) {
01836                         safe_str(r, buff, bufc);
01837                         return;
01838                 }
01839         } while (s);
01840 }
01841 
01842 /* Same as grab, but return all matches */
01843 void fun_graball(char *buff, char **bufc, dbref player, dbref cause,
01844                                  char *fargs[], int nfargs, char *cargs[], int ncargs)
01845 {
01846         char *r, *s, sep, *b;
01847 
01848         varargs_preamble("GRABALL", 3);
01849 
01850         b = *bufc;
01851         s = trim_space_sep(fargs[0], sep);
01852         do {
01853                 r = split_token(&s, sep);
01854                 if(quick_wild(fargs[1], r)) {
01855                         if(*bufc != b)
01856                                 safe_str(" ", buff, bufc);
01857                         safe_str(r, buff, bufc);
01858                 }
01859         } while (s);
01860 }
01861 
01862 /*
01863  * ---------------------------------------------------------------------------
01864  * * fun_scramble:  randomizes the letters in a string.
01865  */
01866 
01867 /*
01868  * Borrowed from PennMUSH 1.50 
01869  */
01870 void fun_scramble(char *buff, char **bufc, dbref player, dbref cause,
01871                                   char *fargs[], int nfargs, char *cargs[], int ncargs)
01872 {
01873         int n, i, j;
01874         char c, *old;
01875 
01876         if(!fargs[0] || !*fargs[0]) {
01877                 return;
01878         }
01879         old = *bufc;
01880 
01881         safe_str(fargs[0], buff, bufc);
01882         **bufc = '\0';
01883 
01884         n = strlen(old);
01885 
01886         for(i = 0; i < n; i++) {
01887                 j = (random() % (n - i)) + i;
01888                 c = old[i];
01889                 old[i] = old[j];
01890                 old[j] = c;
01891         }
01892 }
01893 
01894 /*
01895  * ---------------------------------------------------------------------------
01896  * * fun_shuffle: randomize order of words in a list.
01897  */
01898 
01899 /*
01900  * Borrowed from PennMUSH 1.50 
01901  */
01902 static void swap(char **p, char **q)
01903 {
01904         /*
01905          * swaps two points to strings 
01906          */
01907 
01908         char *temp;
01909 
01910         temp = *p;
01911         *p = *q;
01912         *q = temp;
01913 }
01914 
01915 void fun_shuffle(char *buff, char **bufc, dbref player, dbref cause,
01916                                  char *fargs[], int nfargs, char *cargs[], int ncargs)
01917 {
01918         char *words[LBUF_SIZE];
01919         int n, i, j;
01920         char sep;
01921 
01922         if(!nfargs || !fargs[0] || !*fargs[0]) {
01923                 return;
01924         }
01925         varargs_preamble("SHUFFLE", 2);
01926 
01927         n = list2arr(words, LBUF_SIZE, fargs[0], sep);
01928 
01929         for(i = 0; i < n; i++) {
01930                 j = (random() % (n - i)) + i;
01931                 swap(&words[i], &words[j]);
01932         }
01933         arr2list(words, n, buff, bufc, sep);
01934 }
01935 
01936 /*
01937  * sortby() code borrowed from TinyMUSH 2.2 
01938  */
01939 
01940 static char ucomp_buff[LBUF_SIZE];
01941 static dbref ucomp_cause;
01942 static dbref ucomp_player;
01943 
01944 static int u_comp(const void *s1, const void *s2)
01945 {
01946         /*
01947          * Note that this function is for use in conjunction with our own * * 
01948          * 
01949          * *  * * sane_qsort routine, NOT with the standard library qsort! 
01950          */
01951 
01952         char *result, *tbuf, *elems[2], *bp, *str;
01953         int n;
01954 
01955         if((mudstate.func_invk_ctr > mudconf.func_invk_lim) ||
01956            (mudstate.func_nest_lev > mudconf.func_nest_lim))
01957                 return 0;
01958 
01959         tbuf = alloc_lbuf("u_comp");
01960         elems[0] = (char *) s1;
01961         elems[1] = (char *) s2;
01962         StringCopy(tbuf, ucomp_buff);
01963         result = bp = alloc_lbuf("u_comp");
01964         str = tbuf;
01965         exec(result, &bp, 0, ucomp_player, ucomp_cause,
01966                  EV_STRIP | EV_FCHECK | EV_EVAL, &str, &(elems[0]), 2);
01967         *bp = '\0';
01968         if(!result)
01969                 n = 0;
01970         else {
01971                 n = atoi(result);
01972                 free_lbuf(result);
01973         }
01974         free_lbuf(tbuf);
01975         return n;
01976 }
01977 
01978 static void sane_qsort(void *array[], int left, int right, int (*compare) ())
01979 {
01980         /*
01981          * Andrew Molitor's qsort, which doesn't require transitivity between
01982          * * * * * comparisons (essential for preventing crashes due to *
01983          * boneheads * * * who write comparison functions where a > b doesn't
01984          * * mean b < a).  
01985          */
01986 
01987         int i, last;
01988         void *tmp;
01989 
01990   loop:
01991         if(left >= right)
01992                 return;
01993 
01994         /*
01995          * Pick something at random at swap it into the leftmost slot   
01996          */
01997         /*
01998          * This is the pivot, we'll put it back in the right spot later 
01999          */
02000 
02001         i = random() % (1 + (right - left));
02002         tmp = array[left + i];
02003         array[left + i] = array[left];
02004         array[left] = tmp;
02005 
02006         last = left;
02007         for(i = left + 1; i <= right; i++) {
02008 
02009                 /*
02010                  * Walk the array, looking for stuff that's less than our 
02011                  */
02012                 /*
02013                  * pivot. If it is, swap it with the next thing along     
02014                  */
02015 
02016                 if((*compare) (array[i], array[left]) < 0) {
02017                         last++;
02018                         if(last == i)
02019                                 continue;
02020 
02021                         tmp = array[last];
02022                         array[last] = array[i];
02023                         array[i] = tmp;
02024                 }
02025         }
02026 
02027         /*
02028          * Now we put the pivot back, it's now in the right spot, we never 
02029          */
02030         /*
02031          * need to look at it again, trust me.                             
02032          */
02033 
02034         tmp = array[last];
02035         array[last] = array[left];
02036         array[left] = tmp;
02037 
02038         /*
02039          * At this point everything underneath the 'last' index is < the 
02040          */
02041         /*
02042          * entry at 'last' and everything above it is not < it.          
02043          */
02044 
02045         if((last - left) < (right - last)) {
02046                 sane_qsort(array, left, last - 1, compare);
02047                 left = last + 1;
02048                 goto loop;
02049         } else {
02050                 sane_qsort(array, last + 1, right, compare);
02051                 right = last - 1;
02052                 goto loop;
02053         }
02054 }
02055 
02056 void fun_sortby(char *buff, char **bufc, dbref player, dbref cause,
02057                                 char *fargs[], int nfargs, char *cargs[], int ncargs)
02058 {
02059         char *atext, *list, *ptrs[LBUF_SIZE / 2], sep;
02060         int nptrs, aflags, anum;
02061         dbref thing, aowner;
02062         ATTR *ap;
02063 
02064         if((nfargs == 0) || !fargs[0] || !*fargs[0]) {
02065                 return;
02066         }
02067         varargs_preamble("SORTBY", 3);
02068 
02069         if(parse_attrib(player, fargs[0], &thing, &anum)) {
02070                 if((anum == NOTHING) || !Good_obj(thing))
02071                         ap = NULL;
02072                 else
02073                         ap = atr_num(anum);
02074         } else {
02075                 thing = player;
02076                 ap = atr_str(fargs[0]);
02077         }
02078 
02079         if(!ap) {
02080                 return;
02081         }
02082         atext = atr_pget(thing, ap->number, &aowner, &aflags);
02083         if(!atext) {
02084                 return;
02085         } else if(!*atext || !See_attr(player, thing, ap, aowner, aflags)) {
02086                 free_lbuf(atext);
02087                 return;
02088         }
02089         StringCopy(ucomp_buff, atext);
02090         ucomp_player = thing;
02091         ucomp_cause = cause;
02092 
02093         list = alloc_lbuf("fun_sortby");
02094         StringCopy(list, fargs[1]);
02095         nptrs = list2arr(ptrs, LBUF_SIZE / 2, list, sep);
02096 
02097         if(nptrs > 1)                           /*
02098                                                                  * pointless to sort less than 2 elements 
02099                                                                  */
02100                 sane_qsort((void *) ptrs, 0, nptrs - 1, u_comp);
02101 
02102         arr2list(ptrs, nptrs, buff, bufc, sep);
02103         free_lbuf(list);
02104         free_lbuf(atext);
02105 }
02106 
02107 /*
02108  * ---------------------------------------------------------------------------
02109  * * fun_last: Returns last word in a string
02110  */
02111 
02112 /*
02113  * Borrowed from TinyMUSH 2.2 
02114  */
02115 void fun_last(char *buff, char **bufc, dbref player, dbref cause,
02116                           char *fargs[], int nfargs, char *cargs[], int ncargs)
02117 {
02118         char *s, *last, sep;
02119         int len, i;
02120 
02121         /*
02122          * If we are passed an empty arglist return a null string 
02123          */
02124 
02125         if(nfargs == 0) {
02126                 return;
02127         }
02128         varargs_preamble("LAST", 2);
02129         s = trim_space_sep(fargs[0], sep);      /*
02130                                                                                  * trim leading spaces 
02131                                                                                  */
02132 
02133         /*
02134          * If we're dealing with spaces, trim off the trailing stuff 
02135          */
02136 
02137         if(sep == ' ') {
02138                 len = strlen(s);
02139                 for(i = len - 1; s[i] == ' '; i--);
02140                 if(i + 1 <= len)
02141                         s[i + 1] = '\0';
02142         }
02143         last = (char *) rindex(s, sep);
02144         if(last)
02145                 safe_str(++last, buff, bufc);
02146         else
02147                 safe_str(s, buff, bufc);
02148 }
02149 
02150 /*
02151  * Borrowed from TinyMUSH 2.2 
02152  */
02153 void fun_matchall(char *buff, char **bufc, dbref player, dbref cause,
02154                                   char *fargs[], int nfargs, char *cargs[], int ncargs)
02155 {
02156         int wcount;
02157         char *r, *s, *old, sep, tbuf[8];
02158 
02159         varargs_preamble("MATCHALL", 3);
02160         old = *bufc;
02161 
02162         /*
02163          * Check each word individually, returning the word number of all * * 
02164          * 
02165          * *  * * that match. If none match, return 0. 
02166          */
02167 
02168         wcount = 1;
02169         s = trim_space_sep(fargs[0], sep);
02170         do {
02171                 r = split_token(&s, sep);
02172                 if(quick_wild(fargs[1], r)) {
02173                         sprintf(tbuf, "%d", wcount);
02174                         if(old != *bufc)
02175                                 safe_chr(' ', buff, bufc);
02176                         safe_str(tbuf, buff, bufc);
02177                 }
02178                 wcount++;
02179         } while (s);
02180 
02181         if(*bufc == old)
02182                 safe_str("0", buff, bufc);
02183 }
02184 
02185 /*
02186  * ---------------------------------------------------------------------------
02187  * * fun_ports: Returns a list of ports for a user.
02188  */
02189 
02190 /*
02191  * Borrowed from TinyMUSH 2.2 
02192  */
02193 void fun_ports(char *buff, char **bufc, dbref player, dbref cause,
02194                            char *fargs[], int nfargs, char *cargs[], int ncargs)
02195 {
02196         dbref target;
02197 
02198         if(!Wizard(player)) {
02199                 return;
02200         }
02201         target = lookup_player(player, fargs[0], 1);
02202         if(!Good_obj(target) || !Connected(target)) {
02203                 return;
02204         }
02205         make_portlist(player, target, buff, bufc);
02206 }
02207 
02208 /*
02209  * ---------------------------------------------------------------------------
02210  * * fun_mix: Like map, but operates on two lists simultaneously, passing
02211  * * the elements as %0 as %1.
02212  */
02213 
02214 /*
02215  * Borrowed from PennMUSH 1.50 
02216  */
02217 void fun_mix(char *buff, char **bufc, dbref player, dbref cause,
02218                          char *fargs[], int nfargs, char *cargs[], int ncargs)
02219 {
02220         dbref aowner, thing;
02221         int aflags, anum;
02222         ATTR *ap;
02223         char *atext, *os[2], *oldp, *str, *cp1, *cp2, *atextbuf, sep;
02224 
02225         varargs_preamble("MIX", 4);
02226         oldp = *bufc;
02227 
02228         /*
02229          * Get the attribute, check the permissions. 
02230          */
02231 
02232         if(parse_attrib(player, fargs[0], &thing, &anum)) {
02233                 if((anum == NOTHING) || !Good_obj(thing))
02234                         ap = NULL;
02235                 else
02236                         ap = atr_num(anum);
02237         } else {
02238                 thing = player;
02239                 ap = atr_str(fargs[0]);
02240         }
02241 
02242         if(!ap) {
02243                 return;
02244         }
02245         atext = atr_pget(thing, ap->number, &aowner, &aflags);
02246         if(!atext) {
02247                 return;
02248         } else if(!*atext || !See_attr(player, thing, ap, aowner, aflags)) {
02249                 free_lbuf(atext);
02250                 return;
02251         }
02252         /*
02253          * process the two lists, one element at a time. 
02254          */
02255 
02256         cp1 = trim_space_sep(fargs[1], sep);
02257         cp2 = trim_space_sep(fargs[2], sep);
02258 
02259         if(countwords(cp1, sep) != countwords(cp2, sep)) {
02260                 free_lbuf(atext);
02261                 safe_str("#-1 LISTS MUST BE OF EQUAL SIZE", buff, bufc);
02262                 return;
02263         }
02264         atextbuf = alloc_lbuf("fun_mix");
02265 
02266         while (cp1 && cp2) {
02267                 if(*bufc != oldp)
02268                         safe_chr(sep, buff, bufc);
02269                 os[0] = split_token(&cp1, sep);
02270                 os[1] = split_token(&cp2, sep);
02271                 StringCopy(atextbuf, atext);
02272                 str = atextbuf;
02273                 exec(buff, bufc, 0, player, cause, EV_STRIP | EV_FCHECK | EV_EVAL,
02274                          &str, &(os[0]), 2);
02275         }
02276         free_lbuf(atext);
02277         free_lbuf(atextbuf);
02278 }
02279 
02280 /*
02281  * ---------------------------------------------------------------------------
02282  * * fun_foreach: like map(), but it operates on a string, rather than on a list,
02283  * * calling a user-defined function for each character in the string.
02284  * * No delimiter is inserted between the results.
02285  */
02286 
02287 /*
02288  * Borrowed from TinyMUSH 2.2 
02289  */
02290 void fun_foreach(char *buff, char **bufc, dbref player, dbref cause,
02291                                  char *fargs[], int nfargs, char *cargs[], int ncargs)
02292 {
02293         dbref aowner, thing;
02294         int aflags, anum, flag = 0;
02295         ATTR *ap;
02296         char *atext, *atextbuf, *str, *cp, *bp;
02297         char cbuf[2], prev = '\0';
02298 
02299         if((nfargs != 2) && (nfargs != 4)) {
02300                 safe_str("#-1 FUNCTION (FOREACH) EXPECTS 2 or 4 ARGUMENTS", buff,
02301                                  bufc);
02302                 return;
02303         }
02304 
02305         if(parse_attrib(player, fargs[0], &thing, &anum)) {
02306                 if((anum == NOTHING) || !Good_obj(thing))
02307                         ap = NULL;
02308                 else
02309                         ap = atr_num(anum);
02310         } else {
02311                 thing = player;
02312                 ap = atr_str(fargs[0]);
02313         }
02314 
02315         if(!ap) {
02316                 return;
02317         }
02318         atext = atr_pget(thing, ap->number, &aowner, &aflags);
02319         if(!atext) {
02320                 return;
02321         } else if(!*atext || !See_attr(player, thing, ap, aowner, aflags)) {
02322                 free_lbuf(atext);
02323                 return;
02324         }
02325         atextbuf = alloc_lbuf("fun_foreach");
02326         cp = trim_space_sep(fargs[1], ' ');
02327 
02328         bp = cbuf;
02329 
02330         cbuf[1] = '\0';
02331 
02332         if(nfargs == 4) {
02333                 while (cp && *cp) {
02334                         cbuf[0] = *cp++;
02335 
02336                         if(flag) {
02337                                 if((cbuf[0] == *fargs[3]) && (prev != '\\') && (prev != '%')) {
02338                                         flag = 0;
02339                                         continue;
02340                                 }
02341                         } else {
02342                                 if((cbuf[0] == *fargs[2]) && (prev != '\\') && (prev != '%')) {
02343                                         flag = 1;
02344                                         continue;
02345                                 } else {
02346                                         safe_chr(cbuf[0], buff, bufc);
02347                                         continue;
02348                                 }
02349                         }
02350 
02351                         StringCopy(atextbuf, atext);
02352                         str = atextbuf;
02353                         exec(buff, bufc, 0, player, cause,
02354                                  EV_STRIP | EV_FCHECK | EV_EVAL, &str, &bp, 1);
02355                         prev = cbuf[0];
02356                 }
02357         } else {
02358                 while (cp && *cp) {
02359                         cbuf[0] = *cp++;
02360 
02361                         StringCopy(atextbuf, atext);
02362                         str = atextbuf;
02363                         exec(buff, bufc, 0, player, cause,
02364                                  EV_STRIP | EV_FCHECK | EV_EVAL, &str, &bp, 1);
02365                 }
02366         }
02367 
02368         free_lbuf(atextbuf);
02369         free_lbuf(atext);
02370 }
02371 
02372 /*
02373  * ---------------------------------------------------------------------------
02374  * * fun_munge: combines two lists in an arbitrary manner.
02375  */
02376 
02377 /*
02378  * Borrowed from TinyMUSH 2.2 
02379  */
02380 void fun_munge(char *buff, char **bufc, dbref player, dbref cause,
02381                            char *fargs[], int nfargs, char *cargs[], int ncargs)
02382 {
02383         dbref aowner, thing;
02384         int aflags, anum, nptrs1, nptrs2, nresults, i, j;
02385         ATTR *ap;
02386         char *list1, *list2, *rlist;
02387         char *ptrs1[LBUF_SIZE / 2], *ptrs2[LBUF_SIZE / 2],
02388                 *results[LBUF_SIZE / 2];
02389         char *atext, *bp, *str, sep, *oldp;
02390 
02391         oldp = *bufc;
02392         if((nfargs == 0) || !fargs[0] || !*fargs[0]) {
02393                 return;
02394         }
02395         varargs_preamble("MUNGE", 4);
02396 
02397         /*
02398          * Find our object and attribute 
02399          */
02400 
02401         if(parse_attrib(player, fargs[0], &thing, &anum)) {
02402                 if((anum == NOTHING) || !Good_obj(thing))
02403                         ap = NULL;
02404                 else
02405                         ap = atr_num(anum);
02406         } else {
02407                 thing = player;
02408                 ap = atr_str(fargs[0]);
02409         }
02410 
02411         if(!ap) {
02412                 return;
02413         }
02414         atext = atr_pget(thing, ap->number, &aowner, &aflags);
02415         if(!atext) {
02416                 return;
02417         } else if(!*atext || !See_attr(player, thing, ap, aowner, aflags)) {
02418                 free_lbuf(atext);
02419                 return;
02420         }
02421         /*
02422          * Copy our lists and chop them up. 
02423          */
02424 
02425         list1 = alloc_lbuf("fun_munge.list1");
02426         list2 = alloc_lbuf("fun_munge.list2");
02427         StringCopy(list1, fargs[1]);
02428         StringCopy(list2, fargs[2]);
02429         nptrs1 = list2arr(ptrs1, LBUF_SIZE / 2, list1, sep);
02430         nptrs2 = list2arr(ptrs2, LBUF_SIZE / 2, list2, sep);
02431 
02432         if(nptrs1 != nptrs2) {
02433                 safe_str("#-1 LISTS MUST BE OF EQUAL SIZE", buff, bufc);
02434                 free_lbuf(atext);
02435                 free_lbuf(list1);
02436                 free_lbuf(list2);
02437                 return;
02438         }
02439         /*
02440          * Call the u-function with the first list as %0. 
02441          */
02442 
02443         bp = rlist = alloc_lbuf("fun_munge");
02444         str = atext;
02445         exec(rlist, &bp, 0, player, cause, EV_STRIP | EV_FCHECK | EV_EVAL,
02446                  &str, &fargs[1], 1);
02447         *bp = '\0';
02448 
02449         /*
02450          * Now that we have our result, put it back into array form. Search * 
02451          * 
02452          * *  * *  * * through list1 until we find the element position, then 
02453          * copy  * the * * * corresponding element from list2. 
02454          */
02455 
02456         nresults = list2arr(results, LBUF_SIZE / 2, rlist, sep);
02457 
02458         for(i = 0; i < nresults; i++) {
02459                 for(j = 0; j < nptrs1; j++) {
02460                         if(!strcmp(results[i], ptrs1[j])) {
02461                                 if(*bufc != oldp)
02462                                         safe_chr(sep, buff, bufc);
02463                                 safe_str(ptrs2[j], buff, bufc);
02464                                 ptrs1[j][0] = '\0';
02465                                 break;
02466                         }
02467                 }
02468         }
02469         free_lbuf(atext);
02470         free_lbuf(list1);
02471         free_lbuf(list2);
02472         free_lbuf(rlist);
02473 }
02474 
02475 /*
02476  * die() code borrowed from PennMUSH 1.50 
02477  */
02478 int getrandom(int x)
02479 {
02480         /*
02481          * In order to be perfectly anal about not introducing any further *
02482          * * * sources * of statistical bias, we're going to call random() *
02483          * until * * we get a number * less than the greatest representable * 
02484          * multiple * of  * x. We'll then return * n mod x. 
02485          */
02486         long n;
02487 
02488         if(x <= 0)
02489                 return -1;
02490 
02491         do {
02492                 n = random();
02493         } while (LONG_MAX - n < x);
02494 
02495         /*
02496          * N.B. This loop happens in randomized constant time, and pretty damn
02497          * * fast randomized constant time too, since P(LONG_MAX - n < x) < 0.5
02498          * * for any x, so for any X, the average number of times we should
02499          * * have to call random() is less than 2.
02500          */
02501         return (n % x);
02502 }
02503 
02504 void fun_die(char *buff, char **bufc, dbref player, dbref cause,
02505                          char *fargs[], int nfargs, char *cargs[], int ncargs)
02506 {
02507         int n, die, count;
02508         int total = 0;
02509 
02510         if(!fargs[0] || !fargs[1])
02511                 return;
02512 
02513         n = atoi(fargs[0]);
02514         die = atoi(fargs[1]);
02515 
02516         if((n < 1) || (n > 20)) {
02517                 safe_str("#-1 NUMBER OUT OF RANGE", buff, bufc);
02518                 return;
02519         }
02520         if(die > 100) {
02521                 safe_str("#-1 DON'T BE AN ASSHOLE", buff, bufc);
02522                 return;
02523         }
02524         for(count = 0; count < n; count++)
02525                 total += getrandom(die) + 1;
02526 
02527         safe_tprintf_str(buff, bufc, "%d", total);
02528 }
02529 
02530 /*
02531  * Borrowed from PennMUSH 1.50 
02532  */
02533 void fun_lit(char *buff, char **bufc, dbref player, dbref cause,
02534                          char *fargs[], int nfargs, char *cargs[], int ncargs)
02535 {
02536         /*
02537          * Just returns the argument, literally 
02538          */
02539         safe_str(fargs[0], buff, bufc);
02540 }
02541 
02542 /*
02543  * shl() and shr() borrowed from PennMUSH 1.50 
02544  */
02545 void fun_shl(char *buff, char **bufc, dbref player, dbref cause,
02546                          char *fargs[], int nfargs, char *cargs[], int ncargs)
02547 {
02548         if(is_number(fargs[0]) && is_number(fargs[1]))
02549                 safe_tprintf_str(buff, bufc, "%d", atoi(fargs[0]) << atoi(fargs[1]));
02550         else
02551                 safe_str("#-1 ARGUMENTS MUST BE NUMBERS", buff, bufc);
02552 }
02553 
02554 void fun_shr(char *buff, char **bufc, dbref player, dbref cause,
02555                          char *fargs[], int nfargs, char *cargs[], int ncargs)
02556 {
02557         if(is_number(fargs[0]) && is_number(fargs[1]))
02558                 safe_tprintf_str(buff, bufc, "%d", atoi(fargs[0]) >> atoi(fargs[1]));
02559         else
02560                 safe_str("#-1 ARGUMENTS MUST BE NUMBERS", buff, bufc);
02561 }
02562 
02563 /*
02564  * ------------------------------------------------------------------------
02565  * * Vector functions: VADD, VSUB, VMUL, VCROSS, VMAG, VUNIT, VDIM
02566  * * Vectors are space-separated numbers.
02567  */
02568 
02569 /*
02570  * Vector functions borrowed from PennMUSH 1.50 
02571  */
02572 #define MAXDIM  20
02573 
02574 void fun_vadd(char *buff, char **bufc, dbref player, dbref cause,
02575                           char *fargs[], int nfargs, char *cargs[], int ncargs)
02576 {
02577         char *v1[LBUF_SIZE], *v2[LBUF_SIZE];
02578         char vres[MAXDIM][LBUF_SIZE];
02579         int n, m, i;
02580         char sep;
02581 
02582         varargs_preamble("VADD", 3);
02583 
02584         /*
02585          * split the list up, or return if the list is empty 
02586          */
02587         if(!fargs[0] || !*fargs[0] || !fargs[1] || !*fargs[1]) {
02588                 return;
02589         }
02590         n = list2arr(v1, LBUF_SIZE, fargs[0], sep);
02591         m = list2arr(v2, LBUF_SIZE, fargs[1], sep);
02592 
02593         if(n != m) {
02594                 safe_str("#-1 VECTORS MUST BE SAME DIMENSIONS", buff, bufc);
02595                 return;
02596         }
02597         if(n > MAXDIM) {
02598                 safe_str("#-1 TOO MANY DIMENSIONS ON VECTORS", buff, bufc);
02599                 return;
02600         }
02601         /*
02602          * add it 
02603          */
02604         for(i = 0; i < n; i++) {
02605                 sprintf(vres[i], "%f", atof(v1[i]) + atof(v2[i]));
02606                 v1[i] = (char *) vres[i];
02607         }
02608 
02609         arr2list(v1, n, buff, bufc, sep);
02610 }
02611 
02612 void fun_vsub(char *buff, char **bufc, dbref player, dbref cause,
02613                           char *fargs[], int nfargs, char *cargs[], int ncargs)
02614 {
02615         char *v1[LBUF_SIZE], *v2[LBUF_SIZE];
02616         char vres[MAXDIM][LBUF_SIZE];
02617         int n, m, i;
02618         char sep;
02619 
02620         varargs_preamble("VSUB", 3);
02621 
02622         /*
02623          * split the list up, or return if the list is empty 
02624          */
02625         if(!fargs[0] || !*fargs[0] || !fargs[1] || !*fargs[1]) {
02626                 return;
02627         }
02628         n = list2arr(v1, LBUF_SIZE, fargs[0], sep);
02629         m = list2arr(v2, LBUF_SIZE, fargs[1], sep);
02630 
02631         if(n != m) {
02632                 safe_str("#-1 VECTORS MUST BE SAME DIMENSIONS", buff, bufc);
02633                 return;
02634         }
02635         if(n > MAXDIM) {
02636                 safe_str("#-1 TOO MANY DIMENSIONS ON VECTORS", buff, bufc);
02637                 return;
02638         }
02639         /*
02640          * sub it 
02641          */
02642         for(i = 0; i < n; i++) {
02643                 sprintf(vres[i], "%f", atof(v1[i]) - atof(v2[i]));
02644                 v1[i] = (char *) vres[i];
02645         }
02646 
02647         arr2list(v1, n, buff, bufc, sep);
02648 }
02649 
02650 void fun_vmul(char *buff, char **bufc, dbref player, dbref cause,
02651                           char *fargs[], int nfargs, char *cargs[], int ncargs)
02652 {
02653         char *v1[LBUF_SIZE], *v2[LBUF_SIZE];
02654         char vres[MAXDIM][LBUF_SIZE];
02655         int n, m, i;
02656         float scalar;
02657         char sep;
02658 
02659         varargs_preamble("VMUL", 3);
02660 
02661         /*
02662          * split the list up, or return if the list is empty 
02663          */
02664         if(!fargs[0] || !*fargs[0] || !fargs[1] || !*fargs[1]) {
02665                 return;
02666         }
02667         n = list2arr(v1, LBUF_SIZE, fargs[0], sep);
02668         m = list2arr(v2, LBUF_SIZE, fargs[1], sep);
02669 
02670         if((n != 1) && (m != 1) && (n != m)) {
02671                 safe_str("#-1 VECTORS MUST BE SAME DIMENSIONS", buff, bufc);
02672                 return;
02673         }
02674         if(n > MAXDIM) {
02675                 safe_str("#-1 TOO MANY DIMENSIONS ON VECTORS", buff, bufc);
02676                 return;
02677         }
02678         /*
02679          * multiply it - if n or m is 1, it's scalar multiplication by a * *
02680          * * vector, otherwise it's a dot-product 
02681          */
02682 
02683         if(n == 1) {
02684                 scalar = atof(v1[0]);
02685                 for(i = 0; i < m; i++) {
02686                         sprintf(vres[i], "%f", atof(v2[i]) * scalar);
02687                         v1[i] = (char *) vres[i];
02688                 }
02689                 n = m;
02690         } else if(m == 1) {
02691                 scalar = atof(v2[0]);
02692                 for(i = 0; i < n; i++) {
02693                         sprintf(vres[i], "%f", atof(v1[i]) * scalar);
02694                         v1[i] = (char *) vres[i];
02695                 }
02696         } else {
02697                 /*
02698                  * dot product 
02699                  */
02700                 scalar = 0;
02701                 for(i = 0; i < n; i++) {
02702                         scalar += atof(v1[i]) * atof(v2[i]);
02703                         v1[i] = (char *) vres[i];
02704                 }
02705 
02706                 safe_tprintf_str(buff, bufc, "%f", scalar);
02707                 return;
02708         }
02709 
02710         arr2list(v1, n, buff, bufc, sep);
02711 }
02712 
02713 void fun_vmag(char *buff, char **bufc, dbref player, dbref cause,
02714                           char *fargs[], int nfargs, char *cargs[], int ncargs)
02715 {
02716         char *v1[LBUF_SIZE];
02717         int n, i;
02718         float tmp, res = 0;
02719         char sep;
02720 
02721         varargs_preamble("VMAG", 2);
02722 
02723         /*
02724          * split the list up, or return if the list is empty 
02725          */
02726         if(!fargs[0] || !*fargs[0]) {
02727                 return;
02728         }
02729         n = list2arr(v1, LBUF_SIZE, fargs[0], sep);
02730 
02731         if(n > MAXDIM) {
02732                 StringCopy(buff, "#-1 TOO MANY DIMENSIONS ON VECTORS");
02733                 return;
02734         }
02735         /*
02736          * calculate the magnitude 
02737          */
02738         for(i = 0; i < n; i++) {
02739                 tmp = atof(v1[i]);
02740                 res += tmp * tmp;
02741         }
02742 
02743         if(res > 0)
02744                 safe_tprintf_str(buff, bufc, "%f", sqrt(res));
02745         else
02746                 safe_str("0", buff, bufc);
02747 }
02748 
02749 void fun_vunit(char *buff, char **bufc, dbref player, dbref cause,
02750                            char *fargs[], int nfargs, char *cargs[], int ncargs)
02751 {
02752         char *v1[LBUF_SIZE];
02753         char vres[MAXDIM][LBUF_SIZE];
02754         int n, i;
02755         float tmp, res = 0;
02756         char sep;
02757 
02758         varargs_preamble("VUNIT", 2);
02759 
02760         /*
02761          * split the list up, or return if the list is empty 
02762          */
02763         if(!fargs[0] || !*fargs[0]) {
02764                 return;
02765         }
02766         n = list2arr(v1, LBUF_SIZE, fargs[0], sep);
02767 
02768         if(n > MAXDIM) {
02769                 StringCopy(buff, "#-1 TOO MANY DIMENSIONS ON VECTORS");
02770                 return;
02771         }
02772         /*
02773          * calculate the magnitude 
02774          */
02775         for(i = 0; i < n; i++) {
02776                 tmp = atof(v1[i]);
02777                 res += tmp * tmp;
02778         }
02779 
02780         if(res <= 0) {
02781                 safe_str("#-1 CAN'T MAKE UNIT VECTOR FROM ZERO-LENGTH VECTOR",
02782                                  buff, bufc);
02783                 return;
02784         }
02785         for(i = 0; i < n; i++) {
02786                 sprintf(vres[i], "%f", atof(v1[i]) / sqrt(res));
02787                 v1[i] = (char *) vres[i];
02788         }
02789 
02790         arr2list(v1, n, buff, bufc, sep);
02791 }
02792 
02793 void fun_vdim(char *buff, char **bufc, dbref player, dbref cause,
02794                           char *fargs[], int nfargs, char *cargs[], int ncargs)
02795 {
02796         char sep;
02797 
02798         if(fargs == 0)
02799                 safe_str("0", buff, bufc);
02800         else {
02801                 varargs_preamble("VDIM", 2);
02802                 safe_tprintf_str(buff, bufc, "%d", countwords(fargs[0], sep));
02803         }
02804 }
02805 
02806 void fun_strcat(char *buff, char **bufc, dbref player, dbref cause,
02807                                 char *fargs[], int nfargs, char *cargs[], int ncargs)
02808 {
02809         int i;
02810 
02811         safe_str(fargs[0], buff, bufc);
02812         for(i = 1; i < nfargs; i++) {
02813                 safe_str(fargs[i], buff, bufc);
02814         }
02815 }
02816 
02817 /*
02818  * grep() and grepi() code borrowed from PennMUSH 1.50 
02819  */
02820 char *grep_util(dbref player, dbref thing, char *pattern, char *lookfor,
02821                                 int len, int insensitive)
02822 {
02823         /*
02824          * returns a list of attributes which match <pattern> on <thing> * *
02825          * * * whose contents have <lookfor> 
02826          */
02827         dbref aowner;
02828         char *tbuf1, *buf, *text, *attrib;
02829         char *bp, *bufc;
02830         int found;
02831         int ca, aflags;
02832 
02833         tbuf1 = alloc_lbuf("grep_util");
02834         bufc = buf = alloc_lbuf("grep_util.parse_attrib");
02835         bp = tbuf1;
02836         safe_tprintf_str(buf, &bufc, "#%d/%s", thing, pattern);
02837         olist_push();
02838         if(parse_attrib_wild(player, buf, &thing, 0, 0, 1)) {
02839                 for(ca = olist_first(); ca != NOTHING; ca = olist_next()) {
02840                         attrib = atr_get(thing, ca, &aowner, &aflags);
02841                         text = attrib;
02842                         found = 0;
02843                         while (*text && !found) {
02844                                 if((!insensitive && !strncmp(lookfor, text, len)) ||
02845                                    (insensitive && !strncasecmp(lookfor, text, len)))
02846                                         found = 1;
02847                                 else
02848                                         text++;
02849                         }
02850 
02851                         if(found) {
02852                                 if(bp != tbuf1)
02853                                         safe_chr(' ', tbuf1, &bp);
02854 
02855                                 safe_str((char *) (atr_num(ca))->name, tbuf1, &bp);
02856                         }
02857                         free_lbuf(attrib);
02858                 }
02859         }
02860         free_lbuf(buf);
02861         *bp = '\0';
02862         olist_pop();
02863         return tbuf1;
02864 }
02865 
02866 void fun_grep(char *buff, char **bufc, dbref player, dbref cause,
02867                           char *fargs[], int nfargs, char *cargs[], int ncargs)
02868 {
02869         char *tp;
02870 
02871         dbref it = match_thing(player, fargs[0]);
02872 
02873         if(it == NOTHING) {
02874                 safe_str("#-1 NO MATCH", buff, bufc);
02875                 return;
02876         } else if(!(Examinable(player, it))) {
02877                 safe_str("#-1 PERMISSION DENIED", buff, bufc);
02878                 return;
02879         }
02880         /*
02881          * make sure there's an attribute and a pattern 
02882          */
02883         if(!fargs[1] || !*fargs[1]) {
02884                 safe_str("#-1 NO SUCH ATTRIBUTE", buff, bufc);
02885                 return;
02886         }
02887         if(!fargs[2] || !*fargs[2]) {
02888                 safe_str("#-1 INVALID GREP PATTERN", buff, bufc);
02889                 return;
02890         }
02891         tp = grep_util(player, it, fargs[1], fargs[2], strlen(fargs[2]), 0);
02892         safe_str(tp, buff, bufc);
02893         free_lbuf(tp);
02894 }
02895 
02896 void fun_grepi(char *buff, char **bufc, dbref player, dbref cause,
02897                            char *fargs[], int nfargs, char *cargs[], int ncargs)
02898 {
02899         char *tp;
02900 
02901         dbref it = match_thing(player, fargs[0]);
02902 
02903         if(it == NOTHING) {
02904                 safe_str("#-1 NO MATCH", buff, bufc);
02905                 return;
02906         } else if(!(Examinable(player, it))) {
02907                 safe_str("#-1 PERMISSION DENIED", buff, bufc);
02908                 return;
02909         }
02910         /*
02911          * make sure there's an attribute and a pattern 
02912          */
02913         if(!fargs[1] || !*fargs[1]) {
02914                 safe_str("#-1 NO SUCH ATTRIBUTE", buff, bufc);
02915                 return;
02916         }
02917         if(!fargs[2] || !*fargs[2]) {
02918                 safe_str("#-1 INVALID GREP PATTERN", buff, bufc);
02919                 return;
02920         }
02921         tp = grep_util(player, it, fargs[1], fargs[2], strlen(fargs[2]), 1);
02922         safe_str(tp, buff, bufc);
02923         free_lbuf(tp);
02924 }
02925 
02926 /*
02927  * Borrowed from PennMUSH 1.50 
02928  */
02929 void fun_art(char *buff, char **bufc, dbref player, dbref cause,
02930                          char *fargs[], int nfargs, char *cargs[], int ncargs)
02931 {
02932 
02933         /*
02934          * checks a word and returns the appropriate article, "a" or "an" 
02935          */
02936         char c = tolower(*fargs[0]);
02937 
02938         if(c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u')
02939                 safe_str("an", buff, bufc);
02940         else
02941                 safe_str("a", buff, bufc);
02942 }
02943 
02944 /*
02945  * Borrowed from PennMUSH 1.50 
02946  */
02947 void fun_alphamax(char *buff, char **bufc, dbref player, dbref cause,
02948                                   char *fargs[], int nfargs, char *cargs[], int ncargs)
02949 {
02950         char *amax;
02951         int i = 1;
02952 
02953         if(!fargs[0]) {
02954                 safe_str("#-1 TOO FEW ARGUMENTS", buff, bufc);
02955                 return;
02956         } else
02957                 amax = fargs[0];
02958 
02959         while ((i < 10) && fargs[i]) {
02960                 amax = (strcmp(amax, fargs[i]) > 0) ? amax : fargs[i];
02961                 i++;
02962         }
02963 
02964         safe_tprintf_str(buff, bufc, "%s", amax);
02965 }
02966 
02967 /*
02968  * Borrowed from PennMUSH 1.50 
02969  */
02970 void fun_alphamin(char *buff, char **bufc, dbref player, dbref cause,
02971                                   char *fargs[], int nfargs, char *cargs[], int ncargs)
02972 {
02973         char *amin;
02974         int i = 1;
02975 
02976         if(!fargs[0]) {
02977                 safe_str("#-1 TOO FEW ARGUMENTS", buff, bufc);
02978                 return;
02979         } else
02980                 amin = fargs[0];
02981 
02982         while ((i < 10) && fargs[i]) {
02983                 amin = (strcmp(amin, fargs[i]) < 0) ? amin : fargs[i];
02984                 i++;
02985         }
02986 
02987         safe_tprintf_str(buff, bufc, "%s", amin);
02988 }
02989 
02990 /*
02991  * Borrowed from PennMUSH 1.50 
02992  */
02993 
02994 void fun_valid(char *buff, char **bufc, dbref player, dbref cause,
02995                            char *fargs[], int nfargs, char *cargs[], int ncargs)
02996 {
02997 
02998         /*
02999          * Checks to see if a given <something> is valid as a parameter of a
03000          * * given type (such as an object name).
03001          */
03002 
03003         if(!fargs[0] || !*fargs[0] || !fargs[1] || !*fargs[1])
03004                 safe_str("0", buff, bufc);
03005         else if(!strcasecmp(fargs[0], "name"))
03006                 safe_tprintf_str(buff, bufc, "%d", ok_name(fargs[1]));
03007         else
03008                 safe_str("#-1", buff, bufc);
03009 }
03010 
03011 /*
03012  * Borrowed from PennMUSH 1.50 
03013  */
03014 void fun_hastype(char *buff, char **bufc, dbref player, dbref cause,
03015                                  char *fargs[], int nfargs, char *cargs[], int ncargs)
03016 {
03017         dbref it = match_thing(player, fargs[0]);
03018 
03019         if(it == NOTHING) {
03020                 safe_str("#-1 NO MATCH", buff, bufc);
03021                 return;
03022         }
03023         if(!fargs[1] || !*fargs[1]) {
03024                 safe_str("#-1 NO SUCH TYPE", buff, bufc);
03025                 return;
03026         }
03027         switch (*fargs[1]) {
03028         case 'r':
03029         case 'R':
03030                 safe_str((Typeof(it) == TYPE_ROOM) ? "1" : "0", buff, bufc);
03031                 break;
03032         case 'e':
03033         case 'E':
03034                 safe_str((Typeof(it) == TYPE_EXIT) ? "1" : "0", buff, bufc);
03035                 break;
03036         case 'p':
03037         case 'P':
03038                 safe_str((Typeof(it) == TYPE_PLAYER) ? "1" : "0", buff, bufc);
03039                 break;
03040         case 't':
03041         case 'T':
03042                 safe_str((Typeof(it) == TYPE_THING) ? "1" : "0", buff, bufc);
03043                 break;
03044         default:
03045                 safe_str("#-1 NO SUCH TYPE", buff, bufc);
03046                 break;
03047         };
03048 }
03049 
03050 /*
03051  * Borrowed from PennMUSH 1.50 
03052  */
03053 void fun_lparent(char *buff, char **bufc, dbref player, dbref cause,
03054                                  char *fargs[], int nfargs, char *cargs[], int ncargs)
03055 {
03056         dbref it;
03057         dbref par;
03058         char tbuf1[20];
03059 
03060         it = match_thing(player, fargs[0]);
03061         if(!Good_obj(it)) {
03062                 safe_str("#-1 NO MATCH", buff, bufc);
03063                 return;
03064         } else if(!(Examinable(player, it))) {
03065                 safe_str("#-1 PERMISSION DENIED", buff, bufc);
03066                 return;
03067         }
03068         sprintf(tbuf1, "#%d", it);
03069         safe_str(tbuf1, buff, bufc);
03070         par = Parent(it);
03071 
03072         while (Good_obj(par) && Examinable(player, it)) {
03073                 sprintf(tbuf1, " #%d", par);
03074                 safe_str(tbuf1, buff, bufc);
03075                 it = par;
03076                 par = Parent(par);
03077         }
03078 }
03079 
03080 /* stacksize - returns how many items are stuffed onto an object stack */
03081 
03082 int stacksize(dbref doer)
03083 {
03084         int i;
03085         STACK *sp;
03086 
03087         for(i = 0, sp = Stack(doer); sp != NULL; sp = sp->next, i++);
03088 
03089         return i;
03090 }
03091 
03092 void fun_lstack(char *buff, char **bufc, dbref player, dbref cause,
03093                                 char *fargs[], int nfargs, char *cargs[], int ncargs)
03094 {
03095         STACK *sp;
03096         dbref doer;
03097 
03098         if(nfargs > 1) {
03099                 safe_str("#-1 FUNCTION (CSTACK) EXPECTS 0-1 ARGUMENTS", buff, bufc);
03100                 return;
03101         }
03102         if(!fargs[0]) {
03103                 doer = player;
03104         } else {
03105                 doer = match_thing(player, fargs[0]);
03106         }
03107 
03108         if(!Controls(player, doer)) {
03109                 safe_str("#-1 PERMISSION DENIED", buff, bufc);
03110                 return;
03111         }
03112         for(sp = Stack(doer); sp != NULL; sp = sp->next) {
03113                 safe_str(sp->data, buff, bufc);
03114                 safe_chr(' ', buff, bufc);
03115         }
03116 
03117         if(sp)
03118                 (*bufc)--;
03119 }
03120 
03121 void fun_empty(char *buff, char **bufc, dbref player, dbref cause,
03122                            char *fargs[], int nfargs, char *cargs[], int ncargs)
03123 {
03124         STACK *sp, *next;
03125         dbref doer;
03126 
03127         if(nfargs > 1) {
03128                 safe_str("#-1 FUNCTION (CSTACK) EXPECTS 0-1 ARGUMENTS", buff, bufc);
03129                 return;
03130         }
03131         if(!fargs[0]) {
03132                 doer = player;
03133         } else {
03134                 doer = match_thing(player, fargs[0]);
03135         }
03136 
03137         if(!Controls(player, doer)) {
03138                 safe_str("#-1 PERMISSION DENIED", buff, bufc);
03139                 return;
03140         }
03141         for(sp = Stack(doer); sp != NULL; sp = next) {
03142                 next = sp->next;
03143                 free_lbuf(sp->data);
03144                 free(sp);
03145         }
03146 
03147         s_Stack(doer, NULL);
03148 }
03149 
03150 void fun_items(char *buff, char **bufc, dbref player, dbref cause,
03151                            char *fargs[], int nfargs, char *cargs[], int ncargs)
03152 {
03153         dbref doer;
03154 
03155         if(nfargs > 1) {
03156                 safe_str("#-1 FUNCTION (NUMSTACK) EXPECTS 0-1 ARGUMENTS", buff, bufc);
03157                 return;
03158         }
03159         if(!fargs[0]) {
03160                 doer = player;
03161         } else {
03162                 doer = match_thing(player, fargs[0]);
03163         }
03164 
03165         if(!Controls(player, doer)) {
03166                 safe_str("#-1 PERMISSION DENIED", buff, bufc);
03167                 return;
03168         }
03169         safe_tprintf_str(buff, bufc, "%d", stacksize(doer));
03170 }
03171 
03172 void fun_peek(char *buff, char **bufc, dbref player, dbref cause,
03173                           char *fargs[], int nfargs, char *cargs[], int ncargs)
03174 {
03175         STACK *sp;
03176         dbref doer;
03177         int count, pos;
03178 
03179         if(nfargs > 2) {
03180                 safe_str("#-1 FUNCTION (PEEK) EXPECTS 0-2 ARGUMENTS", buff, bufc);
03181                 return;
03182         }
03183         if(!fargs[0]) {
03184                 doer = player;
03185         } else {
03186                 doer = match_thing(player, fargs[0]);
03187         }
03188 
03189         if(!Controls(player, doer)) {
03190                 safe_str("#-1 PERMISSION DENIED", buff, bufc);
03191                 return;
03192         }
03193         if(!fargs[1] || !*fargs[1]) {
03194                 pos = 0;
03195         } else {
03196                 pos = atoi(fargs[1]);
03197         }
03198 
03199         if(stacksize(doer) == 0) {
03200                 return;
03201         }
03202         if(pos > (stacksize(doer) - 1)) {
03203                 safe_str("#-1 POSITION TOO LARGE", buff, bufc);
03204                 return;
03205         }
03206         count = 0;
03207         sp = Stack(doer);
03208         while (count != pos) {
03209                 if(sp == NULL) {
03210                         return;
03211                 }
03212                 count++;
03213                 sp = sp->next;
03214         }
03215 
03216         safe_str(sp->data, buff, bufc);
03217 }
03218 
03219 void fun_pop(char *buff, char **bufc, dbref player, dbref cause,
03220                          char *fargs[], int nfargs, char *cargs[], int ncargs)
03221 {
03222         STACK *sp, *prev = NULL;
03223         dbref doer;
03224         int count, pos;
03225 
03226         if(nfargs > 2) {
03227                 safe_str("#-1 FUNCTION (POP) EXPECTS 0-2 ARGUMENTS", buff, bufc);
03228                 return;
03229         }
03230 
03231         if(!fargs[0]) {
03232                 doer = player;
03233         } else {
03234                 doer = match_thing(player, fargs[0]);
03235         }
03236 
03237         if(!Controls(player, doer)) {
03238                 safe_str("#-1 PERMISSION DENIED", buff, bufc);
03239                 return;
03240         }
03241 
03242         if(!fargs[1] || !*fargs[1]) {
03243                 pos = 0;
03244         } else {
03245                 pos = atoi(fargs[1]);
03246         }
03247 
03248         sp = Stack(doer);
03249         count = 0;
03250 
03251         if(stacksize(doer) == 0) {
03252                 return;
03253         }
03254 
03255         if(pos > (stacksize(doer) - 1)) {
03256                 safe_str("#-1 POSITION TOO LARGE", buff, bufc);
03257                 return;
03258         }
03259 
03260         while (count != pos) {
03261                 if(sp == NULL) {
03262                         return;
03263                 }
03264                 prev = sp;
03265                 sp = sp->next;
03266                 count++;
03267         }
03268 
03269         safe_str(sp->data, buff, bufc);
03270         if(count == 0) {
03271                 s_Stack(doer, sp->next);
03272                 free_lbuf(sp->data);
03273                 free(sp);
03274         } else {
03275                 prev->next = sp->next;
03276                 free_lbuf(sp->data);
03277                 free(sp);
03278         }
03279 }
03280 
03281 void fun_push(char *buff, char **bufc, dbref player, dbref cause,
03282                           char *fargs[], int nfargs, char *cargs[], int ncargs)
03283 {
03284         STACK *sp;
03285         dbref doer;
03286         char *data;
03287 
03288         if((nfargs > 2) || (nfargs < 1)) {
03289                 safe_str("#-1 FUNCTION (PUSH) EXPECTS 1-2 ARGUMENTS", buff, bufc);
03290                 return;
03291         }
03292         if(!fargs[1]) {
03293                 doer = player;
03294                 data = fargs[0];
03295         } else {
03296                 doer = match_thing(player, fargs[0]);
03297                 data = fargs[1];
03298         }
03299 
03300         if(!Controls(player, doer)) {
03301                 safe_str("#-1 PERMISSION DENIED", buff, bufc);
03302                 return;
03303         }
03304         if(stacksize(doer) >= mudconf.stack_limit) {
03305                 safe_str("#-1 STACK SIZE EXCEEDED", buff, bufc);
03306                 return;
03307         }
03308         sp = (STACK *) malloc(sizeof(STACK));
03309         sp->next = Stack(doer);
03310         sp->data = alloc_lbuf("push");
03311         StringCopy(sp->data, data);
03312         s_Stack(doer, sp);
03313 }
03314 
03315 /* ---------------------------------------------------------------------------
03316  * fun_regmatch: Return 0 or 1 depending on whether or not a regular
03317  * expression matches a string. If a third argument is specified, dump
03318  * the results of a regexp pattern match into a set of arbitrary r()-registers.
03319  *
03320  * regmatch(string, pattern, list of registers)
03321  * If the number of matches exceeds the registers, those bits are tossed
03322  * out.
03323  * If -1 is specified as a register number, the matching bit is tossed.
03324  * Therefore, if the list is "-1 0 3 5", the regexp $0 is tossed, and
03325  * the regexp $1, $2, and $3 become r(0), r(3), and r(5), respectively.
03326  *
03327  */
03328 
03329 void fun_regmatch(char *buff, char **bufc, dbref player, dbref cause,
03330                                   char *fargs[], int nfargs, char *cargs[], int ncargs)
03331 {
03332         int i, nqregs, curq, len;
03333         char *qregs[10];
03334         regex_t re;
03335         int errcode;
03336         static char errbuf[LINE_MAX];
03337         int got_match;
03338         regmatch_t pmatch[NSUBEXP];
03339 
03340         if(!fn_range_check("REGMATCH", nfargs, 2, 3, buff, bufc))
03341                 return;
03342 
03343         if((errcode = regcomp(&re, fargs[1], REG_EXTENDED)) != 0) {
03344                 /* Matching error. */
03345                 regerror(errcode, &re, errbuf, LINE_MAX);
03346                 notify_quiet(player, errbuf);
03347                 safe_chr('0', buff, bufc);
03348                 return;
03349         }
03350 
03351         got_match = (regexec(&re, fargs[0], NSUBEXP, pmatch, 0) == 0);
03352         if(got_match) {
03353                 if(re.re_nsub > 0)
03354                         safe_tprintf_str(buff, bufc, "%d", re.re_nsub);
03355                 else
03356                         safe_tprintf_str(buff, bufc, "1");
03357         } else
03358                 safe_tprintf_str(buff, bufc, "0");
03359 
03360         /* If we don't have a third argument, we're done. */
03361         if(nfargs != 3) {
03362                 regfree(&re);
03363                 return;
03364         }
03365 
03366         /* We need to parse the list of registers. Anything that we don't get is
03367          * assumed to be -1.
03368          */
03369         nqregs = list2arr(qregs, 10, fargs[2], ' ');
03370         for(i = 0; i < nqregs; i++) {
03371                 if(qregs[i] && *qregs[i] && isdigit(*qregs[i]))
03372                         curq = atoi(qregs[i]);
03373                 else
03374                         continue;
03375                 if(curq < 0 || curq > 9)
03376                         continue;
03377 
03378                 if(!mudstate.global_regs[curq])
03379                         mudstate.global_regs[curq] = alloc_lbuf("fun_regmatch");
03380 
03381                 if(!got_match || pmatch[i].rm_so == -1 || pmatch[i].rm_eo == -1) {
03382                         mudstate.global_regs[curq][0] = '\0';
03383                         continue;
03384                 }
03385                 len = pmatch[i].rm_eo - pmatch[i].rm_so;
03386                 if(len < 0)
03387                         len = 0;
03388                 if(len >= LBUF_SIZE)
03389                         len = LBUF_SIZE - 1;
03390                 strncpy(mudstate.global_regs[curq], fargs[0] + pmatch[i].rm_so, len);
03391                 mudstate.global_regs[curq][len] = '\0'; /* must null-terminate */
03392         }
03393         regfree(&re);
03394 }
03395 
03396 /* ---------------------------------------------------------------------------
03397  * fun_translate: Takes a string and a second argument. If the second argument
03398  * is 0 or s, control characters are converted to spaces. If it's 1 or p,
03399  * they're converted to percent substitutions.
03400  */
03401 
03402 void fun_translate(char *buff, char **bufc, dbref player, dbref cause,
03403                                    char *fargs[], int nfargs, char *cargs[], int ncargs)
03404 {
03405         int type = 0;
03406 
03407         if(fargs[0] && fargs[1]) {
03408                 if(*fargs[1] && ((*fargs[1] == 's') || (*fargs[1] == '0')))
03409                         type = 0;
03410                 else if(*fargs[1] && ((*fargs[1] == 'p') || (*fargs[1] == '1')))
03411                         type = 1;
03412 
03413                 safe_str(translate_string(fargs[0], type), buff, bufc);
03414         }
03415 }
03416 
03417 /*
03418  * ---------------------------------------------------------------------------
03419  * fun_setlock: Set lock from a function (like @lock)
03420  */
03421 
03422 extern NAMETAB lock_sw;
03423 
03424 void fun_setlock(char *buff, char **bufc, dbref player, dbref cause,
03425                                  char *fargs[], int nfargs, char *cargs[], int ncargs)
03426 {
03427         int switchkey = 0;
03428         dbref thing, aowner;
03429         int atr, aflags;
03430         ATTR *ap;
03431         struct boolexp *okey;
03432 
03433         if(*fargs[0]) {
03434                 switchkey = search_nametab(player, &lock_sw, fargs[0]);
03435                 if(switchkey < 0) {
03436                         safe_str("#-1 SWITCH ERROR", buff, bufc);
03437                         return;
03438                 }
03439         }
03440 
03441         if(parse_attrib(player, fargs[1], &thing, &atr)) {
03442                 if(atr != NOTHING) {
03443                         if(!atr_get_info(thing, atr, &aowner, &aflags)) {
03444                                 safe_str("#-1 ATTR NOT FOUND", buff, bufc);
03445                                 return;
03446                         }
03447                         ap = atr_num(atr);
03448 
03449                         /*
03450                          * You may lock an attribute iff: you could write the
03451                          * attribute if it were stored on yourself --and-- you own
03452                          * the attribute or are a wizard as long as you are not #1
03453                          * and are trying to do something to #1.
03454                          */
03455 
03456                         if(ap && (God(player) || (!God(thing) &&
03457                                                                           (Set_attr(player, player, ap, 0)
03458                                                                            && (Wizard(player)
03459                                                                                    || aowner == Owner(player)))))) {
03460                                 if(*fargs[2])
03461                                         aflags |= AF_LOCK;
03462                                 else
03463                                         aflags &= ~AF_LOCK;
03464                                 atr_set_flags(thing, atr, aflags);
03465                                 safe_str("1", buff, bufc);
03466                         } else {
03467                                 safe_str("#-1 PERMISSION DENIED", buff, bufc);
03468                         }
03469                         return;
03470                 }
03471         }
03472         init_match(player, fargs[1], NOTYPE);
03473         match_everything(MAT_EXIT_PARENTS);
03474         thing = match_result();
03475 
03476         switch (thing) {
03477         case NOTHING:
03478                 safe_str("#-1 NOT FOUND", buff, bufc);
03479                 return;
03480         case AMBIGUOUS:
03481                 safe_str("#-1 AMBIGUOUS MATCH", buff, bufc);
03482                 return;
03483         default:
03484                 if(!controls(player, thing)) {
03485                         safe_str("#-1 PERMISSION DENIED", buff, bufc);
03486                         return;
03487                 }
03488         }
03489 
03490         if(!switchkey)
03491                 switchkey = A_LOCK;
03492 
03493         if(!*fargs[2]) {
03494                 atr_clr(thing, switchkey);
03495                 safe_str("1", buff, bufc);
03496                 return;
03497         }
03498 
03499         okey = parse_boolexp(player, fargs[2], 0);
03500         if(okey == TRUE_BOOLEXP) {
03501                 safe_str("#-1 KEY ERROR", buff, bufc);
03502         } else {
03503 
03504                 /*
03505                  * everything ok, do it 
03506                  */
03507 
03508                 atr_add_raw(thing, switchkey, unparse_boolexp_quiet(player, okey));
03509                 safe_str("1", buff, bufc);
03510         }
03511         free_boolexp(okey);
03512 }

Generated on Mon May 28 04:25:19 2007 for BattletechMUX by  doxygen 1.4.7