mux/src/funceval.cpp

Go to the documentation of this file.
00001 // funceval.cpp -- MUX function handlers.
00002 //
00003 // $Id: funceval.cpp,v 1.106 2007/04/14 04:57:05 sdennis Exp $
00004 //
00005 
00006 #include "copyright.h"
00007 #include "autoconf.h"
00008 #include "config.h"
00009 #include "externs.h"
00010 
00011 #include <limits.h>
00012 #include <math.h>
00013 
00014 #include "ansi.h"
00015 #include "attrs.h"
00016 #include "command.h"
00017 #include "comsys.h"
00018 #include "functions.h"
00019 #include "misc.h"
00020 #include "pcre.h"
00021 #ifdef REALITY_LVLS
00022 #include "levels.h"
00023 #endif /* REALITY_LVLS */
00024 
00025 /* Note: Many functions in this file have been taken, whole or in part, from
00026  * PennMUSH 1.50, and TinyMUSH 2.2, for softcode compatibility. The
00027  * maintainers of MUX would like to thank those responsible for PennMUSH 1.50
00028  * and TinyMUSH 2.2, and hope we have adequately noted in the source where
00029  * credit is due.
00030  */
00031 
00032 bool parse_and_get_attrib(dbref executor, char *fargs[], char **atext, dbref *thing, char *buff, char **bufc)
00033 {
00034     ATTR *ap;
00035 
00036     // Two possibilities for the first arg: <obj>/<attr> and <attr>.
00037     //
00038     if (!parse_attrib(executor, fargs[0], thing, &ap))
00039     {
00040         *thing = executor;
00041         ap = atr_str(fargs[0]);
00042     }
00043 
00044     // Make sure we got a good attribute.
00045     //
00046     if (!ap)
00047     {
00048         return false;
00049     }
00050 
00051     // Use it if we can access it, otherwise return an error.
00052     //
00053     if (!See_attr(executor, *thing, ap))
00054     {
00055         safe_noperm(buff, bufc);
00056         return false;
00057     }
00058 
00059     dbref aowner;
00060     int aflags;
00061     *atext = atr_pget(*thing, ap->number, &aowner, &aflags);
00062     if (!*atext)
00063     {
00064         return false;
00065     }
00066     else if (!**atext)
00067     {
00068         free_lbuf(*atext);
00069         return false;
00070     }
00071     return true;
00072 }
00073 
00074 #define CWHO_ON  0
00075 #define CWHO_OFF 1
00076 #define CWHO_ALL 2
00077 
00078 FUNCTION(fun_cwho)
00079 {
00080     UNUSED_PARAMETER(caller);
00081     UNUSED_PARAMETER(enactor);
00082     UNUSED_PARAMETER(cargs);
00083     UNUSED_PARAMETER(ncargs);
00084 
00085     struct channel *ch = select_channel(fargs[0]);
00086     if (!ch)
00087     {
00088         safe_str("#-1 CHANNEL NOT FOUND", buff, bufc);
00089         return;
00090     }
00091     if (  !mudconf.have_comsys
00092        || (  !Comm_All(executor)
00093           && executor != ch->charge_who))
00094     {
00095         safe_noperm(buff, bufc);
00096         return;
00097     }
00098 
00099     int match_type = CWHO_ON;
00100     if (nfargs == 2)
00101     {
00102         if (mux_stricmp(fargs[1], "all") == 0)
00103         {
00104             match_type = CWHO_ALL;
00105         }
00106         else if (mux_stricmp(fargs[1], "off") == 0)
00107         {
00108             match_type = CWHO_OFF;
00109         }
00110         else if (mux_stricmp(fargs[1], "on") == 0)
00111         {
00112             match_type = CWHO_ON;
00113         }
00114     }
00115 
00116     ITL pContext;
00117     struct comuser *user;
00118     ItemToList_Init(&pContext, buff, bufc, '#');
00119     for (user = ch->on_users; user; user = user->on_next)
00120     {
00121         if (  (  match_type == CWHO_ALL
00122               || (  (Connected(user->who) || isThing(user->who))
00123                  && (  (match_type == CWHO_ON && user->bUserIsOn)
00124                     || (match_type == CWHO_OFF && !(user->bUserIsOn)))))
00125            && !ItemToList_AddInteger(&pContext, user->who))
00126         {
00127             break;
00128         }
00129     }
00130     ItemToList_Final(&pContext);
00131 }
00132 
00133 FUNCTION(fun_beep)
00134 {
00135     UNUSED_PARAMETER(executor);
00136     UNUSED_PARAMETER(caller);
00137     UNUSED_PARAMETER(enactor);
00138     UNUSED_PARAMETER(fargs);
00139     UNUSED_PARAMETER(nfargs);
00140     UNUSED_PARAMETER(cargs);
00141     UNUSED_PARAMETER(ncargs);
00142 
00143     safe_chr(BEEP_CHAR, buff, bufc);
00144 }
00145 
00146 #define ANSI_F  0x00000001
00147 #define ANSI_H  0x00000002
00148 #define ANSI_U  0x00000004
00149 #define ANSI_I  0x00000008
00150 #define ANSI_FC 0x00000010
00151 #define ANSI_BC 0x00000020
00152 
00153 static const unsigned char ansi_have_table[256] =
00154 {
00155     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,      // 0x00-0x0F
00156     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,      // 0x10-0x1F
00157     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,      // 0x20-0x2F
00158     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,      // 0x30-0x3F
00159     0,           0,             ANSI_BC,     ANSI_BC,     // 0x40-0x43
00160     0,           0,             0,           ANSI_BC,     // 0x44-0x47
00161     0,           0,             0,           0,           // 0x48-0x4B
00162     0,           ANSI_BC,       0,           0,           // 0x4B-0x4F
00163     0,           0,             ANSI_BC,     0,           // 0x50-0x53
00164     0,           0,             0,           ANSI_BC,     // 0x54-0x57
00165     ANSI_BC,     ANSI_BC,       0,           0,           // 0x58-0x5B
00166     0,           0,             0,           0,           // 0x5B-0x5F
00167     0,           0,             ANSI_FC,     ANSI_FC,     // 0x60-0x63
00168     0,           0,             ANSI_F,      ANSI_FC,     // 0x64-0x67
00169     ANSI_H,      ANSI_I,        0,           0,           // 0x68-0x6B
00170     0,           ANSI_FC,       0,           0,           // 0x6C-0x6F
00171     0,           0,             ANSI_FC,     0,           // 0x70-0x73
00172     0,           ANSI_U,        0,           ANSI_FC,     // 0x74-0x77
00173     ANSI_FC,     ANSI_FC,       0,           0,           // 0x78-0x7B
00174     0,           0,             0,           0,           // 0x7B-0x7F
00175     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,      // 0x80-0x8F
00176     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,      // 0x90-0x9F
00177     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,      // 0xA0-0xAF
00178     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,      // 0xB0-0xBF
00179     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,      // 0xC0-0xCF
00180     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,      // 0xD0-0xDF
00181     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,      // 0xE0-0xEF
00182     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0       // 0xF0-0xFF
00183 };
00184 
00185 static void SimplifyColorLetters(char *pOut, char *pIn)
00186 {
00187     if (  pIn[0] == 'n'
00188        && pIn[1] == '\0')
00189     {
00190         pOut[0] = 'n';
00191         pOut[1] = '\0';
00192         return;
00193     }
00194     char *p;
00195     int have = 0;
00196     size_t nIn = strlen(pIn);
00197     for (p = pIn + nIn - 1; p >= pIn && *p != 'n'; p--)
00198     {
00199         int mask = ansi_have_table[(unsigned char)*p];
00200         if (  mask
00201            && (have & mask) == 0)
00202         {
00203             *pOut++ = *p;
00204             have |= mask;
00205         }
00206     }
00207     *pOut = '\0';
00208 }
00209 
00210 // This function was originally taken from PennMUSH 1.50
00211 //
00212 FUNCTION(fun_ansi)
00213 {
00214     UNUSED_PARAMETER(executor);
00215     UNUSED_PARAMETER(caller);
00216     UNUSED_PARAMETER(enactor);
00217     UNUSED_PARAMETER(cargs);
00218     UNUSED_PARAMETER(ncargs);
00219 
00220     int iArg0;
00221     for (iArg0 = 0; iArg0 + 1 < nfargs; iArg0 += 2)
00222     {
00223         char   pOut[8];
00224         SimplifyColorLetters(pOut, fargs[iArg0]);
00225         char tmp[LBUF_SIZE];
00226         char *bp = tmp;
00227 
00228         char *s = pOut;
00229         while (*s)
00230         {
00231             const char *pColor = ColorTable[(unsigned char)*s];
00232             if (pColor)
00233             {
00234                 safe_str(pColor, tmp, &bp);
00235             }
00236             s++;
00237         }
00238         safe_str(fargs[iArg0+1], tmp, &bp);
00239         *bp = '\0';
00240         int nVisualWidth;
00241         size_t nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1;
00242         size_t nLen = ANSI_TruncateToField(tmp, nBufferAvailable, *bufc,
00243             LBUF_SIZE, &nVisualWidth, ANSI_ENDGOAL_NORMAL);
00244         *bufc += nLen;
00245     }
00246 }
00247 
00248 FUNCTION(fun_zone)
00249 {
00250     UNUSED_PARAMETER(caller);
00251     UNUSED_PARAMETER(enactor);
00252     UNUSED_PARAMETER(nfargs);
00253     UNUSED_PARAMETER(cargs);
00254     UNUSED_PARAMETER(ncargs);
00255 
00256     if (!mudconf.have_zones)
00257     {
00258         safe_str("#-1 ZONES DISABLED", buff, bufc);
00259         return;
00260     }
00261     dbref it = match_thing_quiet(executor, fargs[0]);
00262     if (!Good_obj(it))
00263     {
00264         safe_match_result(it, buff, bufc);
00265     }
00266     else if (Examinable(executor, it))
00267     {
00268         safe_tprintf_str(buff, bufc, "#%d", Zone(it));
00269     }
00270     else
00271     {
00272         safe_nothing(buff, bufc);
00273     }
00274 }
00275 
00276 #ifdef SIDE_EFFECT_FUNCTIONS
00277 
00278 static bool check_command(dbref player, char *name, char *buff, char **bufc)
00279 {
00280     CMDENT *cmdp = (CMDENT *)hashfindLEN(name, strlen(name), &mudstate.command_htab);
00281     if (cmdp)
00282     {
00283         // Perform checks similiar to (but not exactly like) the
00284         // ones in process_cmdent(): object type checks, permission
00285         // checks, ands global flags.
00286         //
00287         if (  Invalid_Objtype(player)
00288            || !check_access(player, cmdp->perms)
00289            || (  !Builder(player)
00290               && Protect(CA_GBL_BUILD)
00291               && !(mudconf.control_flags & CF_BUILD)))
00292         {
00293             safe_noperm(buff, bufc);
00294             return true;
00295         }
00296     }
00297     return false;
00298 }
00299 
00300 FUNCTION(fun_link)
00301 {
00302     UNUSED_PARAMETER(nfargs);
00303     UNUSED_PARAMETER(cargs);
00304     UNUSED_PARAMETER(ncargs);
00305 
00306     if (check_command(executor, "@link", buff, bufc))
00307     {
00308         return;
00309     }
00310     do_link(executor, caller, enactor, 0, 2, fargs[0], fargs[1]);
00311 }
00312 
00313 FUNCTION(fun_tel)
00314 {
00315     UNUSED_PARAMETER(nfargs);
00316     UNUSED_PARAMETER(cargs);
00317     UNUSED_PARAMETER(ncargs);
00318 
00319     if (check_command(executor, "@teleport", buff, bufc))
00320     {
00321         return;
00322     }
00323     do_teleport(executor, caller, enactor, 0, 2, fargs[0], fargs[1]);
00324 }
00325 
00326 FUNCTION(fun_pemit)
00327 {
00328     UNUSED_PARAMETER(caller);
00329     UNUSED_PARAMETER(enactor);
00330     UNUSED_PARAMETER(nfargs);
00331     UNUSED_PARAMETER(cargs);
00332     UNUSED_PARAMETER(ncargs);
00333 
00334     if (check_command(executor, "@pemit", buff, bufc))
00335     {
00336         return;
00337     }
00338     do_pemit_list(executor, PEMIT_PEMIT, false, 0, fargs[0], 0, fargs[1]);
00339 }
00340 
00341 FUNCTION(fun_oemit)
00342 {
00343     UNUSED_PARAMETER(caller);
00344     UNUSED_PARAMETER(enactor);
00345     UNUSED_PARAMETER(nfargs);
00346     UNUSED_PARAMETER(cargs);
00347     UNUSED_PARAMETER(ncargs);
00348 
00349     if (check_command(executor, "@oemit", buff, bufc))
00350     {
00351         return;
00352     }
00353     do_pemit_single(executor, PEMIT_OEMIT, false, 0, fargs[0], 0, fargs[1]);
00354 }
00355 
00356 FUNCTION(fun_emit)
00357 {
00358     UNUSED_PARAMETER(nfargs);
00359     UNUSED_PARAMETER(cargs);
00360     UNUSED_PARAMETER(ncargs);
00361 
00362     if (check_command(executor, "@emit", buff, bufc))
00363     {
00364         return;
00365     }
00366     do_say(executor, caller, enactor, SAY_EMIT, fargs[0]);
00367 }
00368 
00369 FUNCTION(fun_remit)
00370 {
00371     UNUSED_PARAMETER(caller);
00372     UNUSED_PARAMETER(enactor);
00373     UNUSED_PARAMETER(nfargs);
00374     UNUSED_PARAMETER(cargs);
00375     UNUSED_PARAMETER(ncargs);
00376 
00377     if (check_command(executor, "@pemit", buff, bufc))
00378     {
00379         return;
00380     }
00381     do_pemit_single(executor, PEMIT_PEMIT, true, 0, fargs[0], 0, fargs[1]);
00382 }
00383 
00384 FUNCTION(fun_cemit)
00385 {
00386     UNUSED_PARAMETER(cargs);
00387     UNUSED_PARAMETER(ncargs);
00388 
00389     if (check_command(executor, "@cemit", buff, bufc))
00390     {
00391         return;
00392     }
00393     do_cemit(executor, caller, enactor, 0, nfargs, fargs[0], fargs[1]);
00394 }
00395 
00396 // ------------------------------------------------------------------------
00397 // fun_create: Creates a room, thing or exit.
00398 //
00399 FUNCTION(fun_create)
00400 {
00401     SEP sep;
00402     if (!OPTIONAL_DELIM(3, sep, DELIM_DFLT))
00403     {
00404         return;
00405     }
00406 
00407     char *name = fargs[0];
00408 
00409     if (!name || !*name)
00410     {
00411         safe_str("#-1 ILLEGAL NAME", buff, bufc);
00412         return;
00413     }
00414     if (nfargs >= 3 && *fargs[2])
00415     {
00416         sep.str[0] = *fargs[2];
00417     }
00418     else
00419     {
00420         sep.str[0] = 't';
00421     }
00422 
00423     dbref thing;
00424     int cost;
00425 
00426     switch (sep.str[0])
00427     {
00428     case 'r':
00429 
00430         if (check_command(executor, "@dig", buff, bufc))
00431         {
00432             return;
00433         }
00434         thing = create_obj(executor, TYPE_ROOM, name, 0);
00435         if (thing != NOTHING)
00436         {
00437             local_data_create(thing);
00438         }
00439         break;
00440 
00441     case 'e':
00442 
00443         if (check_command(executor, "@open", buff, bufc))
00444         {
00445             return;
00446         }
00447         thing = create_obj(executor, TYPE_EXIT, name, 0);
00448         if (thing != NOTHING)
00449         {
00450             s_Exits(thing, executor);
00451             s_Next(thing, Exits(executor));
00452             s_Exits(executor, thing);
00453             local_data_create(thing);
00454         }
00455         break;
00456 
00457     default:
00458 
00459         if (check_command(executor, "@create", buff, bufc))
00460         {
00461             return;
00462         }
00463         if (*fargs[1])
00464         {
00465             cost = mux_atol(fargs[1]);
00466             if (  cost < mudconf.createmin
00467                || mudconf.createmax < cost)
00468             {
00469                 safe_range(buff, bufc);
00470                 return;
00471             }
00472         }
00473         else
00474         {
00475             cost = mudconf.createmin;
00476         }
00477         thing = create_obj(executor, TYPE_THING, name, cost);
00478         if (thing != NOTHING)
00479         {
00480             move_via_generic(thing, executor, NOTHING, 0);
00481             s_Home(thing, new_home(executor));
00482             local_data_create(thing);
00483         }
00484         break;
00485     }
00486     safe_tprintf_str(buff, bufc, "#%d", thing);
00487 }
00488 
00489 FUNCTION(fun_textfile)
00490 {
00491     UNUSED_PARAMETER(caller);
00492     UNUSED_PARAMETER(enactor);
00493     UNUSED_PARAMETER(nfargs);
00494     UNUSED_PARAMETER(cargs);
00495     UNUSED_PARAMETER(ncargs);
00496 
00497     mux_strlwr(fargs[0]);
00498 
00499     CMDENT_ONE_ARG *cmdp = (CMDENT_ONE_ARG *)hashfindLEN(fargs[0],
00500         strlen(fargs[0]), &mudstate.command_htab);
00501     if (  !cmdp
00502        || cmdp->handler != do_help)
00503     {
00504         safe_str("#-1 NOT FOUND", buff, bufc);
00505         return;
00506     }
00507 
00508     if (check_command(executor, fargs[0], buff, bufc))
00509     {
00510         return;
00511     }
00512 
00513     help_helper(executor, cmdp->extra, fargs[1], buff, bufc);
00514 }
00515 
00516 /* ---------------------------------------------------------------------------
00517  * fun_set: sets an attribute on an object
00518  */
00519 
00520 static void set_attr_internal(dbref player, dbref thing, int attrnum, char *attrtext, int key, char *buff, char **bufc)
00521 {
00522     if (!Good_obj(thing))
00523     {
00524         safe_noperm(buff, bufc);
00525         notify_quiet(player, "You shouldn't be rummaging through the garbage.");
00526         return;
00527     }
00528 
00529     dbref aowner;
00530     int aflags;
00531     ATTR *pattr = atr_num(attrnum);
00532     atr_pget_info(thing, attrnum, &aowner, &aflags);
00533     if (  pattr
00534        && bCanSetAttr(player, thing, pattr))
00535     {
00536         bool could_hear = Hearer(thing);
00537         atr_add(thing, attrnum, attrtext, Owner(player), aflags);
00538         handle_ears(thing, could_hear, Hearer(thing));
00539         if (  !(key & SET_QUIET)
00540            && !Quiet(player)
00541            && !Quiet(thing))
00542         {
00543             notify_quiet(player, "Set.");
00544         }
00545     }
00546     else
00547     {
00548         safe_noperm(buff, bufc);
00549     }
00550 }
00551 
00552 FUNCTION(fun_set)
00553 {
00554     UNUSED_PARAMETER(caller);
00555     UNUSED_PARAMETER(enactor);
00556     UNUSED_PARAMETER(nfargs);
00557     UNUSED_PARAMETER(cargs);
00558     UNUSED_PARAMETER(ncargs);
00559 
00560     if (check_command(executor, "@set", buff, bufc))
00561     {
00562         return;
00563     }
00564 
00565     dbref thing, aowner;
00566     int aflags;
00567     ATTR *pattr;
00568 
00569     // See if we have the <obj>/<attr> form, which is how you set
00570     // attribute flags.
00571     //
00572     if (parse_attrib(executor, fargs[0], &thing, &pattr))
00573     {
00574         if (  pattr
00575            && See_attr(executor, thing, pattr))
00576         {
00577             char *flagname = fargs[1];
00578 
00579             // You must specify a flag name.
00580             //
00581             if (flagname[0] == '\0')
00582             {
00583                 safe_str("#-1 UNSPECIFIED PARAMETER", buff, bufc);
00584                 return;
00585             }
00586 
00587             // Check for clearing.
00588             //
00589             bool clear = false;
00590             if (flagname[0] == NOT_TOKEN)
00591             {
00592                 flagname++;
00593                 clear = true;
00594             }
00595 
00596             // Make sure player specified a valid attribute flag.
00597             //
00598             int flagvalue;
00599             if (!search_nametab(executor, indiv_attraccess_nametab, flagname, &flagvalue))
00600             {
00601                 safe_str("#-1 CANNOT SET", buff, bufc);
00602                 return;
00603             }
00604 
00605             // Make sure the object has the attribute present.
00606             //
00607             if (!atr_get_info(thing, pattr->number, &aowner, &aflags))
00608             {
00609                 safe_str("#-1 ATTRIBUTE NOT PRESENT ON OBJECT", buff, bufc);
00610                 return;
00611             }
00612 
00613             // Make sure we can write to the attribute.
00614             //
00615             if (!bCanSetAttr(executor, thing, pattr))
00616             {
00617                 safe_noperm(buff, bufc);
00618                 return;
00619             }
00620 
00621             // Go do it.
00622             //
00623             if (clear)
00624             {
00625                 aflags &= ~flagvalue;
00626             }
00627             else
00628             {
00629                 aflags |= flagvalue;
00630             }
00631             atr_set_flags(thing, pattr->number, aflags);
00632             return;
00633         }
00634     }
00635 
00636     // Find thing.
00637     //
00638     thing = match_controlled_quiet(executor, fargs[0]);
00639     if (!Good_obj(thing))
00640     {
00641         safe_nothing(buff, bufc);
00642         return;
00643     }
00644 
00645     // Check for attr set first.
00646     //
00647     char *p;
00648     for (p = fargs[1]; *p && *p != ':'; p++)
00649     {
00650         ; // Nothing
00651     }
00652 
00653     if (*p)
00654     {
00655         *p++ = 0;
00656         int atr = mkattr(executor, fargs[1]);
00657         if (atr <= 0)
00658         {
00659             safe_str("#-1 UNABLE TO CREATE ATTRIBUTE", buff, bufc);
00660             return;
00661         }
00662         pattr = atr_num(atr);
00663         if (!pattr)
00664         {
00665             safe_noperm(buff, bufc);
00666             return;
00667         }
00668         if (!bCanSetAttr(executor, thing, pattr))
00669         {
00670             safe_noperm(buff, bufc);
00671             return;
00672         }
00673         char *buff2 = alloc_lbuf("fun_set");
00674 
00675         // Check for _
00676         //
00677         if (*p == '_')
00678         {
00679             ATTR *pattr2;
00680             dbref thing2;
00681 
00682             strcpy(buff2, p + 1);
00683             if (!( parse_attrib(executor, p + 1, &thing2, &pattr2)
00684                 && pattr2))
00685             {
00686                 free_lbuf(buff2);
00687                 safe_nomatch(buff, bufc);
00688                 return;
00689             }
00690             p = buff2;
00691             atr_pget_str(buff2, thing2, pattr2->number, &aowner, &aflags);
00692 
00693             if (!See_attr(executor, thing2, pattr2))
00694             {
00695                 free_lbuf(buff2);
00696                 safe_noperm(buff, bufc);
00697                 return;
00698             }
00699         }
00700 
00701         // Go set it.
00702         //
00703         set_attr_internal(executor, thing, atr, p, 0, buff, bufc);
00704         free_lbuf(buff2);
00705         return;
00706     }
00707 
00708     // Set/clear a flag.
00709     //
00710     flag_set(thing, executor, fargs[1], 0);
00711 }
00712 #endif
00713 
00714 // Generate a substitution array.
00715 //
00716 static unsigned int GenCode(char *pCode, const char *pCodeASCII)
00717 {
00718     // Strip out the ANSI.
00719     //
00720     size_t nIn;
00721     char *pIn = strip_ansi(pCodeASCII, &nIn);
00722 
00723     // Process the printable characters.
00724     //
00725     char *pOut = pCode;
00726     while (*pIn)
00727     {
00728         unsigned char ch = *pIn;
00729         if (  ' ' <= ch
00730            && ch <= '~')
00731         {
00732             *pOut++ = ch - ' ';
00733         }
00734         pIn++;
00735     }
00736     *pOut = '\0';
00737     return pOut - pCode;
00738 }
00739 
00740 static char *crypt_code(char *code, char *text, bool type)
00741 {
00742     if (  !text
00743        || text[0] == '\0')
00744     {
00745         return "";
00746     }
00747     if (  !code
00748        || code[0] == '\0')
00749     {
00750         return text;
00751     }
00752 
00753     char codebuff[LBUF_SIZE];
00754     unsigned int nCode = GenCode(codebuff, code);
00755     if (nCode == 0)
00756     {
00757         return text;
00758     }
00759 
00760     static char textbuff[LBUF_SIZE];
00761     char *p = strip_ansi(text);
00762     char *q = codebuff;
00763     unsigned int nq = nCode;
00764     char *r = textbuff;
00765 
00766     int iMod    = '~' - ' ' + 1;
00767 
00768     // Encryption loop:
00769     //
00770     while (*p)
00771     {
00772         unsigned char ch = *p;
00773         if (  ' ' <= ch
00774            && ch <= '~')
00775         {
00776             int iCode = ch - ' ';
00777             if (type)
00778             {
00779                 iCode += *q;
00780                 if (iMod <= iCode)
00781                 {
00782                     iCode -= iMod;
00783                 }
00784             }
00785             else
00786             {
00787                 iCode -= *q;
00788                 if (iCode < 0)
00789                 {
00790                     iCode += iMod;
00791                 }
00792             }
00793             *r++ = iCode + ' ';
00794             q++;
00795             nq--;
00796             if (0 == nq)
00797             {
00798                 q = codebuff;
00799                 nq = nCode;
00800             }
00801         }
00802         p++;
00803     }
00804     *r = '\0';
00805     return textbuff;
00806 }
00807 
00808 // Code for encrypt() and decrypt() was taken from the DarkZone
00809 // server.
00810 //
00811 FUNCTION(fun_encrypt)
00812 {
00813     UNUSED_PARAMETER(executor);
00814     UNUSED_PARAMETER(caller);
00815     UNUSED_PARAMETER(enactor);
00816     UNUSED_PARAMETER(nfargs);
00817     UNUSED_PARAMETER(cargs);
00818     UNUSED_PARAMETER(ncargs);
00819 
00820     safe_str(crypt_code(fargs[1], fargs[0], true), buff, bufc);
00821 }
00822 
00823 FUNCTION(fun_decrypt)
00824 {
00825     UNUSED_PARAMETER(executor);
00826     UNUSED_PARAMETER(caller);
00827     UNUSED_PARAMETER(enactor);
00828     UNUSED_PARAMETER(nfargs);
00829     UNUSED_PARAMETER(cargs);
00830     UNUSED_PARAMETER(ncargs);
00831 
00832     safe_str(crypt_code(fargs[1], fargs[0], false), buff, bufc);
00833 }
00834 
00835 // Borrowed from DarkZone
00836 //
00837 static void scan_zone
00838 (
00839     dbref executor,
00840     char *szZone,
00841     int   ObjectType,
00842     char *buff,
00843     char **bufc
00844 )
00845 {
00846     if (!mudconf.have_zones)
00847     {
00848         safe_str("#-1 ZONES DISABLED", buff, bufc);
00849         return;
00850     }
00851 
00852     dbref it = match_thing_quiet(executor, szZone);
00853     if (!Good_obj(it))
00854     {
00855         safe_match_result(it, buff, bufc);
00856         return;
00857     }
00858     else if (!(  WizRoy(executor)
00859               || Controls(executor, it)))
00860     {
00861         safe_noperm(buff, bufc);
00862         return;
00863     }
00864 
00865     dbref i;
00866     ITL pContext;
00867     ItemToList_Init(&pContext, buff, bufc, '#');
00868     DO_WHOLE_DB(i)
00869     {
00870         if (  Typeof(i) == ObjectType
00871            && Zone(i) == it
00872            && !ItemToList_AddInteger(&pContext, i))
00873         {
00874             break;
00875         }
00876     }
00877     ItemToList_Final(&pContext);
00878 }
00879 
00880 FUNCTION(fun_zwho)
00881 {
00882     UNUSED_PARAMETER(caller);
00883     UNUSED_PARAMETER(enactor);
00884     UNUSED_PARAMETER(nfargs);
00885     UNUSED_PARAMETER(cargs);
00886     UNUSED_PARAMETER(ncargs);
00887 
00888     scan_zone(executor, fargs[0], TYPE_PLAYER, buff, bufc);
00889 }
00890 
00891 FUNCTION(fun_inzone)
00892 {
00893     UNUSED_PARAMETER(caller);
00894     UNUSED_PARAMETER(enactor);
00895     UNUSED_PARAMETER(nfargs);
00896     UNUSED_PARAMETER(cargs);
00897     UNUSED_PARAMETER(ncargs);
00898 
00899     scan_zone(executor, fargs[0], TYPE_ROOM, buff, bufc);
00900 }
00901 
00902 // Borrowed from DarkZone
00903 //
00904 FUNCTION(fun_children)
00905 {
00906     UNUSED_PARAMETER(caller);
00907     UNUSED_PARAMETER(enactor);
00908     UNUSED_PARAMETER(nfargs);
00909     UNUSED_PARAMETER(cargs);
00910     UNUSED_PARAMETER(ncargs);
00911 
00912     dbref it = match_thing_quiet(executor, fargs[0]);
00913     if (!Good_obj(it))
00914     {
00915         safe_match_result(it, buff, bufc);
00916         return;
00917     }
00918     else if (!(  WizRoy(executor)
00919               || Controls(executor, it)))
00920     {
00921         safe_noperm(buff, bufc);
00922         return;
00923     }
00924 
00925     dbref i;
00926     ITL pContext;
00927     ItemToList_Init(&pContext, buff, bufc, '#');
00928     DO_WHOLE_DB(i)
00929     {
00930         if (  Parent(i) == it
00931            && !ItemToList_AddInteger(&pContext, i))
00932         {
00933             break;
00934         }
00935     }
00936     ItemToList_Final(&pContext);
00937 }
00938 
00939 FUNCTION(fun_objeval)
00940 {
00941     UNUSED_PARAMETER(nfargs);
00942 
00943     if (!*fargs[0])
00944     {
00945         return;
00946     }
00947     char *name = alloc_lbuf("fun_objeval");
00948     char *bp = name;
00949     char *str = fargs[0];
00950     mux_exec(name, &bp, executor, caller, enactor,
00951              EV_FCHECK | EV_STRIP_CURLY | EV_EVAL, &str, cargs, ncargs);
00952     *bp = '\0';
00953 
00954     dbref obj = match_thing_quiet(executor, name);
00955     free_lbuf(name);
00956     if (!Good_obj(obj))
00957     {
00958         safe_match_result(obj, buff, bufc);
00959         return;
00960     }
00961 
00962     if (!Controls(executor, obj))
00963     {
00964         // The right circumstances were not met, so we are evaluating
00965         // as the executor who gave the command instead of the
00966         // requested object.
00967         //
00968         obj = executor;
00969     }
00970 
00971     mudstate.nObjEvalNest++;
00972     str = fargs[1];
00973     mux_exec(buff, bufc, obj, executor, enactor,
00974              EV_FCHECK | EV_STRIP_CURLY | EV_EVAL, &str, cargs, ncargs);
00975     mudstate.nObjEvalNest--;
00976 }
00977 
00978 FUNCTION(fun_localize)
00979 {
00980     UNUSED_PARAMETER(nfargs);
00981 
00982     char **preserve = NULL;
00983     int *preserve_len = NULL;
00984     preserve = PushPointers(MAX_GLOBAL_REGS);
00985     preserve_len = PushIntegers(MAX_GLOBAL_REGS);
00986     save_global_regs("fun_localize", preserve, preserve_len);
00987 
00988     char *str = fargs[0];
00989     mux_exec(buff, bufc, executor, caller, enactor,
00990         EV_FCHECK | EV_STRIP_CURLY | EV_EVAL, &str, cargs, ncargs);
00991 
00992     restore_global_regs("fun_localize", preserve, preserve_len);
00993     PopIntegers(preserve_len, MAX_GLOBAL_REGS);
00994     PopPointers(preserve, MAX_GLOBAL_REGS);
00995 }
00996 
00997 FUNCTION(fun_null)
00998 {
00999     UNUSED_PARAMETER(buff);
01000     UNUSED_PARAMETER(bufc);
01001     UNUSED_PARAMETER(executor);
01002     UNUSED_PARAMETER(caller);
01003     UNUSED_PARAMETER(enactor);
01004     UNUSED_PARAMETER(fargs);
01005     UNUSED_PARAMETER(nfargs);
01006     UNUSED_PARAMETER(cargs);
01007     UNUSED_PARAMETER(ncargs);
01008 
01009     return;
01010 }
01011 
01012 FUNCTION(fun_squish)
01013 {
01014     UNUSED_PARAMETER(executor);
01015     UNUSED_PARAMETER(caller);
01016     UNUSED_PARAMETER(enactor);
01017     UNUSED_PARAMETER(cargs);
01018     UNUSED_PARAMETER(ncargs);
01019 
01020     if (nfargs == 0)
01021     {
01022         return;
01023     }
01024 
01025     SEP sep;
01026     if (!OPTIONAL_DELIM(2, sep, DELIM_DFLT))
01027     {
01028         return;
01029     }
01030 
01031     char *p;
01032     char *q = fargs[0];
01033     while ((p = strchr(q, sep.str[0])) != NULL)
01034     {
01035         p = p + 1;
01036         size_t nLen = p - q;
01037         safe_copy_buf(q, nLen, buff, bufc);
01038         q = p;
01039         while (*q == sep.str[0])
01040         {
01041             q++;
01042         }
01043     }
01044     safe_str(q, buff, bufc);
01045 }
01046 
01047 FUNCTION(fun_stripansi)
01048 {
01049     UNUSED_PARAMETER(executor);
01050     UNUSED_PARAMETER(caller);
01051     UNUSED_PARAMETER(enactor);
01052     UNUSED_PARAMETER(nfargs);
01053     UNUSED_PARAMETER(cargs);
01054     UNUSED_PARAMETER(ncargs);
01055 
01056     safe_str(strip_ansi(fargs[0]), buff, bufc);
01057 }
01058 
01059 // Borrowed from PennMUSH 1.50
01060 //
01061 FUNCTION(fun_zfun)
01062 {
01063     UNUSED_PARAMETER(caller);
01064     UNUSED_PARAMETER(cargs);
01065     UNUSED_PARAMETER(ncargs);
01066 
01067     if (!mudconf.have_zones)
01068     {
01069         safe_str("#-1 ZONES DISABLED", buff, bufc);
01070         return;
01071     }
01072 
01073     dbref zone = Zone(executor);
01074     if (!Good_obj(zone))
01075     {
01076         safe_str("#-1 INVALID ZONE", buff, bufc);
01077         return;
01078     }
01079 
01080     // Find the user function attribute.
01081     //
01082     int attrib = get_atr(fargs[0]);
01083     if (!attrib)
01084     {
01085         safe_str("#-1 NO SUCH USER FUNCTION", buff, bufc);
01086         return;
01087     }
01088     dbref aowner;
01089     int aflags;
01090     ATTR *pattr = atr_num(attrib);
01091     char *tbuf1 = atr_pget(zone, attrib, &aowner, &aflags);
01092     if (  !pattr
01093        || !See_attr(executor, zone, pattr))
01094     {
01095         safe_noperm(buff, bufc);
01096         free_lbuf(tbuf1);
01097         return;
01098     }
01099     char *str = tbuf1;
01100     mux_exec(buff, bufc, zone, executor, enactor,
01101              EV_EVAL | EV_STRIP_CURLY | EV_FCHECK, &str, &(fargs[1]), nfargs - 1);
01102     free_lbuf(tbuf1);
01103 }
01104 
01105 FUNCTION(fun_columns)
01106 {
01107     SEP sep;
01108     if (!OPTIONAL_DELIM(3, sep, DELIM_STRING))
01109     {
01110         return;
01111     }
01112 
01113     int nWidth = mux_atol(fargs[1]);
01114     int nIndent = 0;
01115     if (nfargs == 4)
01116     {
01117         nIndent = mux_atol(fargs[3]);
01118         if (nIndent < 0 || 77 < nIndent)
01119         {
01120             nIndent = 1;
01121         }
01122     }
01123 
01124     int nRight = nIndent + nWidth;
01125     if (  nWidth < 1
01126        || 78 < nWidth
01127        || nRight < 1
01128        || 78 < nRight)
01129     {
01130         safe_range(buff, bufc);
01131         return;
01132     }
01133 
01134     char *cp = trim_space_sep(fargs[0], &sep);
01135     if (!*cp)
01136     {
01137         return;
01138     }
01139 
01140     int nColumns = (78-nIndent)/nWidth;
01141     int iColumn = 0;
01142 
01143     int nBufferAvailable = LBUF_SIZE - (*bufc-buff) - 1;
01144     bool bNeedCRLF = false;
01145     while (  cp
01146           && 0 < nBufferAvailable)
01147     {
01148         if (iColumn == 0)
01149         {
01150             nBufferAvailable -= safe_fill(buff, bufc, ' ', nIndent);
01151         }
01152 
01153         char *objstring = split_token(&cp, &sep);
01154         int nVisualWidth;
01155         int nLen = ANSI_TruncateToField(objstring, nBufferAvailable, *bufc,
01156             nWidth, &nVisualWidth, ANSI_ENDGOAL_NORMAL);
01157         *bufc += nLen;
01158         nBufferAvailable -= nLen;
01159 
01160         if (nColumns-1 <= iColumn)
01161         {
01162             iColumn = 0;
01163             nBufferAvailable -= safe_copy_buf("\r\n", 2, buff, bufc);
01164             bNeedCRLF = false;
01165         }
01166         else
01167         {
01168             iColumn++;
01169             nBufferAvailable -= safe_fill(buff, bufc, ' ',
01170                 nWidth - nVisualWidth);
01171             bNeedCRLF = true;
01172         }
01173     }
01174     if (bNeedCRLF)
01175     {
01176         safe_copy_buf("\r\n", 2, buff, bufc);
01177     }
01178 }
01179 
01180 // table(<list>,<field width>,<line length>,<delimiter>,<output separator>, <padding>)
01181 //
01182 // Ported from PennMUSH 1.7.3 by Morgan.
01183 //
01184 // TODO: Support ANSI in output separator and padding.
01185 //
01186 FUNCTION(fun_table)
01187 {
01188     UNUSED_PARAMETER(executor);
01189     UNUSED_PARAMETER(caller);
01190     UNUSED_PARAMETER(enactor);
01191     UNUSED_PARAMETER(cargs);
01192     UNUSED_PARAMETER(ncargs);
01193 
01194     // Check argument numbers, assign values and defaults if necessary.
01195     //
01196     char *pPaddingStart = NULL;
01197     char *pPaddingEnd = NULL;
01198     if (nfargs == 6 && *fargs[5])
01199     {
01200         pPaddingStart = strip_ansi(fargs[5]);
01201         pPaddingEnd = strchr(pPaddingStart, '\0');
01202     }
01203 
01204     // Get single-character separator.
01205     //
01206     char cSeparator = ' ';
01207     if (nfargs >= 5 && fargs[4][0] != '\0')
01208     {
01209         if (fargs[4][1] == '\0')
01210         {
01211             cSeparator = *fargs[4];
01212         }
01213         else
01214         {
01215             safe_str("#-1 SEPARATOR MUST BE ONE CHARACTER", buff, bufc);
01216             return;
01217         }
01218     }
01219 
01220     // Get single-character delimiter.
01221     //
01222     char cDelimiter = ' ';
01223     if (nfargs >= 4 && fargs[3][0] != '\0')
01224     {
01225         if (fargs[3][1] == '\0')
01226         {
01227             cDelimiter = *fargs[3];
01228         }
01229         else
01230         {
01231             safe_str("#-1 DELIMITER MUST BE ONE CHARACTER", buff, bufc);
01232             return;
01233         }
01234     }
01235 
01236     // Get line length.
01237     //
01238     int nLineLength = 78;
01239     if (nfargs >= 3)
01240     {
01241         nLineLength = mux_atol(fargs[2]);
01242     }
01243 
01244     // Get field width.
01245     //
01246     int nFieldWidth = 10;
01247     if (nfargs >= 2)
01248     {
01249         nFieldWidth = mux_atol(fargs[1]);
01250     }
01251     else
01252     {
01253         nFieldWidth = 10;
01254     }
01255 
01256     // Validate nFieldWidth and nLineLength.
01257     //
01258     if (  nLineLength < 1
01259        || LBUF_SIZE   <= nLineLength
01260        || nFieldWidth < 1
01261        || nLineLength < nFieldWidth)
01262     {
01263         safe_range(buff, bufc);
01264         return;
01265     }
01266 
01267     int nNumCols = nLineLength / nFieldWidth;
01268     SEP sep;
01269     sep.n = 1;
01270     sep.str[0] = cDelimiter;
01271     char *pNext = trim_space_sep(fargs[0], &sep);
01272     if (!*pNext)
01273     {
01274         return;
01275     }
01276 
01277     char *pCurrent = split_token(&pNext, &sep);
01278     if (!pCurrent)
01279     {
01280         return;
01281     }
01282 
01283     int nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1;
01284     int nCurrentCol = nNumCols - 1;
01285     for (;;)
01286     {
01287         int nVisibleLength, nPaddingLength;
01288         int nStringLength =
01289             ANSI_TruncateToField( pCurrent, nBufferAvailable, *bufc,
01290                                   nFieldWidth, &nVisibleLength, ANSI_ENDGOAL_NORMAL);
01291 
01292         *bufc += nStringLength;
01293         nBufferAvailable -= nStringLength;
01294 
01295         nPaddingLength = nFieldWidth - nVisibleLength;
01296         if (nPaddingLength > nBufferAvailable)
01297         {
01298             nPaddingLength = nBufferAvailable;
01299         }
01300         if (nPaddingLength)
01301         {
01302             nBufferAvailable -= nPaddingLength;
01303             if (pPaddingStart)
01304             {
01305                 for (  char *pPaddingCurrent = pPaddingStart;
01306                        nPaddingLength > 0;
01307                        nPaddingLength--)
01308                 {
01309                     **bufc = *pPaddingCurrent;
01310                     (*bufc)++;
01311                     pPaddingCurrent++;
01312 
01313                     if (pPaddingCurrent == pPaddingEnd)
01314                     {
01315                         pPaddingCurrent = pPaddingStart;
01316                     }
01317                 }
01318             }
01319             else
01320             {
01321                 memset(*bufc, ' ', nPaddingLength);
01322                 *bufc += nPaddingLength;
01323             }
01324         }
01325 
01326         pCurrent = split_token(&pNext, &sep);
01327         if (!pCurrent)
01328         {
01329             break;
01330         }
01331 
01332         if (!nCurrentCol)
01333         {
01334             nCurrentCol = nNumCols - 1;
01335             if (nBufferAvailable >= 2)
01336             {
01337                 char *p = *bufc;
01338                 p[0] = '\r';
01339                 p[1] = '\n';
01340 
01341                 nBufferAvailable -= 2;
01342                 *bufc += 2;
01343             }
01344             else
01345             {
01346                 // nBufferAvailable has less than 2 characters left, if there's
01347                 // no room left just break out.
01348                 //
01349                 if (!nBufferAvailable)
01350                 {
01351                     break;
01352                 }
01353             }
01354         }
01355         else
01356         {
01357             nCurrentCol--;
01358             if (!nBufferAvailable)
01359             {
01360                 break;
01361             }
01362             **bufc = cSeparator;
01363             (*bufc)++;
01364             nBufferAvailable--;
01365         }
01366     }
01367 }
01368 
01369 // Code for objmem and playmem borrowed from PennMUSH 1.50
01370 //
01371 static int mem_usage(dbref thing)
01372 {
01373     int k = sizeof(struct object) + strlen(Name(thing)) + 1;
01374 
01375     char *as;
01376     for (int ca = atr_head(thing, &as); ca; ca = atr_next(&as))
01377     {
01378         size_t nLen;
01379         const char *str = atr_get_raw_LEN(thing, ca, &nLen);
01380         k += nLen+1;
01381         ATTR *pattr = atr_num(ca);
01382         if (pattr)
01383         {
01384             str = pattr->name;
01385             if (  str
01386                && *str)
01387             {
01388                 k += strlen(str)+1;
01389             }
01390         }
01391     }
01392     return k;
01393 }
01394 
01395 FUNCTION(fun_objmem)
01396 {
01397     UNUSED_PARAMETER(caller);
01398     UNUSED_PARAMETER(enactor);
01399     UNUSED_PARAMETER(nfargs);
01400     UNUSED_PARAMETER(cargs);
01401     UNUSED_PARAMETER(ncargs);
01402 
01403     dbref thing = match_thing_quiet(executor, fargs[0]);
01404     if (!Good_obj(thing))
01405     {
01406         safe_match_result(thing, buff, bufc);
01407     }
01408     else if (Examinable(executor, thing))
01409     {
01410         safe_ltoa(mem_usage(thing), buff, bufc);
01411     }
01412     else
01413     {
01414         safe_noperm(buff, bufc);
01415     }
01416 }
01417 
01418 FUNCTION(fun_playmem)
01419 {
01420     UNUSED_PARAMETER(caller);
01421     UNUSED_PARAMETER(enactor);
01422     UNUSED_PARAMETER(cargs);
01423     UNUSED_PARAMETER(ncargs);
01424 
01425     dbref thing;
01426     if (nfargs == 1)
01427     {
01428         thing = match_thing_quiet(executor, fargs[0]);
01429         if (!Good_obj(thing))
01430         {
01431             safe_match_result(thing, buff, bufc);
01432             return;
01433         }
01434         else if (!Examinable(executor, thing))
01435         {
01436             safe_noperm(buff, bufc);
01437             return;
01438         }
01439     }
01440     else
01441     {
01442         thing = executor;
01443     }
01444     int tot = 0;
01445     dbref j;
01446     DO_WHOLE_DB(j)
01447     {
01448         if (Owner(j) == thing)
01449         {
01450             tot += mem_usage(j);
01451         }
01452     }
01453     safe_ltoa(tot, buff, bufc);
01454 }
01455 
01456 // Code for andflags() and orflags() borrowed from PennMUSH 1.50
01457 // false for orflags, true for andflags
01458 //
01459 static bool handle_flaglists(dbref player, char *name, char *fstr, bool type)
01460 {
01461     dbref it = match_thing_quiet(player, name);
01462     if (!Good_obj(it))
01463     {
01464         return false;
01465     }
01466 
01467     char *s;
01468     char flagletter[2];
01469     FLAGSET fset;
01470     FLAG p_type;
01471     bool negate = false;
01472     bool temp = false;
01473     bool ret = type;
01474 
01475     for (s = fstr; *s; s++)
01476     {
01477         // Check for a negation sign. If we find it, we note it and
01478         // increment the pointer to the next character.
01479         //
01480         if (*s == '!')
01481         {
01482             negate = true;
01483             s++;
01484         }
01485         else
01486         {
01487             negate = false;
01488         }
01489 
01490         if (!*s)
01491         {
01492             return false;
01493         }
01494         flagletter[0] = *s;
01495         flagletter[1] = '\0';
01496 
01497         if (!convert_flags(player, flagletter, &fset, &p_type))
01498         {
01499             // Either we got a '!' that wasn't followed by a letter, or we
01500             // couldn't find that flag. For AND, since we've failed a check,
01501             // we can return false. Otherwise we just go on.
01502             //
01503             if (type)
01504             {
01505                 return false;
01506             }
01507             else
01508             {
01509                 continue;
01510             }
01511         }
01512         else
01513         {
01514             // Does the object have this flag?
01515             //
01516             if (  (Flags(it) & fset.word[FLAG_WORD1])
01517                || (Flags2(it) & fset.word[FLAG_WORD2])
01518                || (Flags3(it) & fset.word[FLAG_WORD3])
01519                || Typeof(it) == p_type)
01520             {
01521                 if (  isPlayer(it)
01522                    && fset.word[FLAG_WORD2] == CONNECTED
01523                    && Hidden(it)
01524                    && !See_Hidden(player))
01525                 {
01526                     temp = false;
01527                 }
01528                 else
01529                 {
01530                     temp = true;
01531                 }
01532             }
01533             else
01534             {
01535                 temp = false;
01536             }
01537 
01538             if (  type
01539                && (  (negate && temp)
01540                   || (!negate && !temp)))
01541             {
01542                 // Too bad there's no NXOR function. At this point we've
01543                 // either got a flag and we don't want it, or we don't have a
01544                 // flag and we want it. Since it's AND, we return false.
01545                 //
01546                 return false;
01547 
01548             }
01549             else if (  !type
01550                     && (  (!negate && temp)
01551                        || (negate && !temp)))
01552             {
01553                 // We've found something we want, in an OR. We OR a true with
01554                 // the current value.
01555                 //
01556                 ret |= true;
01557             }
01558 
01559             // Otherwise, we don't need to do anything.
01560             //
01561         }
01562     }
01563     return ret;
01564 }
01565 
01566 FUNCTION(fun_orflags)
01567 {
01568     UNUSED_PARAMETER(caller);
01569     UNUSED_PARAMETER(enactor);
01570     UNUSED_PARAMETER(nfargs);
01571     UNUSED_PARAMETER(cargs);
01572     UNUSED_PARAMETER(ncargs);
01573 
01574     safe_bool(handle_flaglists(executor, fargs[0], fargs[1], false), buff, bufc);
01575 }
01576 
01577 FUNCTION(fun_andflags)
01578 {
01579     UNUSED_PARAMETER(caller);
01580     UNUSED_PARAMETER(enactor);
01581     UNUSED_PARAMETER(nfargs);
01582     UNUSED_PARAMETER(cargs);
01583     UNUSED_PARAMETER(ncargs);
01584 
01585     safe_bool(handle_flaglists(executor, fargs[0], fargs[1], true), buff, bufc);
01586 }
01587 
01588 FUNCTION(fun_strtrunc)
01589 {
01590     UNUSED_PARAMETER(executor);
01591     UNUSED_PARAMETER(caller);
01592     UNUSED_PARAMETER(enactor);
01593     UNUSED_PARAMETER(nfargs);
01594     UNUSED_PARAMETER(cargs);
01595     UNUSED_PARAMETER(ncargs);
01596 
01597     int maxVisualWidth = mux_atol(fargs[1]);
01598     if (maxVisualWidth < 0)
01599     {
01600         safe_range(buff, bufc);
01601         return;
01602     }
01603     if (maxVisualWidth == 0)
01604     {
01605         return;
01606     }
01607     int nVisualWidth;
01608     char buf[LBUF_SIZE+1];
01609     ANSI_TruncateToField(fargs[0], LBUF_SIZE, buf, maxVisualWidth, &nVisualWidth, ANSI_ENDGOAL_NORMAL);
01610     safe_str(buf, buff, bufc);
01611 }
01612 
01613 FUNCTION(fun_ifelse)
01614 {
01615     // This function assumes that its arguments have not been evaluated.
01616     //
01617     char *lbuff = alloc_lbuf("fun_ifelse");
01618     char *bp = lbuff;
01619     char *str = fargs[0];
01620     mux_exec(lbuff, &bp, executor, caller, enactor,
01621         EV_STRIP_CURLY | EV_FCHECK | EV_EVAL, &str, cargs, ncargs);
01622     *bp = '\0';
01623 
01624     if (!xlate(lbuff))
01625     {
01626         if (nfargs == 3)
01627         {
01628             str = fargs[2];
01629             mux_exec(buff, bufc, executor, caller, enactor,
01630                 EV_STRIP_CURLY | EV_FCHECK | EV_EVAL, &str, cargs, ncargs);
01631         }
01632     }
01633     else
01634     {
01635         str = fargs[1];
01636         mux_exec(buff, bufc, executor, caller, enactor,
01637             EV_STRIP_CURLY | EV_FCHECK | EV_EVAL, &str, cargs, ncargs);
01638     }
01639     free_lbuf(lbuff);
01640 }
01641 
01642 // Mail functions borrowed from DarkZone.
01643 //
01644 // This function can take one of three formats:
01645 //
01646 // 1. mail(num)           --> returns message <num> for privs.
01647 // 2. mail(executor)      --> returns number of messages for <executor>.
01648 // 3. mail(executor, num) --> returns message <num> for <executor>.
01649 // 4. mail()              --> returns number of messages for executor.
01650 //
01651 FUNCTION(fun_mail)
01652 {
01653     UNUSED_PARAMETER(caller);
01654     UNUSED_PARAMETER(enactor);
01655     UNUSED_PARAMETER(cargs);
01656     UNUSED_PARAMETER(ncargs);
01657 
01658     if (!mudconf.have_mailer)
01659     {
01660         safe_str("#-1 MAILER DISABLED.", buff, bufc);
01661         return;
01662     }
01663 
01664     dbref playerask;
01665     int num, rc, uc, cc;
01666 
01667     // Make sure we have the right number of arguments.
01668     //
01669     if (nfargs == 0 || !fargs[0] || !fargs[0][0])
01670     {
01671         count_mail(executor, 0, &rc, &uc, &cc);
01672         safe_ltoa(rc + uc, buff, bufc);
01673         return;
01674     }
01675     else if (nfargs == 1)
01676     {
01677         if (!is_integer(fargs[0], NULL))
01678         {
01679             // Handle the case of wanting to count the number of
01680             // messages.
01681             //
01682             playerask = lookup_player(executor, fargs[0], true);
01683             if (playerask == NOTHING)
01684             {
01685                 playerask = match_thing_quiet(executor, fargs[0]);
01686                 if (!isPlayer(playerask))
01687                 {
01688                     safe_str("#-1 NO SUCH PLAYER", buff, bufc);
01689                     return;
01690                 }
01691             }
01692             if (playerask == executor || Wizard(executor))
01693             {
01694                 count_mail(playerask, 0, &rc, &uc, &cc);
01695                 safe_tprintf_str(buff, bufc, "%d %d %d", rc, uc, cc);
01696             }
01697             else
01698             {
01699                 safe_noperm(buff, bufc);
01700             }
01701             return;
01702         }
01703         else
01704         {
01705             playerask = executor;
01706             num = mux_atol(fargs[0]);
01707         }
01708     }
01709     else // if (nfargs == 2)
01710     {
01711         playerask = lookup_player(executor, fargs[0], true);
01712         if (playerask == NOTHING)
01713         {
01714             safe_str("#-1 NO SUCH PLAYER", buff, bufc);
01715             return;
01716         }
01717         else if (  (playerask == executor && !mudstate.nObjEvalNest)
01718                 || God(executor))
01719         {
01720             num = mux_atol(fargs[1]);
01721         }
01722         else
01723         {
01724             safe_noperm(buff, bufc);
01725             return;
01726         }
01727     }
01728 
01729     if (  num < 1
01730        || !isPlayer(playerask))
01731     {
01732         safe_str("#-1 NO SUCH MESSAGE", buff, bufc);
01733         return;
01734     }
01735 
01736     const char *p = mail_fetch_message(playerask, num);
01737     if (p)
01738     {
01739         safe_str(p, buff, bufc);
01740         return;
01741     }
01742 
01743     // Ran off the end of the list without finding anything.
01744     //
01745     safe_str("#-1 NO SUCH MESSAGE", buff, bufc);
01746 }
01747 
01748 // This function can take these formats:
01749 //
01750 //  1) mailfrom(<num>)
01751 //  2) mailfrom(<executor>,<num>)
01752 //
01753 // It returns the dbref of the executor the mail is from.
01754 //
01755 FUNCTION(fun_mailfrom)
01756 {
01757     UNUSED_PARAMETER(caller);
01758     UNUSED_PARAMETER(enactor);
01759     UNUSED_PARAMETER(cargs);
01760     UNUSED_PARAMETER(ncargs);
01761 
01762     if (!mudconf.have_mailer)
01763     {
01764         safe_str("#-1 MAILER DISABLED.", buff, bufc);
01765         return;
01766     }
01767 
01768     // Make sure we have the right number of arguments.
01769     //
01770     int num;
01771     dbref playerask;
01772     if (nfargs == 1)
01773     {
01774         playerask = executor;
01775         num = mux_atol(fargs[0]);
01776     }
01777     else // if (nfargs == 2)
01778     {
01779         playerask = lookup_player(executor, fargs[0], true);
01780         if (playerask == NOTHING)
01781         {
01782             safe_str("#-1 NO SUCH PLAYER", buff, bufc);
01783             return;
01784         }
01785         if (  playerask == executor
01786            || Wizard(executor))
01787         {
01788             num = mux_atol(fargs[1]);
01789         }
01790         else
01791         {
01792             safe_noperm(buff, bufc);
01793             return;
01794         }
01795     }
01796 
01797     if (  num < 1
01798        || !isPlayer(playerask))
01799     {
01800         safe_str("#-1 NO SUCH MESSAGE", buff, bufc);
01801         return;
01802     }
01803 
01804     int from = mail_fetch_from(playerask, num);
01805     if (NOTHING != from)
01806     {
01807         safe_tprintf_str(buff, bufc, "#%d", from);
01808         return;
01809     }
01810 
01811     // Ran off the end of the list without finding anything.
01812     //
01813     safe_str("#-1 NO SUCH MESSAGE", buff, bufc);
01814 }
01815 
01816 // ---------------------------------------------------------------------------
01817 // fun_hasattr: does object X have attribute Y.
01818 // Hasattr (and hasattrp, which is derived from hasattr) borrowed from
01819 // TinyMUSH 2.2.
01820 
01821 static void hasattr_handler(char *buff, char **bufc, dbref executor, char *fargs[],
01822                    bool bCheckParent)
01823 {
01824     dbref thing = match_thing_quiet(executor, fargs[0]);
01825     if (!Good_obj(thing))
01826     {
01827         safe_match_result(thing, buff, bufc);
01828         return;
01829     }
01830 
01831     ATTR *pattr = atr_str(fargs[1]);
01832     bool result = false;
01833     if (pattr)
01834     {
01835         if (!bCanReadAttr(executor, thing, pattr, bCheckParent))
01836         {
01837             safe_noperm(buff, bufc);
01838             return;
01839         }
01840         else
01841         {
01842             if (bCheckParent)
01843             {
01844                 dbref aowner;
01845                 int aflags;
01846                 char *tbuf = atr_pget(thing, pattr->number, &aowner, &aflags);
01847                 result = (tbuf[0] != '\0');
01848                 free_lbuf(tbuf);
01849             }
01850             else
01851             {
01852                 const char *tbuf = atr_get_raw(thing, pattr->number);
01853                 result = (tbuf != NULL);
01854             }
01855         }
01856     }
01857     safe_bool(result, buff, bufc);
01858 }
01859 
01860 FUNCTION(fun_hasattr)
01861 {
01862     UNUSED_PARAMETER(caller);
01863     UNUSED_PARAMETER(enactor);
01864     UNUSED_PARAMETER(nfargs);
01865     UNUSED_PARAMETER(cargs);
01866     UNUSED_PARAMETER(ncargs);
01867 
01868     hasattr_handler(buff, bufc, executor, fargs, false);
01869 }
01870 
01871 FUNCTION(fun_hasattrp)
01872 {
01873     UNUSED_PARAMETER(caller);
01874     UNUSED_PARAMETER(enactor);
01875     UNUSED_PARAMETER(nfargs);
01876     UNUSED_PARAMETER(cargs);
01877     UNUSED_PARAMETER(ncargs);
01878 
01879     hasattr_handler(buff, bufc, executor, fargs, true);
01880 }
01881 
01882 /* ---------------------------------------------------------------------------
01883  * fun_default, fun_edefault, and fun_udefault:
01884  * These check for the presence of an attribute. If it exists, then it
01885  * is gotten, via the equivalent of get(), get_eval(), or u(), respectively.
01886  * Otherwise, the default message is used.
01887  * In the case of udefault(), the remaining arguments to the function
01888  * are used as arguments to the u().
01889  */
01890 
01891 // default(), edefault(), and udefault() borrowed from TinyMUSH 2.2
01892 //
01893 #define DEFAULT_DEFAULT  1
01894 #define DEFAULT_EDEFAULT 2
01895 #define DEFAULT_UDEFAULT 4
01896 
01897 static void default_handler(char *buff, char **bufc, dbref executor, dbref caller, dbref enactor,
01898                      char *fargs[], int nfargs, char *cargs[], int ncargs, int key)
01899 {
01900     // Evaluating the first argument.
01901     //
01902     char *objattr = alloc_lbuf("default_handler");
01903     char *bp = objattr;
01904     char *str = fargs[0];
01905     mux_exec(objattr, &bp, executor, caller, enactor,
01906              EV_EVAL | EV_STRIP_CURLY | EV_FCHECK, &str, cargs, ncargs);
01907     *bp = '\0';
01908 
01909     // Parse the first argument as either <dbref>/<attrname> or <attrname>.
01910     //
01911     dbref thing;
01912     ATTR *pattr;
01913 
01914     if (!parse_attrib(executor, objattr, &thing, &pattr))
01915     {
01916         thing = executor;
01917         pattr = atr_str(objattr);
01918     }
01919     free_lbuf(objattr);
01920 
01921     if (  pattr
01922        && See_attr(executor, thing, pattr))
01923     {
01924         dbref aowner;
01925         int   aflags;
01926         char *atr_gotten = atr_pget(thing, pattr->number, &aowner, &aflags);
01927         if (atr_gotten[0] != '\0')
01928         {
01929             switch (key)
01930             {
01931             case DEFAULT_DEFAULT:
01932                 safe_str(atr_gotten, buff, bufc);
01933                 break;
01934 
01935             case DEFAULT_EDEFAULT:
01936                 str = atr_gotten;
01937                 mux_exec(buff, bufc, thing, executor, executor,
01938                      EV_FIGNORE | EV_EVAL, &str, (char **)NULL, 0);
01939                 break;
01940 
01941             case DEFAULT_UDEFAULT:
01942                 {
01943                     char *xargs[MAX_ARG];
01944                     int  nxargs = nfargs-2;
01945                     int  i;
01946                     for (i = 0; i < nxargs; i++)
01947                     {
01948                         xargs[i] = alloc_lbuf("fun_udefault_args");
01949                         char *bp2 = xargs[i];
01950                         str = fargs[i+2];
01951 
01952                         mux_exec(xargs[i], &bp2,
01953                             thing, caller, enactor,
01954                             EV_TOP | EV_STRIP_CURLY | EV_FCHECK | EV_EVAL,
01955                             &str, cargs, ncargs);
01956                         *bp2 = '\0';
01957                     }
01958 
01959                     str = atr_gotten;
01960                     mux_exec(buff, bufc, thing, caller, enactor,
01961                         EV_FCHECK | EV_EVAL, &str, xargs, nxargs);
01962 
01963                     for (i = 0; i < nxargs; i++)
01964                     {
01965                         free_lbuf(xargs[i]);
01966                     }
01967                 }
01968                 break;
01969 
01970             }
01971             free_lbuf(atr_gotten);
01972             return;
01973         }
01974         free_lbuf(atr_gotten);
01975     }
01976 
01977     // If we've hit this point, we've not gotten anything useful, so
01978     // we go and evaluate the default.
01979     //
01980     str = fargs[1];
01981     mux_exec(buff, bufc, executor, caller, enactor,
01982              EV_EVAL | EV_STRIP_CURLY | EV_FCHECK, &str, cargs, ncargs);
01983 }
01984 
01985 
01986 FUNCTION(fun_default)
01987 {
01988     default_handler(buff, bufc, executor, caller, enactor, fargs, nfargs, cargs,
01989         ncargs, DEFAULT_DEFAULT);
01990 }
01991 
01992 FUNCTION(fun_edefault)
01993 {
01994     default_handler(buff, bufc, executor, caller, enactor, fargs, nfargs, cargs,
01995         ncargs, DEFAULT_EDEFAULT);
01996 }
01997 
01998 FUNCTION(fun_udefault)
01999 {
02000     default_handler(buff, bufc, executor, caller, enactor, fargs, nfargs, cargs,
02001         ncargs, DEFAULT_UDEFAULT);
02002 }
02003 
02004 /* ---------------------------------------------------------------------------
02005  * fun_findable: can X locate Y
02006  * Borrowed from PennMUSH 1.50
02007  */
02008 FUNCTION(fun_findable)
02009 {
02010     UNUSED_PARAMETER(caller);
02011     UNUSED_PARAMETER(enactor);
02012     UNUSED_PARAMETER(nfargs);
02013     UNUSED_PARAMETER(cargs);
02014     UNUSED_PARAMETER(ncargs);
02015 
02016     dbref obj = match_thing_quiet(executor, fargs[0]);
02017     if (!Good_obj(obj))
02018     {
02019         safe_match_result(obj, buff, bufc);
02020         safe_str(" (ARG1)", buff, bufc);
02021         return;
02022     }
02023     dbref victim = match_thing_quiet(executor, fargs[1]);
02024     if (!Good_obj(victim))
02025     {
02026         safe_match_result(victim, buff, bufc);
02027         safe_str(" (ARG2)", buff, bufc);
02028         return;
02029     }
02030 #ifndef WOD_REALMS
02031 #ifndef REALITY_LVLS
02032     safe_bool(locatable(obj, victim, obj), buff, bufc);
02033 #else
02034     if (IsReal(obj, victim))
02035     {
02036         safe_bool(locatable(obj, victim, obj), buff, bufc);
02037     }
02038     else safe_chr('0', buff, bufc);
02039 #endif
02040 #else
02041 #ifndef REALITY_LVLS
02042     if (REALM_DO_HIDDEN_FROM_YOU != DoThingToThingVisibility(obj, victim, ACTION_IS_STATIONARY))
02043     {
02044         safe_bool(locatable(obj, victim, obj), buff, bufc);
02045     }
02046     else
02047     {
02048         safe_chr('0', buff, bufc);
02049     }
02050 
02051 #else
02052     if (REALM_DO_HIDDEN_FROM_YOU != DoThingToThingVisibility(obj, victim, ACTION_IS_STATIONARY))
02053     {
02054         safe_bool(locatable(obj, victim, obj), buff, bufc);
02055     }
02056     else if (IsReal(obj, victim))
02057     {
02058         safe_bool(locatable(obj, victim, obj), buff, bufc);
02059     }
02060     else safe_chr('0', buff, bufc);
02061 #endif
02062 #endif
02063 }
02064 
02065 /* ---------------------------------------------------------------------------
02066  * isword: is every character in the argument a letter?
02067  * Borrowed from PennMUSH 1.50
02068  */
02069 FUNCTION(fun_isword)
02070 {
02071     UNUSED_PARAMETER(executor);
02072     UNUSED_PARAMETER(caller);
02073     UNUSED_PARAMETER(enactor);
02074     UNUSED_PARAMETER(nfargs);
02075     UNUSED_PARAMETER(cargs);
02076     UNUSED_PARAMETER(ncargs);
02077 
02078     char *p;
02079     bool result = true;
02080 
02081     for (p = fargs[0]; *p; p++)
02082     {
02083         if (!mux_isalpha(*p))
02084         {
02085             result = false;
02086             break;
02087         }
02088     }
02089     safe_bool(result, buff, bufc);
02090 }
02091 
02092 /* ---------------------------------------------------------------------------
02093  * fun_visible. Borrowed from PennMUSH 1.50
02094  */
02095 FUNCTION(fun_visible)
02096 {
02097     UNUSED_PARAMETER(caller);
02098     UNUSED_PARAMETER(enactor);
02099     UNUSED_PARAMETER(nfargs);
02100     UNUSED_PARAMETER(cargs);
02101     UNUSED_PARAMETER(ncargs);
02102 
02103     dbref it = match_thing_quiet(executor, fargs[0]);
02104     if (!Good_obj(it))
02105     {
02106         safe_match_result(it, buff, bufc);
02107         safe_str(" (ARG1)", buff, bufc);
02108         return;
02109     }
02110     else if (!Controls(executor, it))
02111     {
02112         safe_noperm(buff, bufc);
02113         return;
02114     }
02115 
02116     bool  result = false;
02117     dbref thing;
02118     ATTR  *pattr;
02119     if (!parse_attrib(executor, fargs[1], &thing, &pattr))
02120     {
02121         thing = match_thing_quiet(executor, fargs[1]);
02122         if (!Good_obj(thing))
02123         {
02124             safe_match_result(thing, buff, bufc);
02125             safe_str(" (ARG2)", buff, bufc);
02126             return;
02127         }
02128     }
02129     if (Good_obj(thing))
02130     {
02131         if (pattr)
02132         {
02133             result = (See_attr(it, thing, pattr));
02134         }
02135         else
02136         {
02137             result = (Examinable(it, thing));
02138         }
02139     }
02140     safe_bool(result, buff, bufc);
02141 }
02142 
02143 /* ---------------------------------------------------------------------------
02144  * fun_elements: given a list of numbers, get corresponding elements from
02145  * the list.  elements(ack bar eep foof yay,2 4) ==> bar foof
02146  * The function takes a separator, but the separator only applies to the
02147  * first list.
02148  * Borrowed from PennMUSH 1.50
02149  */
02150 FUNCTION(fun_elements)
02151 {
02152     SEP sep;
02153     if (!OPTIONAL_DELIM(3, sep, DELIM_DFLT|DELIM_STRING))
02154     {
02155         return;
02156     }
02157 
02158     SEP osep = sep;
02159     if (!OPTIONAL_DELIM(4, osep, DELIM_NULL|DELIM_CRLF|DELIM_STRING|DELIM_INIT))
02160     {
02161         return;
02162     }
02163 
02164     int nwords, cur;
02165     char *ptrs[LBUF_SIZE / 2];
02166     char *wordlist, *s, *r;
02167     bool bFirst = true;
02168 
02169     // Turn the first list into an array.
02170     //
02171     wordlist = alloc_lbuf("fun_elements.wordlist");
02172     strcpy(wordlist, fargs[0]);
02173     nwords = list2arr(ptrs, LBUF_SIZE / 2, wordlist, &sep);
02174 
02175     s = trim_space_sep(fargs[1], &sepSpace);
02176 
02177     // Go through the second list, grabbing the numbers and finding the
02178     // corresponding elements.
02179     //
02180     do {
02181         r = split_token(&s, &sepSpace);
02182         cur = mux_atol(r) - 1;
02183         if (  cur >= 0
02184            && cur < nwords
02185            && ptrs[cur])
02186         {
02187             if (!bFirst)
02188             {
02189                 print_sep(&osep, buff, bufc);
02190             }
02191             else
02192             {
02193                 bFirst = false;
02194             }
02195             safe_str(ptrs[cur], buff, bufc);
02196         }
02197     } while (s);
02198     free_lbuf(wordlist);
02199 }
02200 
02201 /* ---------------------------------------------------------------------------
02202  * fun_grab: a combination of extract() and match(), sortof. We grab the
02203  *           single element that we match.
02204  *
02205  *  grab(Test:1 Ack:2 Foof:3,*:2)    => Ack:2
02206  *  grab(Test-1+Ack-2+Foof-3,*o*,+)  => Foof-3
02207  * Borrowed from PennMUSH 1.50
02208  */
02209 FUNCTION(fun_grab)
02210 {
02211     SEP sep;
02212     if (!OPTIONAL_DELIM(3, sep, DELIM_DFLT|DELIM_STRING))
02213     {
02214         return;
02215     }
02216 
02217     // Walk the wordstring, until we find the word we want.
02218     //
02219     char *s = trim_space_sep(fargs[0], &sep);
02220     do
02221     {
02222         char *r = split_token(&s, &sep);
02223         mudstate.wild_invk_ctr = 0;
02224         if (quick_wild(fargs[1], r))
02225         {
02226             safe_str(r, buff, bufc);
02227             return;
02228         }
02229     } while (s);
02230 }
02231 
02232 FUNCTION(fun_graball)
02233 {
02234     SEP sep;
02235     if (!OPTIONAL_DELIM(3, sep, DELIM_DFLT|DELIM_STRING))
02236     {
02237         return;
02238     }
02239     SEP osep = sep;
02240     if (!OPTIONAL_DELIM(4, osep, DELIM_NULL|DELIM_CRLF|DELIM_STRING|DELIM_INIT))
02241     {
02242         return;
02243     }
02244 
02245     bool bFirst = true;
02246     char *s = trim_space_sep(fargs[0], &sep);
02247     do
02248     {
02249         char *r = split_token(&s, &sep);
02250         mudstate.wild_invk_ctr = 0;
02251         if (quick_wild(fargs[1], r))
02252         {
02253             if (!bFirst)
02254             {
02255                 print_sep(&osep, buff, bufc);
02256             }
02257             else
02258             {
02259                 bFirst = false;
02260             }
02261             safe_str(r, buff, bufc);
02262         }
02263     } while (s);
02264 }
02265 
02266 /* ---------------------------------------------------------------------------
02267  * fun_scramble:  randomizes the letters in a string.
02268  * Borrowed from PennMUSH 1.50
02269  */
02270 FUNCTION(fun_scramble)
02271 {
02272     UNUSED_PARAMETER(executor);
02273     UNUSED_PARAMETER(caller);
02274     UNUSED_PARAMETER(enactor);
02275     UNUSED_PARAMETER(nfargs);
02276     UNUSED_PARAMETER(cargs);
02277     UNUSED_PARAMETER(ncargs);
02278 
02279     size_t n;
02280     char *old = strip_ansi(fargs[0], &n);
02281 
02282     if (2 <= n)
02283     {
02284         unsigned int i;
02285         for (i = 0; i < n-1; i++)
02286         {
02287             int j = RandomINT32(i, n-1);
02288             char c = old[i];
02289             old[i] = old[j];
02290             old[j] = c;
02291         }
02292     }
02293     safe_str(old, buff, bufc);
02294 }
02295 
02296 /* ---------------------------------------------------------------------------
02297  * fun_shuffle: randomize order of words in a list.
02298  * Borrowed from PennMUSH 1.50
02299  */
02300 FUNCTION(fun_shuffle)
02301 {
02302     SEP sep;
02303     if (!OPTIONAL_DELIM(2, sep, DELIM_DFLT|DELIM_STRING))
02304     {
02305         return;
02306     }
02307 
02308     SEP osep = sep;
02309     if (!OPTIONAL_DELIM(3, osep, DELIM_NULL|DELIM_CRLF|DELIM_STRING|DELIM_INIT))
02310     {
02311         return;
02312     }
02313 
02314     char *words[LBUF_SIZE];
02315     int n, i, j;
02316 
02317     n = list2arr(words, LBUF_SIZE, fargs[0], &sep);
02318 
02319     for (i = 0; i < n-1; i++)
02320     {
02321         j = RandomINT32(i, n-1);
02322 
02323         // Swap words[i] with words[j]
02324         //
02325         char *temp = words[i];
02326         words[i] = words[j];
02327         words[j] = temp;
02328     }
02329     arr2list(words, n, buff, bufc, &osep);
02330 }
02331 
02332 // pickrand -- choose a random item from a list.
02333 //
02334 FUNCTION(fun_pickrand)
02335 {
02336     if (  nfargs == 0
02337        || fargs[0][0] == '\0')
02338     {
02339         return;
02340     }
02341 
02342     SEP sep;
02343     if (!OPTIONAL_DELIM(2, sep, DELIM_DFLT|DELIM_STRING))
02344     {
02345         return;
02346     }
02347 
02348     char *s = trim_space_sep(fargs[0], &sep);
02349     char *t = s;
02350     if (s[0] == '\0')
02351     {
02352         return;
02353     }
02354     INT32 n;
02355     for (n = 0; t; t = next_token(t, &sep), n++)
02356     {
02357         ; // Nothing
02358     }
02359 
02360     if (n >= 1)
02361     {
02362         INT32 w = RandomINT32(0, n-1);
02363         for (n = 0; n < w; n++)
02364         {
02365             s = next_token(s, &sep);
02366         }
02367         t = split_token(&s, &sep);
02368         safe_str(t, buff, bufc);
02369     }
02370 }
02371 
02372 // sortby() code borrowed from TinyMUSH 2.2
02373 //
02374 static char  ucomp_buff[LBUF_SIZE];
02375 static dbref ucomp_executor;
02376 static dbref ucomp_caller;
02377 static dbref ucomp_enactor;
02378 
02379 static int u_comp(const void *s1, const void *s2)
02380 {
02381     // Note that this function is for use in conjunction with our own
02382     // sane_qsort routine, NOT with the standard library qsort!
02383     //
02384     char *result, *tbuf, *elems[2], *bp, *str;
02385     int n;
02386 
02387     if (  mudstate.func_invk_ctr > mudconf.func_invk_lim
02388        || mudstate.func_nest_lev > mudconf.func_nest_lim
02389        || MuxAlarm.bAlarmed)
02390     {
02391         return 0;
02392     }
02393 
02394     tbuf = alloc_lbuf("u_comp");
02395     elems[0] = (char *)s1;
02396     elems[1] = (char *)s2;
02397     strcpy(tbuf, ucomp_buff);
02398     result = bp = alloc_lbuf("u_comp");
02399     str = tbuf;
02400     mux_exec(result, &bp, ucomp_executor, ucomp_caller, ucomp_enactor,
02401              EV_STRIP_CURLY | EV_FCHECK | EV_EVAL, &str, &(elems[0]), 2);
02402     *bp = '\0';
02403     if (!result)
02404     {
02405         n = 0;
02406     }
02407     else
02408     {
02409         n = mux_atol(result);
02410         free_lbuf(result);
02411     }
02412     free_lbuf(tbuf);
02413     return n;
02414 }
02415 
02416 typedef int PV(const void *, const void *);
02417 
02418 static void sane_qsort(void *array[], int left, int right, PV compare)
02419 {
02420     // Andrew Molitor's qsort, which doesn't require transitivity between
02421     // comparisons (essential for preventing crashes due to boneheads
02422     // who write comparison functions where a > b doesn't mean b < a).
02423     //
02424     int i, last;
02425     void *tmp;
02426 
02427 loop:
02428 
02429     if (left >= right)
02430     {
02431         return;
02432     }
02433 
02434     // Pick something at random at swap it into the leftmost slot
02435     // This is the pivot, we'll put it back in the right spot later.
02436     //
02437     i = RandomINT32(0, right - left);
02438     tmp = array[left + i];
02439     array[left + i] = array[left];
02440     array[left] = tmp;
02441 
02442     last = left;
02443     for (i = left + 1; i <= right; i++) {
02444 
02445         // Walk the array, looking for stuff that's less than our
02446         // pivot. If it is, swap it with the next thing along
02447         //
02448         if ((*compare) (array[i], array[left]) < 0)
02449         {
02450             last++;
02451             if (last == i)
02452             {
02453                 continue;
02454             }
02455 
02456             tmp = array[last];
02457             array[last] = array[i];
02458             array[i] = tmp;
02459         }
02460     }
02461 
02462     // Now we put the pivot back, it's now in the right spot, we never
02463     // need to look at it again, trust me.
02464     //
02465     tmp = array[last];
02466     array[last] = array[left];
02467     array[left] = tmp;
02468 
02469     // At this point everything underneath the 'last' index is < the
02470     // entry at 'last' and everything above it is not < it.
02471     //
02472     if ((last - left) < (right - last))
02473     {
02474         sane_qsort(array, left, last - 1, compare);
02475         left = last + 1;
02476         goto loop;
02477     }
02478     else
02479     {
02480         sane_qsort(array, last + 1, right, compare);
02481         right = last - 1;
02482         goto loop;
02483     }
02484 }
02485 
02486 FUNCTION(fun_sortby)
02487 {
02488     SEP sep;
02489     if (!OPTIONAL_DELIM(3, sep, DELIM_DFLT|DELIM_STRING))
02490     {
02491         return;
02492     }
02493 
02494     SEP osep = sep;
02495     if (!OPTIONAL_DELIM(4, osep, DELIM_NULL|DELIM_CRLF|DELIM_STRING|DELIM_INIT))
02496     {
02497         return;
02498     }
02499 
02500     char *atext;
02501     dbref thing;
02502     if (!parse_and_get_attrib(executor, fargs, &atext, &thing, buff, bufc))
02503     {
02504         return;
02505     }
02506 
02507     strcpy(ucomp_buff, atext);
02508     ucomp_executor = thing;
02509     ucomp_caller   = executor;
02510     ucomp_enactor  = enactor;
02511 
02512     char *list = alloc_lbuf("fun_sortby");
02513     strcpy(list, fargs[1]);
02514     char *ptrs[LBUF_SIZE / 2];
02515     int nptrs = list2arr(ptrs, LBUF_SIZE / 2, list, &sep);
02516 
02517     if (nptrs > 1)
02518     {
02519         sane_qsort((void **)ptrs, 0, nptrs - 1, u_comp);
02520     }
02521 
02522     arr2list(ptrs, nptrs, buff, bufc, &osep);
02523     free_lbuf(list);
02524     free_lbuf(atext);
02525 }
02526 
02527 // fun_last: Returns last word in a string. Borrowed from TinyMUSH 2.2.
02528 //
02529 FUNCTION(fun_last)
02530 {
02531     // If we are passed an empty arglist return a null string.
02532     //
02533     if (nfargs == 0)
02534     {
02535         return;
02536     }
02537 
02538     SEP sep;
02539     if (!OPTIONAL_DELIM(2, sep, DELIM_DFLT|DELIM_STRING))
02540     {
02541         return;
02542     }
02543 
02544     char *str;
02545     char *lstr = trim_space_sep(fargs[0], &sep);
02546     while (NULL != (str = next_token(lstr, &sep)))
02547     {
02548         lstr = str;
02549     }
02550     safe_str(lstr, buff, bufc);
02551 }
02552 
02553 // Borrowed from TinyMUSH 2.2
02554 //
02555 FUNCTION(fun_matchall)
02556 {
02557     SEP sep;
02558     if (!OPTIONAL_DELIM(3, sep, DELIM_DFLT|DELIM_STRING))
02559     {
02560         return;
02561     }
02562 
02563     int wcount;
02564     char *r, *s, *old, tbuf[8];
02565     old = *bufc;
02566 
02567     // Check each word individually, returning the word number of all that
02568     // match. If none match, return 0.
02569     //
02570     wcount = 1;
02571     s = trim_space_sep(fargs[0], &sep);
02572     do
02573     {
02574         r = split_token(&s, &sep);
02575         mudstate.wild_invk_ctr = 0;
02576         if (quick_wild(fargs[1], r))
02577         {
02578             mux_ltoa(wcount, tbuf);
02579             if (old != *bufc)
02580             {
02581                 safe_chr(' ', buff, bufc);
02582             }
02583             safe_str(tbuf, buff, bufc);
02584         }
02585         wcount++;
02586     } while (s);
02587 
02588     if (*bufc == old)
02589     {
02590         safe_chr('0', buff, bufc);
02591     }
02592 }
02593 
02594 // ---------------------------------------------------------------------------
02595 // fun_ports: Returns a list of ports for a user.
02596 // Borrowed from TinyMUSH 2.2
02597 //
02598 FUNCTION(fun_ports)
02599 {
02600     UNUSED_PARAMETER(caller);
02601     UNUSED_PARAMETER(enactor);
02602     UNUSED_PARAMETER(nfargs);
02603     UNUSED_PARAMETER(cargs);
02604     UNUSED_PARAMETER(ncargs);
02605 
02606     dbref target = lookup_player(executor, fargs[0], true);
02607     if (Good_obj(target))
02608     {
02609         if (target == executor || Wizard(executor))
02610         {
02611             if (Connected(target))
02612             {
02613                 make_portlist(executor, target, buff, bufc);
02614             }
02615         }
02616         else
02617         {
02618             safe_noperm(buff, bufc);
02619         }
02620     }
02621     else
02622     {
02623         safe_nomatch(buff, bufc);
02624     }
02625 }
02626 
02627 /* ---------------------------------------------------------------------------
02628  * fun_mix: Like map, but operates on up to ten lists simultaneously, passing
02629  * the elements as %0 - %10.
02630  * Borrowed from PennMUSH 1.50, upgraded by RhostMUSH.
02631  */
02632 FUNCTION(fun_mix)
02633 {
02634     // Check to see if we have an appropriate number of arguments.
02635     // If there are more than three arguments, the last argument is
02636     // ALWAYS assumed to be a delimiter.
02637     //
02638     SEP sep;
02639     int lastn;
02640 
02641     if (nfargs < 4)
02642     {
02643         sep.n = 1;
02644         sep.str[0] = ' ';
02645         sep.str[1] = '\0';
02646         lastn = nfargs - 1;
02647     }
02648     else if (!OPTIONAL_DELIM(nfargs, sep, DELIM_DFLT|DELIM_STRING))
02649     {
02650         return;
02651     }
02652     else
02653     {
02654         lastn = nfargs - 2;
02655     }
02656 
02657     // Get the attribute, check the permissions.
02658     //
02659     dbref thing;
02660     char *atext;
02661     if (!parse_and_get_attrib(executor, fargs, &atext, &thing, buff, bufc))
02662     {
02663         return;
02664     }
02665 
02666     char *cp[10];
02667     int i;
02668     for (i = 0; i < lastn; i++)
02669     {
02670         cp[i] = NULL;
02671     }
02672 
02673     // Process the lists, one element at a time.
02674     //
02675     for (i = 0; i < lastn; i++)
02676     {
02677         cp[i] = trim_space_sep(fargs[i+1], &sep);
02678     }
02679     int twords;
02680     int nwords = countwords(cp[0], &sep);
02681     for (i = 1; i < lastn; i++)
02682     {
02683         twords = countwords(cp[i], &sep);
02684         if (twords > nwords)
02685         {
02686            nwords = twords;
02687         }
02688     }
02689     char *atextbuf = alloc_lbuf("fun_mix");
02690     char *str, *os[10];
02691     bool bFirst = true;
02692     for (int wc = 0; wc < nwords && mudstate.func_invk_ctr < mudconf.func_invk_lim && !MuxAlarm.bAlarmed; wc++)
02693     {
02694         if (!bFirst)
02695         {
02696             print_sep(&sep, buff, bufc);
02697         }
02698         else
02699         {
02700             bFirst = false;
02701         }
02702         for (i = 0; i < lastn; i++)
02703         {
02704             os[i] = split_token(&cp[i], &sep);
02705         }
02706         strcpy(atextbuf, atext);
02707         str = atextbuf;
02708         mux_exec(buff, bufc, thing, executor, enactor,
02709             EV_STRIP_CURLY | EV_FCHECK | EV_EVAL, &str, &(os[0]), lastn);
02710     }
02711     free_lbuf(atext);
02712     free_lbuf(atextbuf);
02713 }
02714 
02715 /* ---------------------------------------------------------------------------
02716  * fun_foreach: like map(), but it operates on a string, rather than on a list,
02717  * calling a user-defined function for each character in the string.
02718  * No delimiter is inserted between the results.
02719  * Borrowed from TinyMUSH 2.2
02720  */
02721 FUNCTION(fun_foreach)
02722 {
02723     UNUSED_PARAMETER(caller);
02724     UNUSED_PARAMETER(enactor);
02725     UNUSED_PARAMETER(cargs);
02726     UNUSED_PARAMETER(ncargs);
02727 
02728     if (  nfargs != 2
02729        && nfargs != 4)
02730     {
02731         safe_str("#-1 FUNCTION (FOREACH) EXPECTS 2 OR 4 ARGUMENTS", buff, bufc);
02732         return;
02733     }
02734 
02735     char *atext;
02736     dbref thing;
02737     if (!parse_and_get_attrib(executor, fargs, &atext, &thing, buff, bufc))
02738     {
02739         return;
02740     }
02741 
02742     char *str;
02743     char cbuf[2], prev = '\0';
02744     char *atextbuf = alloc_lbuf("fun_foreach");
02745     SEP sep;
02746     sep.n = 1;
02747     sep.str[0] = ' ';
02748     sep.str[1] = '\0';
02749     char *cp = trim_space_sep(fargs[1], &sep);
02750 
02751     char *bp = cbuf;
02752 
02753     cbuf[1] = '\0';
02754 
02755     if (nfargs == 4)
02756     {
02757         bool flag = false;
02758         while (  cp
02759               && *cp
02760               && mudstate.func_invk_ctr < mudconf.func_invk_lim
02761               && !MuxAlarm.bAlarmed)
02762         {
02763             cbuf[0] = *cp++;
02764 
02765             if (flag)
02766             {
02767                 if (  cbuf[0] == *fargs[3]
02768                    && prev != '\\'
02769                    && prev != '%')
02770                 {
02771                     flag = false;
02772                     continue;
02773                 }
02774             }
02775             else
02776             {
02777                 if (  cbuf[0] == *fargs[2]
02778                    && prev != '\\'
02779                    && prev != '%')
02780                 {
02781                     flag = true;
02782                     continue;
02783                 }
02784                 else
02785                 {
02786                     safe_chr(cbuf[0], buff, bufc);
02787                     continue;
02788                 }
02789             }
02790 
02791             strcpy(atextbuf, atext);
02792             str = atextbuf;
02793             mux_exec(buff, bufc, thing, executor, enactor,
02794                 EV_STRIP_CURLY | EV_FCHECK | EV_EVAL, &str, &bp, 1);
02795             prev = cbuf[0];
02796         }
02797     }
02798     else
02799     {
02800         while (  cp
02801               && *cp
02802               && mudstate.func_invk_ctr < mudconf.func_invk_lim
02803               && !MuxAlarm.bAlarmed)
02804         {
02805             cbuf[0] = *cp++;
02806 
02807             strcpy(atextbuf, atext);
02808             str = atextbuf;
02809             mux_exec(buff, bufc, thing, executor, enactor,
02810                 EV_STRIP_CURLY | EV_FCHECK | EV_EVAL, &str, &bp, 1);
02811         }
02812     }
02813     free_lbuf(atextbuf);
02814     free_lbuf(atext);
02815 }
02816 
02817 /* ---------------------------------------------------------------------------
02818  * fun_munge: combines two lists in an arbitrary manner.
02819  * Borrowed from TinyMUSH 2.2
02820  */
02821 FUNCTION(fun_munge)
02822 {
02823     SEP sep;
02824     if (!OPTIONAL_DELIM(4, sep, DELIM_DFLT|DELIM_STRING))
02825     {
02826         return;
02827     }
02828 
02829     // Find our object and attribute.
02830     //
02831     char *atext;
02832     dbref thing;
02833     if (!parse_and_get_attrib(executor, fargs, &atext, &thing, buff, bufc))
02834     {
02835         return;
02836     }
02837 
02838     int nptrs1, nptrs2, nresults, i, j;
02839     char *list1, *list2, *rlist, *bp, *str;
02840     char *ptrs1[LBUF_SIZE / 2], *ptrs2[LBUF_SIZE / 2], *results[LBUF_SIZE / 2];
02841     char *uargs[2];
02842 
02843     // Copy our lists and chop them up.
02844     //
02845     list1 = alloc_lbuf("fun_munge.list1");
02846     list2 = alloc_lbuf("fun_munge.list2");
02847     strcpy(list1, fargs[1]);
02848     strcpy(list2, fargs[2]);
02849     nptrs1 = list2arr(ptrs1, LBUF_SIZE / 2, list1, &sep);
02850     nptrs2 = list2arr(ptrs2, LBUF_SIZE / 2, list2, &sep);
02851 
02852     if (nptrs1 != nptrs2)
02853     {
02854         safe_str("#-1 LISTS MUST BE OF EQUAL SIZE", buff, bufc);
02855         free_lbuf(atext);
02856         free_lbuf(list1);
02857         free_lbuf(list2);
02858         return;
02859     }
02860 
02861     // Call the u-function with the first list as %0.
02862     //
02863     bp = rlist = alloc_lbuf("fun_munge");
02864     str = atext;
02865     uargs[0] = fargs[1];
02866     uargs[1] = sep.str;
02867     mux_exec(rlist, &bp, executor, caller, enactor,
02868              EV_STRIP_CURLY | EV_FCHECK | EV_EVAL, &str, uargs, 2);
02869     *bp = '\0';
02870 
02871     // Now that we have our result, put it back into array form.
02872     // Search through list1 until we find the element position, then
02873     // copy the corresponding element from list2.
02874     //
02875     nresults = list2arr(results, LBUF_SIZE / 2, rlist, &sep);
02876 
02877     bool bFirst = true;
02878     for (i = 0; i < nresults; i++)
02879     {
02880         for (j = 0; j < nptrs1; j++)
02881         {
02882             if (!strcmp(results[i], ptrs1[j]))
02883             {
02884                 if (!bFirst)
02885                 {
02886                     print_sep(&sep, buff, bufc);
02887                 }
02888                 else
02889                 {
02890                     bFirst = false;
02891                 }
02892                 safe_str(ptrs2[j], buff, bufc);
02893                 ptrs1[j][0] = '\0';
02894                 break;
02895             }
02896         }
02897     }
02898     free_lbuf(atext);
02899     free_lbuf(list1);
02900     free_lbuf(list2);
02901     free_lbuf(rlist);
02902 }
02903 
02904 FUNCTION(fun_die)
02905 {
02906     UNUSED_PARAMETER(executor);
02907     UNUSED_PARAMETER(caller);
02908     UNUSED_PARAMETER(enactor);
02909     UNUSED_PARAMETER(cargs);
02910     UNUSED_PARAMETER(ncargs);
02911 
02912     int n   = mux_atol(fargs[0]);
02913     int die = mux_atol(fargs[1]);
02914 
02915     if (  n == 0
02916        || die <= 0)
02917     {
02918         safe_chr('0', buff, bufc);
02919         return;
02920     }
02921 
02922     if (  n < 1
02923        || LBUF_SIZE <= n)
02924     {
02925         safe_range(buff, bufc);
02926         return;
02927     }
02928 
02929     if (  3 <= nfargs
02930        && isTRUE(mux_atol(fargs[2])))
02931     {
02932         ITL pContext;
02933         ItemToList_Init(&pContext, buff, bufc);
02934         for (int count = 0; count < n; count++)
02935         {
02936             if (!ItemToList_AddInteger(&pContext, RandomINT32(1, die)))
02937             {
02938                 break;
02939             }
02940         }
02941         ItemToList_Final(&pContext);
02942         return;
02943     }
02944 
02945     int total = 0;
02946     for (int count = 0; count < n; count++)
02947     {
02948         total += RandomINT32(1, die);
02949     }
02950 
02951     safe_ltoa(total, buff, bufc);
02952 }
02953 
02954 FUNCTION(fun_lrand)
02955 {
02956     SEP sep;
02957     if (!OPTIONAL_DELIM(4, sep, DELIM_NULL|DELIM_CRLF|DELIM_STRING))
02958     {
02959         return;
02960     }
02961 
02962     int n_times = mux_atol(fargs[2]);
02963     if (n_times < 1)
02964     {
02965         return;
02966     }
02967     if (n_times > LBUF_SIZE)
02968     {
02969         n_times = LBUF_SIZE;
02970     }
02971     INT32 iLower = mux_atol(fargs[0]);
02972     INT32 iUpper = mux_atol(fargs[1]);
02973 
02974     if (iLower <= iUpper)
02975     {
02976         for (int i = 0; i < n_times-1; i++)
02977         {
02978             INT32 val = RandomINT32(iLower, iUpper);
02979             safe_ltoa(val, buff, bufc);
02980             print_sep(&sep, buff, bufc);
02981         }
02982         INT32 val = RandomINT32(iLower, iUpper);
02983         safe_ltoa(val, buff, bufc);
02984     }
02985 }
02986 
02987 // Borrowed from PennMUSH 1.50
02988 //
02989 FUNCTION(fun_lit)
02990 {
02991     UNUSED_PARAMETER(executor);
02992     UNUSED_PARAMETER(caller);
02993     UNUSED_PARAMETER(enactor);
02994     UNUSED_PARAMETER(nfargs);
02995     UNUSED_PARAMETER(cargs);
02996     UNUSED_PARAMETER(ncargs);
02997 
02998     // Just returns the argument, literally.
02999     //
03000     safe_str(fargs[0], buff, bufc);
03001 }
03002 
03003 FUNCTION(fun_dumping)
03004 {
03005     UNUSED_PARAMETER(executor);
03006     UNUSED_PARAMETER(caller);
03007     UNUSED_PARAMETER(enactor);
03008     UNUSED_PARAMETER(fargs);
03009     UNUSED_PARAMETER(nfargs);
03010     UNUSED_PARAMETER(cargs);
03011     UNUSED_PARAMETER(ncargs);
03012 
03013 #ifdef WIN32
03014     safe_chr('0', buff, bufc);
03015 #else // WIN32
03016     safe_bool(mudstate.dumping, buff, bufc);
03017 #endif // WIN32
03018 }
03019 
03020 // The following table contains 64 symbols, so this supports -a-
03021 // radix-64 encoding. It is not however 'unix-to-unix' encoding.
03022 // All of the following characters are valid for an attribute
03023 // name, but not for the first character of an attribute name.
03024 //
03025 static char aRadixTable[] =
03026     "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@$";
03027 
03028 FUNCTION(fun_unpack)
03029 {
03030     UNUSED_PARAMETER(executor);
03031     UNUSED_PARAMETER(caller);
03032     UNUSED_PARAMETER(enactor);
03033     UNUSED_PARAMETER(cargs);
03034     UNUSED_PARAMETER(ncargs);
03035 
03036     // Validate radix if present.
03037     //
03038     INT64 iRadix = 64;
03039     if (nfargs == 2)
03040     {
03041         if (  !is_integer(fargs[1], NULL)
03042            || (iRadix = mux_atoi64(fargs[1])) < 2
03043            || 64 < iRadix)
03044         {
03045             safe_str("#-1 RADIX MUST BE A NUMBER BETWEEN 2 and 64", buff, bufc);
03046             return;
03047         }
03048     }
03049 
03050     // Build Table of valid characters.
03051     //
03052     char MatchTable[256];
03053     memset(MatchTable, 0, sizeof(MatchTable));
03054     for (int i = 0; i < iRadix; i++)
03055     {
03056         MatchTable[(unsigned char)aRadixTable[i]] = i+1;
03057     }
03058 
03059     // Validate that first argument contains only characters from the
03060     // subset of permitted characters.
03061     //
03062     char *pString = fargs[0];
03063     INT64 sum;
03064     int c;
03065     int LeadingCharacter;
03066 
03067     // Leading whitespace
03068     //
03069     while (mux_isspace(*pString))
03070     {
03071         pString++;
03072     }
03073 
03074     // Possible sign
03075     //
03076     LeadingCharacter = c = *pString++;
03077     if (c == '-' || c == '+')
03078     {
03079         c = *pString++;
03080     }
03081 
03082     sum = 0;
03083 
03084     // Convert symbols
03085     //
03086     for (int iValue = MatchTable[(unsigned int)c];
03087          iValue;
03088          iValue = MatchTable[(unsigned int)c])
03089     {
03090         sum = iRadix * sum + iValue - 1;
03091         c = *pString++;
03092     }
03093 
03094     // Interpret sign
03095     //
03096     if (LeadingCharacter == '-')
03097     {
03098         sum = -sum;
03099     }
03100     safe_i64toa(sum, buff, bufc);
03101 }
03102 
03103 static size_t mux_Pack(INT64 val, int iRadix, char *buf)
03104 {
03105     char *p = buf;
03106 
03107     // Handle sign.
03108     //
03109     if (val < 0)
03110     {
03111         *p++ = '-';
03112         val = -val;
03113     }
03114 
03115     char *q = p;
03116     while (val > iRadix-1)
03117     {
03118         INT64 iDiv  = val / iRadix;
03119         INT64 iTerm = val - iDiv * iRadix;
03120         val = iDiv;
03121         *p++ = aRadixTable[iTerm];
03122     }
03123     *p++ = aRadixTable[val];
03124 
03125     int nLength = p - buf;
03126     *p-- = '\0';
03127 
03128     // The digits are in reverse order with a possible leading '-'
03129     // if the value was negative. q points to the first digit,
03130     // and p points to the last digit.
03131     //
03132     while (q < p)
03133     {
03134         // Swap characters are *p and *q
03135         //
03136         char temp = *p;
03137         *p = *q;
03138         *q = temp;
03139 
03140         // Move p and first digit towards the middle.
03141         //
03142         --p;
03143         ++q;
03144 
03145         // Stop when we reach or pass the middle.
03146         //
03147     }
03148     return nLength;
03149 }
03150 
03151 FUNCTION(fun_pack)
03152 {
03153     UNUSED_PARAMETER(executor);
03154     UNUSED_PARAMETER(caller);
03155     UNUSED_PARAMETER(enactor);
03156     UNUSED_PARAMETER(cargs);
03157     UNUSED_PARAMETER(ncargs);
03158 
03159     // Validate the arguments are numeric.
03160     //
03161     if (  !is_integer(fargs[0], NULL)
03162        || (nfargs == 2 && !is_integer(fargs[1], NULL)))
03163     {
03164         safe_str("#-1 ARGUMENTS MUST BE NUMBERS", buff, bufc);
03165         return;
03166     }
03167     INT64 val = mux_atoi64(fargs[0]);
03168 
03169     // Validate the radix is between 2 and 64.
03170     //
03171     int iRadix = 64;
03172     if (nfargs == 2)
03173     {
03174         iRadix = mux_atol(fargs[1]);
03175         if (iRadix < 2 || 64 < iRadix)
03176         {
03177             safe_str("#-1 RADIX MUST BE A NUMBER BETWEEN 2 and 64", buff, bufc);
03178             return;
03179         }
03180     }
03181 
03182     char TempBuffer[76]; // 1 '-', 63 binary digits, 1 '\0', 11 for safety.
03183     int nLength = mux_Pack(val, iRadix, TempBuffer);
03184     safe_copy_buf(TempBuffer, nLength, buff, bufc);
03185 }
03186 
03187 FUNCTION(fun_strcat)
03188 {
03189     UNUSED_PARAMETER(executor);
03190     UNUSED_PARAMETER(caller);
03191     UNUSED_PARAMETER(enactor);
03192     UNUSED_PARAMETER(cargs);
03193     UNUSED_PARAMETER(ncargs);
03194 
03195     int i;
03196     for (i = 0; i < nfargs; i++)
03197     {
03198         safe_str(fargs[i], buff, bufc);
03199     }
03200 }
03201 
03202 // grep() and grepi() code borrowed from PennMUSH 1.50
03203 //
03204 static char *grep_util(dbref player, dbref thing, char *pattern, char *lookfor, int len, bool insensitive)
03205 {
03206     // Returns a list of attributes which match <pattern> on <thing>
03207     // whose contents have <lookfor>.
03208     //
03209     dbref aowner;
03210     char *tbuf1, *buf;
03211     char *bp, *bufc;
03212     int ca, aflags;
03213 
03214     tbuf1 = alloc_lbuf("grep_util");
03215     bufc = buf = alloc_lbuf("grep_util.parse_attrib");
03216     bp = tbuf1;
03217     safe_tprintf_str(buf, &bufc, "#%d/%s", thing, pattern);
03218     olist_push();
03219     if (parse_attrib_wild(player, buf, &thing, false, false, true))
03220     {
03221         BMH_State bmhs;
03222         if (insensitive)
03223         {
03224             BMH_PrepareI(&bmhs, len, lookfor);
03225         }
03226         else
03227         {
03228             BMH_Prepare(&bmhs, len, lookfor);
03229         }
03230 
03231         for (ca = olist_first(); ca != NOTHING && !MuxAlarm.bAlarmed; ca = olist_next())
03232         {
03233             size_t nText;
03234             char *attrib = atr_get_LEN(thing, ca, &aowner, &aflags, &nText);
03235             int i;
03236             if (insensitive)
03237             {
03238                 i = BMH_ExecuteI(&bmhs, len, lookfor, nText, attrib);
03239             }
03240             else
03241             {
03242                 i = BMH_Execute(&bmhs, len, lookfor, nText, attrib);
03243             }
03244             if (i >= 0)
03245             {
03246                 if (bp != tbuf1)
03247                 {
03248                     safe_chr(' ', tbuf1, &bp);
03249                 }
03250                 ATTR *ap = atr_num(ca);
03251                 const char *pName = "(WARNING: Bad Attribute Number)";
03252                 if (ap)
03253                 {
03254                     pName = ap->name;
03255                 }
03256                 safe_str(pName, tbuf1, &bp);
03257             }
03258             free_lbuf(attrib);
03259         }
03260     }
03261     free_lbuf(buf);
03262     *bp = '\0';
03263     olist_pop();
03264     return tbuf1;
03265 }
03266 
03267 static void grep_handler(char *buff, char **bufc, dbref executor, char *fargs[],
03268                    bool bCaseInsens)
03269 {
03270     dbref it = match_thing_quiet(executor, fargs[0]);
03271     if (!Good_obj(it))
03272     {
03273         safe_match_result(it, buff, bufc);
03274         return;
03275     }
03276 
03277     if (!Examinable(executor, it))
03278     {
03279         safe_noperm(buff, bufc);
03280         return;
03281     }
03282 
03283     // Make sure there's an attribute and a pattern
03284     //
03285     if (!fargs[1] || !*fargs[1])
03286     {
03287         safe_str("#-1 NO SUCH ATTRIBUTE", buff, bufc);
03288         return;
03289     }
03290     if (!fargs[2] || !*fargs[2])
03291     {
03292         safe_str("#-1 INVALID GREP PATTERN", buff, bufc);
03293         return;
03294     }
03295     char *tp = grep_util(executor, it, fargs[1], fargs[2], strlen(fargs[2]), bCaseInsens);
03296     safe_str(tp, buff, bufc);
03297     free_lbuf(tp);
03298 }
03299 
03300 FUNCTION(fun_grep)
03301 {
03302     UNUSED_PARAMETER(caller);
03303     UNUSED_PARAMETER(enactor);
03304     UNUSED_PARAMETER(nfargs);
03305     UNUSED_PARAMETER(cargs);
03306     UNUSED_PARAMETER(ncargs);
03307 
03308     grep_handler(buff, bufc, executor, fargs, false);
03309 }
03310 
03311 FUNCTION(fun_grepi)
03312 {
03313     UNUSED_PARAMETER(caller);
03314     UNUSED_PARAMETER(enactor);
03315     UNUSED_PARAMETER(nfargs);
03316     UNUSED_PARAMETER(cargs);
03317     UNUSED_PARAMETER(ncargs);
03318 
03319     grep_handler(buff, bufc, executor, fargs, true);
03320 }
03321 
03322 // Borrowed from PennMUSH 1.50
03323 //
03324 FUNCTION(fun_alphamax)
03325 {
03326     UNUSED_PARAMETER(executor);
03327     UNUSED_PARAMETER(caller);
03328     UNUSED_PARAMETER(enactor);
03329     UNUSED_PARAMETER(cargs);
03330     UNUSED_PARAMETER(ncargs);
03331 
03332     char *amax = fargs[0];
03333     for (int i = 1; i < nfargs; i++)
03334     {
03335         if (fargs[i] && strcmp(amax, fargs[i]) < 0)
03336         {
03337             amax = fargs[i];
03338         }
03339     }
03340     safe_str(amax, buff, bufc);
03341 }
03342 
03343 // Borrowed from PennMUSH 1.50
03344 //
03345 FUNCTION(fun_alphamin)
03346 {
03347     UNUSED_PARAMETER(executor);
03348     UNUSED_PARAMETER(caller);
03349     UNUSED_PARAMETER(enactor);
03350     UNUSED_PARAMETER(cargs);
03351     UNUSED_PARAMETER(ncargs);
03352 
03353     char *amin = fargs[0];
03354     for (int i = 1; i < nfargs; i++)
03355     {
03356         if (fargs[i] && strcmp(amin, fargs[i]) > 0)
03357         {
03358             amin = fargs[i];
03359         }
03360     }
03361     safe_str(amin, buff, bufc);
03362 }
03363 
03364 // Borrowed from PennMUSH 1.50
03365 //
03366 FUNCTION(fun_valid)
03367 {
03368     UNUSED_PARAMETER(executor);
03369     UNUSED_PARAMETER(caller);
03370     UNUSED_PARAMETER(enactor);
03371     UNUSED_PARAMETER(nfargs);
03372     UNUSED_PARAMETER(cargs);
03373     UNUSED_PARAMETER(ncargs);
03374 
03375     // Checks to see if a given <something> is valid as a parameter of
03376     // a given type (such as an object name)
03377     //
03378     int nValidName;
03379     bool bValid;
03380     if (!*fargs[0] || !*fargs[1])
03381     {
03382         bValid = false;
03383     }
03384     else if (!mux_stricmp(fargs[0], "name"))
03385     {
03386         MakeCanonicalObjectName(fargs[1], &nValidName, &bValid);
03387     }
03388     else if (!mux_stricmp(fargs[0], "attrname"))
03389     {
03390         MakeCanonicalAttributeName(fargs[1], &nValidName, &bValid);
03391     }
03392     else if (!mux_stricmp(fargs[0], "playername"))
03393     {
03394         bValid = ValidatePlayerName(fargs[1]);
03395     }
03396     else
03397     {
03398         safe_nothing(buff, bufc);
03399         return;
03400     }
03401     safe_bool(bValid, buff, bufc);
03402 }
03403 
03404 // Borrowed from PennMUSH 1.50
03405 //
03406 FUNCTION(fun_hastype)
03407 {
03408     UNUSED_PARAMETER(caller);
03409     UNUSED_PARAMETER(enactor);
03410     UNUSED_PARAMETER(nfargs);
03411     UNUSED_PARAMETER(cargs);
03412     UNUSED_PARAMETER(ncargs);
03413 
03414     dbref it = match_thing_quiet(executor, fargs[0]);
03415     if (!Good_obj(it))
03416     {
03417         safe_match_result(it, buff, bufc);
03418         return;
03419     }
03420     bool bResult = false;
03421     switch (mux_tolower(fargs[1][0]))
03422     {
03423     case 'r':
03424 
03425         bResult = isRoom(it);
03426         break;
03427 
03428     case 'e':
03429 
03430         bResult = isExit(it);
03431         break;
03432 
03433     case 'p':
03434 
03435         bResult = isPlayer(it);
03436         break;
03437 
03438     case 't':
03439 
03440         bResult = isThing(it);
03441         break;
03442 
03443     default:
03444 
03445         safe_str("#-1 NO SUCH TYPE", buff, bufc);
03446         break;
03447     }
03448     safe_bool(bResult, buff, bufc);
03449 }
03450 
03451 // Borrowed from PennMUSH 1.50
03452 //
03453 FUNCTION(fun_lparent)
03454 {
03455     UNUSED_PARAMETER(caller);
03456     UNUSED_PARAMETER(enactor);
03457     UNUSED_PARAMETER(nfargs);
03458     UNUSED_PARAMETER(cargs);
03459     UNUSED_PARAMETER(ncargs);
03460 
03461     dbref it = match_thing_quiet(executor, fargs[0]);
03462     if (!Good_obj(it))
03463     {
03464         safe_match_result(it, buff, bufc);
03465         return;
03466     }
03467     else if (!Examinable(executor, it))
03468     {
03469         safe_noperm(buff, bufc);
03470         return;
03471     }
03472 
03473     ITL pContext;
03474     ItemToList_Init(&pContext, buff, bufc, '#');
03475     if (!ItemToList_AddInteger(&pContext, it))
03476     {
03477         ItemToList_Final(&pContext);
03478         return;
03479     }
03480 
03481     dbref par = Parent(it);
03482 
03483     int iNestLevel = 1;
03484     while (  Good_obj(par)
03485           && Examinable(executor, it)
03486           && iNestLevel < mudconf.parent_nest_lim)
03487     {
03488         if (!ItemToList_AddInteger(&pContext, par))
03489         {
03490             break;
03491         }
03492         it = par;
03493         par = Parent(par);
03494         iNestLevel++;
03495     }
03496     ItemToList_Final(&pContext);
03497 }
03498 
03499 // stacksize - returns how many items are stuffed onto an object stack
03500 //
03501 static int stacksize(dbref doer)
03502 {
03503     int i;
03504     STACK *sp;
03505     for (i = 0, sp = Stack(doer); sp != NULL; sp = sp->next, i++)
03506     {
03507         // Nothing
03508         ;
03509     }
03510     return i;
03511 }
03512 
03513 FUNCTION(fun_lstack)
03514 {
03515     UNUSED_PARAMETER(caller);
03516     UNUSED_PARAMETER(enactor);
03517     UNUSED_PARAMETER(cargs);
03518     UNUSED_PARAMETER(ncargs);
03519 
03520     STACK *sp;
03521     dbref doer;
03522 
03523     if (nfargs == 0 || !*fargs[0])
03524     {
03525         doer = executor;
03526     }
03527     else
03528     {
03529         doer = match_thing_quiet(executor, fargs[0]);
03530         if (!Good_obj(doer))
03531         {
03532             safe_match_result(doer, buff, bufc);
03533             return;
03534         }
03535     }
03536 
03537     if (!Controls(executor, doer))
03538     {
03539         safe_noperm(buff, bufc);
03540         return;
03541     }
03542     for (sp = Stack(doer); sp != NULL; sp = sp->next)
03543     {
03544         safe_str(sp->data, buff, bufc);
03545         if (sp->next != NULL)
03546         {
03547             safe_chr(' ', buff, bufc);
03548         }
03549     }
03550 }
03551 
03552 // stack_clr - clear the stack.
03553 //
03554 void stack_clr(dbref obj)
03555 {
03556     // Clear the stack.
03557     //
03558     STACK *sp, *next;
03559     for (sp = Stack(obj); sp != NULL; sp = next)
03560     {
03561         next = sp->next;
03562         free_lbuf(sp->data);
03563         MEMFREE(sp);
03564         sp = NULL;
03565     }
03566     s_Stack(obj, NULL);
03567 }
03568 
03569 FUNCTION(fun_empty)
03570 {
03571     UNUSED_PARAMETER(caller);
03572     UNUSED_PARAMETER(enactor);
03573     UNUSED_PARAMETER(cargs);
03574     UNUSED_PARAMETER(ncargs);
03575 
03576     dbref doer;
03577 
03578     if (nfargs == 0 || !*fargs[0])
03579     {
03580         doer = executor;
03581     }
03582     else
03583     {
03584         doer = match_thing_quiet(executor, fargs[0]);
03585         if (!Good_obj(doer))
03586         {
03587             safe_match_result(doer, buff, bufc);
03588             return;
03589         }
03590     }
03591 
03592     if (!Controls(executor, doer))
03593     {
03594         safe_noperm(buff, bufc);
03595         return;
03596     }
03597     stack_clr(doer);
03598 }
03599 
03600 FUNCTION(fun_items)
03601 {
03602     UNUSED_PARAMETER(caller);
03603     UNUSED_PARAMETER(enactor);
03604     UNUSED_PARAMETER(cargs);
03605     UNUSED_PARAMETER(ncargs);
03606 
03607     dbref doer;
03608 
03609     if (nfargs == 0 || !*fargs[0])
03610     {
03611         doer = executor;
03612     }
03613     else
03614     {
03615         doer = match_thing_quiet(executor, fargs[0]);
03616         if (!Good_obj(doer))
03617         {
03618             safe_match_result(doer, buff, bufc);
03619             return;
03620         }
03621     }
03622 
03623     if (!Controls(executor, doer))
03624     {
03625         safe_noperm(buff, bufc);
03626         return;
03627     }
03628     safe_ltoa(stacksize(doer), buff, bufc);
03629 }
03630 
03631 FUNCTION(fun_peek)
03632 {
03633     UNUSED_PARAMETER(caller);
03634     UNUSED_PARAMETER(enactor);
03635     UNUSED_PARAMETER(cargs);
03636     UNUSED_PARAMETER(ncargs);
03637 
03638     STACK *sp;
03639     dbref doer;
03640     int count, pos;
03641 
03642     if (nfargs <= 0 || !*fargs[0])
03643     {
03644         doer = executor;
03645     }
03646     else
03647     {
03648         doer = match_thing_quiet(executor, fargs[0]);
03649         if (!Good_obj(doer))
03650         {
03651             safe_match_result(doer, buff, bufc);
03652             return;
03653         }
03654     }
03655 
03656     if (!Controls(executor, doer))
03657     {
03658         safe_noperm(buff, bufc);
03659         return;
03660     }
03661     if (nfargs <= 1 || !*fargs[1])
03662     {
03663         pos = 0;
03664     }
03665     else
03666     {
03667         pos = mux_atol(fargs[1]);
03668     }
03669 
03670     if (stacksize(doer) == 0)
03671     {
03672         return;
03673     }
03674     if (pos > (stacksize(doer) - 1))
03675     {
03676         safe_str("#-1 POSITION TOO LARGE", buff, bufc);
03677         return;
03678     }
03679     count = 0;
03680     sp = Stack(doer);
03681     while (count != pos)
03682     {
03683         if (sp == NULL)
03684         {
03685             return;
03686         }
03687         count++;
03688         sp = sp->next;
03689     }
03690 
03691     safe_str(sp->data, buff, bufc);
03692 }
03693 
03694 FUNCTION(fun_pop)
03695 {
03696     UNUSED_PARAMETER(caller);
03697     UNUSED_PARAMETER(enactor);
03698     UNUSED_PARAMETER(cargs);
03699     UNUSED_PARAMETER(ncargs);
03700 
03701     dbref doer;
03702 
03703     if (nfargs <= 0 || !*fargs[0])
03704     {
03705         doer = executor;
03706     }
03707     else
03708     {
03709         doer = match_thing_quiet(executor, fargs[0]);
03710         if (!Good_obj(doer))
03711         {
03712             safe_match_result(doer, buff, bufc);
03713             return;
03714         }
03715     }
03716     if (!Controls(executor, doer))
03717     {
03718         safe_noperm(buff, bufc);
03719         return;
03720     }
03721 
03722     int pos;
03723     if (nfargs <= 1 || !*fargs[1])
03724     {
03725         pos = 0;
03726     }
03727     else
03728     {
03729         pos = mux_atol(fargs[1]);
03730     }
03731     if (stacksize(doer) == 0)
03732     {
03733         return;
03734     }
03735     if (pos > (stacksize(doer) - 1))
03736     {
03737         safe_str("#-1 POSITION TOO LARGE", buff, bufc);
03738         return;
03739     }
03740 
03741     STACK *sp = Stack(doer);
03742     STACK *prev = NULL;
03743     int count = 0;
03744     while (count != pos)
03745     {
03746         if (sp == NULL)
03747         {
03748             return;
03749         }
03750         prev = sp;
03751         sp = sp->next;
03752         count++;
03753     }
03754 
03755     safe_str(sp->data, buff, bufc);
03756     if (count == 0)
03757     {
03758         s_Stack(doer, sp->next);
03759         free_lbuf(sp->data);
03760         MEMFREE(sp);
03761         sp = NULL;
03762     }
03763     else
03764     {
03765         prev->next = sp->next;
03766         free_lbuf(sp->data);
03767         MEMFREE(sp);
03768         sp = NULL;
03769     }
03770 }
03771 
03772 FUNCTION(fun_push)
03773 {
03774     UNUSED_PARAMETER(caller);
03775     UNUSED_PARAMETER(enactor);
03776     UNUSED_PARAMETER(cargs);
03777     UNUSED_PARAMETER(ncargs);
03778 
03779     dbref doer;
03780     char *data;
03781 
03782     if (nfargs <= 1 || !*fargs[1])
03783     {
03784         doer = executor;
03785         data = fargs[0];
03786     }
03787     else
03788     {
03789         doer = match_thing_quiet(executor, fargs[0]);
03790         if (!Good_obj(doer))
03791         {
03792             safe_match_result(doer, buff, bufc);
03793             return;
03794         }
03795         data = fargs[1];
03796     }
03797 
03798     if (!Controls(executor, doer))
03799     {
03800         safe_noperm(buff, bufc);
03801         return;
03802     }
03803     if (stacksize(doer) >= mudconf.stack_limit)
03804     {
03805         safe_str("#-1 STACK SIZE EXCEEDED", buff, bufc);
03806         return;
03807     }
03808     STACK *sp = (STACK *)MEMALLOC(sizeof(STACK));
03809     ISOUTOFMEMORY(sp);
03810     sp->next = Stack(doer);
03811     sp->data = alloc_lbuf("push");
03812     strcpy(sp->data, data);
03813     s_Stack(doer, sp);
03814 }
03815 
03816 /* ---------------------------------------------------------------------------
03817  * fun_regmatch: Return 0 or 1 depending on whether or not a regular
03818  * expression matches a string. If a third argument is specified, dump
03819  * the results of a regexp pattern match into a set of arbitrary r()-registers.
03820  *
03821  * regmatch(string, pattern, list of registers)
03822  * If the number of matches exceeds the registers, those bits are tossed
03823  * out.
03824  * If -1 is specified as a register number, the matching bit is tossed.
03825  * Therefore, if the list is "-1 0 3 5", the regexp $0 is tossed, and
03826  * the regexp $1, $2, and $3 become r(0), r(3), and r(5), respectively.
03827  */
03828 
03829 static void real_regmatch(const char *search, const char *pattern, char *registers,
03830                    int nfargs, char *buff, char **bufc, bool cis)
03831 {
03832     if (MuxAlarm.bAlarmed)
03833     {
03834         return;
03835     }
03836 
03837     const char *errptr;
03838     int erroffset;
03839     // To capture N substrings, you need space for 3(N+1) offsets in the
03840     // offset vector. We'll allow 2N-1 substrings and possibly ignore some.
03841     //
03842     const int ovecsize = 6 * MAX_GLOBAL_REGS;
03843     int ovec[ovecsize];
03844 
03845     pcre *re = pcre_compile(pattern, cis ? PCRE_CASELESS : 0,
03846         &errptr, &erroffset, NULL);
03847     if (!re)
03848     {
03849         // Matching error.
03850         //
03851         safe_str("#-1 REGEXP ERROR ", buff, bufc);
03852         safe_str(errptr, buff, bufc);
03853         return;
03854     }
03855 
03856     int matches = pcre_exec(re, NULL, search, strlen(search), 0, 0,
03857         ovec, ovecsize);
03858     if (matches == 0)
03859     {
03860         // There were too many substring matches. See docs for
03861         // pcre_copy_substring().
03862         //
03863         matches = ovecsize / 3;
03864     }
03865     safe_bool(matches > 0, buff, bufc);
03866     if (matches < 0)
03867     {
03868         matches = 0;
03869     }
03870 
03871     // If we don't have a third argument, we're done.
03872     //
03873     if (nfargs != 3)
03874     {
03875         MEMFREE(re);
03876         return;
03877     }
03878 
03879     // We need to parse the list of registers. If a register is
03880     // mentioned in the list, then either fill the register with the
03881     // subexpression, or if there wasn't a match, clear it.
03882     //
03883     const int NSUBEXP = 2 * MAX_GLOBAL_REGS;
03884     char *qregs[NSUBEXP];
03885     SEP sep;
03886     sep.n = 1;
03887     memcpy(sep.str, " ", 2);
03888     int nqregs = list2arr(qregs, NSUBEXP, registers, &sep);
03889     int i;
03890     for (i = 0; i < nqregs; i++)
03891     {
03892         int curq;
03893         if (  qregs[i]
03894            && *qregs[i]
03895            && (curq = mux_RegisterSet[(unsigned char)qregs[i][0]]) != -1
03896            && qregs[i][1] == '\0'
03897            && curq < MAX_GLOBAL_REGS)
03898         {
03899             if (!mudstate.global_regs[curq])
03900             {
03901                 mudstate.global_regs[curq] = alloc_lbuf("fun_regmatch");
03902             }
03903             int len;
03904             len = pcre_copy_substring(search, ovec, matches, i,
03905                                       mudstate.global_regs[curq], LBUF_SIZE);
03906             mudstate.glob_reg_len[curq] = (len > 0 ? len : 0);
03907         }
03908     }
03909     MEMFREE(re);
03910 }
03911 
03912 FUNCTION(fun_regmatch)
03913 {
03914     UNUSED_PARAMETER(executor);
03915     UNUSED_PARAMETER(enactor);
03916     UNUSED_PARAMETER(caller);
03917     UNUSED_PARAMETER(enactor);
03918     UNUSED_PARAMETER(cargs);
03919     UNUSED_PARAMETER(ncargs);
03920 
03921     real_regmatch(fargs[0], fargs[1], fargs[2], nfargs, buff, bufc, false);
03922 }
03923 
03924 FUNCTION(fun_regmatchi)
03925 {
03926     UNUSED_PARAMETER(executor);
03927     UNUSED_PARAMETER(enactor);
03928     UNUSED_PARAMETER(caller);
03929     UNUSED_PARAMETER(enactor);
03930     UNUSED_PARAMETER(cargs);
03931     UNUSED_PARAMETER(ncargs);
03932 
03933     real_regmatch(fargs[0], fargs[1], fargs[2], nfargs, buff, bufc, true);
03934 }
03935 
03936 
03937 /* ---------------------------------------------------------------------------
03938  * regrab(), regraball(). Like grab() and graball(), using a regular expression
03939  * instead of a wildcard pattern. The versions ending in i are case-insensitive.
03940  */
03941 
03942 static void real_regrab(char *search, const char *pattern, SEP *psep, char *buff,
03943                  char **bufc, bool cis, bool all)
03944 {
03945     if (MuxAlarm.bAlarmed)
03946     {
03947         return;
03948     }
03949     pcre *re;
03950     pcre_extra *study = NULL;
03951     const char *errptr;
03952     int erroffset;
03953     // To capture N substrings, you need space for 3(N+1) offsets in the
03954     // offset vector. We'll allow 2N-1 substrings and possibly ignore some.
03955     //
03956     const int ovecsize = 6 * MAX_GLOBAL_REGS;
03957     int ovec[ovecsize];
03958 
03959     re = pcre_compile(pattern, cis ? PCRE_CASELESS : 0,
03960         &errptr, &erroffset, NULL);
03961     if (!re)
03962     {
03963         // Matching error.
03964         //
03965         safe_str("#-1 REGEXP ERROR ", buff, bufc);
03966         safe_str(errptr, buff, bufc);
03967         return;
03968     }
03969 
03970     if (all)
03971     {
03972         study = pcre_study(re, 0, &errptr);
03973     }
03974 
03975     bool first = true;
03976     char *s = trim_space_sep(search, psep);
03977     do
03978     {
03979         char *r = split_token(&s, psep);
03980         if (  !MuxAlarm.bAlarmed
03981            && pcre_exec(re, study, r, strlen(r), 0, 0, ovec, ovecsize) >= 0)
03982         {
03983             if (first)
03984             {
03985                 first = false;
03986             }
03987             else
03988             {
03989                 print_sep(psep, buff, bufc);
03990             }
03991             safe_str(r, buff, bufc);
03992             if (!all)
03993             {
03994                 break;
03995             }
03996         }
03997     } while (s);
03998 
03999     MEMFREE(re);
04000     if (study)
04001     {
04002         MEMFREE(study);
04003     }
04004 }
04005 
04006 FUNCTION(fun_regrab)
04007 {
04008     SEP sep;
04009     if (!OPTIONAL_DELIM(3, sep, DELIM_DFLT|DELIM_STRING))
04010     {
04011         return;
04012     }
04013     real_regrab(fargs[0], fargs[1], &sep, buff, bufc, false, false);
04014 }
04015 
04016 FUNCTION(fun_regrabi)
04017 {
04018     SEP sep;
04019     if (!OPTIONAL_DELIM(3, sep, DELIM_DFLT|DELIM_STRING))
04020     {
04021         return;
04022     }
04023     real_regrab(fargs[0], fargs[1], &sep, buff, bufc, true, false);
04024 }
04025 
04026 FUNCTION(fun_regraball)
04027 {
04028     SEP sep;
04029     if (!OPTIONAL_DELIM(3, sep, DELIM_DFLT|DELIM_STRING))
04030     {
04031         return;
04032     }
04033     real_regrab(fargs[0], fargs[1], &sep, buff, bufc, false, true);
04034 }
04035 
04036 FUNCTION(fun_regraballi)
04037 {
04038     SEP sep;
04039     if (!OPTIONAL_DELIM(3, sep, DELIM_DFLT|DELIM_STRING))
04040     {
04041         return;
04042     }
04043     real_regrab(fargs[0], fargs[1], &sep, buff, bufc, true, true);
04044 }
04045 
04046 
04047 /* ---------------------------------------------------------------------------
04048  * fun_translate: Takes a string and a second argument. If the second argument
04049  * is 0 or s, control characters are converted to spaces. If it's 1 or p,
04050  * they're converted to percent substitutions.
04051  */
04052 
04053 FUNCTION(fun_translate)
04054 {
04055     UNUSED_PARAMETER(executor);
04056     UNUSED_PARAMETER(caller);
04057     UNUSED_PARAMETER(enactor);
04058     UNUSED_PARAMETER(nfargs);
04059     UNUSED_PARAMETER(cargs);
04060     UNUSED_PARAMETER(ncargs);
04061 
04062     int ch = fargs[1][0];
04063     bool type = (ch == 'p' || ch == '1');
04064     safe_str(translate_string(fargs[0], type), buff, bufc);
04065 }
04066 
04067 // Construct a CBitField to hold (nMaximum_arg+1) bits numbered 0 through
04068 // nMaximum_arg.
04069 //
04070 CBitField::CBitField(unsigned int nMaximum_arg)
04071 {
04072     nMaximum = 0;
04073     nInts    = 0;
04074     pInts    = NULL;
04075     pMasks   = NULL;
04076 
04077     nBitsPer = sizeof(UINT32)*8;
04078 
04079     // Calculate Shift
04080     //
04081     nShift = 0;
04082     unsigned int i = 1;
04083     while (i < nBitsPer)
04084     {
04085         nShift++;
04086         i <<= 1;
04087     }
04088 
04089     // Calculate Mask
04090     //
04091     nMask = nBitsPer - 1;
04092 
04093     // Allocate array of UINT32s.
04094     //
04095     Resize(nMaximum_arg);
04096 }
04097 
04098 #define MINIMUM_RESIZE (4096*sizeof(UINT32))
04099 
04100 void CBitField::Resize(unsigned int nMaximum_arg)
04101 {
04102     if (  0 < nMaximum_arg
04103        && nMaximum < nMaximum_arg)
04104     {
04105         unsigned int nNewMaximum = nMaximum_arg;
04106 
04107         // This provides some assurances that we are not resizing too often.
04108         //
04109         if (  pMasks
04110            && nNewMaximum < nMaximum + MINIMUM_RESIZE)
04111         {
04112             nNewMaximum = nMaximum + MINIMUM_RESIZE;
04113         }
04114 
04115         size_t  nNewInts = (nNewMaximum+nBitsPer) >> nShift;
04116         UINT32 *pNewMasks = (UINT32 *)MEMALLOC((nNewInts+nBitsPer)
04117                           * sizeof(UINT32));
04118         ISOUTOFMEMORY(pNewMasks);
04119         UINT32 *pNewInts = pNewMasks + nBitsPer;
04120 
04121         // Is this the first sizing or a re-sizing?
04122         //
04123         if (pMasks)
04124         {
04125             // Copy existing masks and bits to the new location, and
04126             // clear the new bits.
04127             //
04128             memcpy(pNewMasks, pMasks, (nInts+nBitsPer)*sizeof(UINT32));
04129             memset(pNewInts + nInts, 0, (nNewInts - nInts)*sizeof(UINT32));
04130 
04131             // Free the previous allocation.
04132             //
04133             MEMFREE(pMasks);
04134 
04135             // A reallocation.
04136             //
04137             nMaximum = nNewMaximum;
04138             nInts    = nNewInts;
04139             pMasks   = pNewMasks;
04140             pInts    = pNewInts;
04141         }
04142         else
04143         {
04144             // First allocation.
04145             //
04146             nMaximum = nNewMaximum;
04147             nInts    = nNewInts;
04148             pMasks   = pNewMasks;
04149             pInts    = pNewInts;
04150 
04151             // Initialize masks by calculating all possible single bits.
04152             //
04153             for (unsigned int i = 0; i < nBitsPer; i++)
04154             {
04155                 pMasks[i] = ((UINT32)1) << i;
04156             }
04157 
04158             // Initialize bits by clearing them all.
04159             //
04160             ClearAll();
04161         }
04162     }
04163 }
04164 
04165 CBitField::~CBitField(void)
04166 {
04167     pInts  = NULL;
04168     if (pMasks)
04169     {
04170         MEMFREE(pMasks);
04171         pMasks = NULL;
04172     }
04173 }
04174 
04175 void CBitField::ClearAll(void)
04176 {
04177     memset(pInts, 0, nInts*sizeof(UINT32));
04178 }
04179 
04180 void CBitField::Set(unsigned int i)
04181 {
04182     if (i <= nMaximum)
04183     {
04184         pInts[i>>nShift] |= pMasks[i&nMask];
04185     }
04186 }
04187 
04188 void CBitField::Clear(unsigned int i)
04189 {
04190     if (i <= nMaximum)
04191     {
04192         pInts[i>>nShift] &= ~pMasks[i&nMask];
04193     }
04194 }
04195 
04196 bool CBitField::IsSet(unsigned int i)
04197 {
04198     if (i <= nMaximum)
04199     {
04200         if (pInts[i>>nShift] & pMasks[i&nMask])
04201         {
04202             return true;
04203         }
04204     }
04205     return false;
04206 }
04207 
04208 
04209 // -------------------------------------------------------------------------
04210 // fun_lrooms:  Takes a dbref (room), an int (N), and an optional bool (B).
04211 //
04212 // MUX Syntax:  lrooms(<room> [,<N>[,<B>]])
04213 //
04214 // Returns a list of rooms <N>-levels deep from <room>. If <B> == 1, it will
04215 //   return all room dbrefs between 0 and <N> levels, while <B> == 0 will
04216 //   return only the room dbrefs on the Nth level. The default is to show all
04217 //   rooms dbrefs between 0 and <N> levels.
04218 //
04219 // Written by Marlek.  Idea from RhostMUSH.
04220 //
04221 static void room_list
04222 (
04223     dbref player,
04224     dbref enactor,
04225     dbref room,
04226     int   level,
04227     int   maxlevels,
04228     bool  showall
04229 )
04230 {
04231     // Make sure the player can really see this room from their location.
04232     //
04233     if (  (  level == maxlevels
04234           || showall)
04235        && (  Examinable(player, room)
04236           || Location(player) == room
04237           || room == enactor))
04238     {
04239         mudstate.bfReport.Set(room);
04240     }
04241 
04242     // If the Nth level has been reach, stop this branch in the recursion
04243     //
04244     if (level >= maxlevels)
04245     {
04246         return;
04247     }
04248 
04249     // Return info for all parent levels.
04250     //
04251     int lev;
04252     dbref parent;
04253     ITER_PARENTS(room, parent, lev)
04254     {
04255         // Look for exits at each level.
04256         //
04257         if (!Has_exits(parent))
04258         {
04259             continue;
04260         }
04261         int key = 0;
04262         if (Examinable(player, parent))
04263         {
04264             key |= VE_LOC_XAM;
04265         }
04266         if (Dark(parent))
04267         {
04268             key |= VE_LOC_DARK;
04269         }
04270         if (Dark(room))
04271         {
04272             key |= VE_BASE_DARK;
04273         }
04274 
04275         dbref thing;
04276         DOLIST(thing, Exits(parent))
04277         {
04278             dbref loc = Location(thing);
04279             if (  exit_visible(thing, player, key)
04280                && !mudstate.bfTraverse.IsSet(loc))
04281             {
04282                 mudstate.bfTraverse.Set(loc);
04283                 room_list(player, enactor, loc, (level + 1), maxlevels, showall);
04284             }
04285         }
04286     }
04287 }
04288 
04289 FUNCTION(fun_lrooms)
04290 {
04291     UNUSED_PARAMETER(caller);
04292     UNUSED_PARAMETER(cargs);
04293     UNUSED_PARAMETER(ncargs);
04294 
04295     dbref room = match_thing_quiet(executor, fargs[0]);
04296     if (!Good_obj(room))
04297     {
04298         safe_match_result(room, buff, bufc);
04299         return;
04300     }
04301     else if (!isRoom(room))
04302     {
04303         safe_str("#-1 FIRST ARGUMENT MUST BE A ROOM", buff, bufc);
04304         return;
04305     }
04306 
04307     int N = 1;
04308     if (nfargs >= 2)
04309     {
04310         N = mux_atol(fargs[1]);
04311         if (N < 0)
04312         {
04313             safe_str("#-1 SECOND ARGUMENT MUST BE A POSITIVE NUMBER",
04314                 buff, bufc);
04315             return;
04316         }
04317         else if (N > 50)
04318         {
04319             // Maybe this can be turned into a config parameter to prevent
04320             // misuse by putting in really large values.
04321             //
04322             safe_str("#-1 SECOND ARGUMENT IS TOO LARGE", buff, bufc);
04323             return;
04324         }
04325     }
04326 
04327     bool B = true;
04328     if (nfargs == 3)
04329     {
04330         B = xlate(fargs[2]);
04331     }
04332 
04333     mudstate.bfReport.Resize(mudstate.db_top-1);
04334     mudstate.bfTraverse.Resize(mudstate.db_top-1);
04335     mudstate.bfReport.ClearAll();
04336     mudstate.bfTraverse.ClearAll();
04337 
04338     mudstate.bfTraverse.Set(room);
04339     room_list(executor, enactor, room, 0, N, B);
04340     mudstate.bfReport.Clear(room);
04341 
04342     ITL pContext;
04343     ItemToList_Init(&pContext, buff, bufc, '#');
04344     dbref i;
04345     DO_WHOLE_DB(i)
04346     {
04347         if (  mudstate.bfReport.IsSet(i)
04348            && !ItemToList_AddInteger(&pContext, i))
04349         {
04350             break;
04351         }
04352     }
04353     ItemToList_Final(&pContext);
04354 }

Generated on Mon May 28 04:40:09 2007 for MUX by  doxygen 1.4.7