root/1.8.3/tags/p6/src/function.c

Revision 1167, 53.2 KB (checked in by shawnw, 13 months ago)

Merge devel into trunk for p6 release

Line 
1/**
2 * \file function.c
3 *
4 * \brief The function parser.
5 *
6 *
7 */
8#include "copyrite.h"
9
10#include "config.h"
11#include <limits.h>
12#include <string.h>
13#include <ctype.h>
14#include <stdlib.h>
15#include "conf.h"
16#include "externs.h"
17#include "attrib.h"
18#include "dbdefs.h"
19#include "mushdb.h"
20#include "function.h"
21#include "match.h"
22#include "htab.h"
23#include "parse.h"
24#include "lock.h"
25#include "flags.h"
26#include "game.h"
27#include "mymalloc.h"
28#include "sort.h"
29#include "funs.h"
30#include "confmagic.h"
31#include "ansi.h"
32
33static void func_hash_insert(const char *name, FUN *func);
34extern void local_functions(void);
35static int apply_restrictions(unsigned int result, const char *restriction);
36static char *build_function_report(dbref player, FUN *fp);
37
38USERFN_ENTRY *userfn_tab;   /**< Table of user-defined functions */
39HASHTAB htab_function;      /**< Function hash table */
40HASHTAB htab_user_function; /**< User-defined function hash table */
41slab *function_slab; /**< slab for 'struct fun' allocations */
42slab *userfun_slab; /**< slab for 'struct userfn_entry' allocations */
43
44/* -------------------------------------------------------------------------*
45 * Utilities.
46 */
47
48/* Save and restore regexp data */
49void
50save_regexp_context(struct re_save *save)
51{
52  save->re_code = global_eval_context.re_code;
53  save->re_from = global_eval_context.re_from;
54  save->re_subpatterns = global_eval_context.re_subpatterns;
55  save->re_offsets = global_eval_context.re_offsets;
56}
57
58void
59restore_regexp_context(struct re_save *save)
60{
61  global_eval_context.re_code = save->re_code;
62  global_eval_context.re_from = save->re_from;
63  global_eval_context.re_subpatterns = save->re_subpatterns;
64  global_eval_context.re_offsets = save->re_offsets;
65}
66
67/** Save a single q-register
68 */
69void
70save_partial_global_reg(const char *funcname, char *preserve[], int i)
71{
72  preserve[i] = mush_strdup(global_eval_context.renv[i], funcname);
73}
74
75/** Restore q-registers saved with save_partial_global_reg()
76 */
77void
78restore_partial_global_regs(const char *funcname, char *preserve[])
79{
80  int i;
81  for (i = 0; i < NUMQ; i++) {
82    if (preserve[i]) {
83      mush_strncpy(global_eval_context.renv[i], preserve[i], BUFFER_LEN);
84      mush_free(preserve[i], funcname);
85    }
86  }
87}
88
89/** Save a copy of the q-registers.
90 * \param funcname name of function calling (for memory leak testing)
91 * \param preserve pointer to array to store the q-registers in.
92 */
93void
94save_global_regs(const char *funcname, char *preserve[])
95{
96  int i;
97  for (i = 0; i < NUMQ; i++) {
98    if (!global_eval_context.renv[i][0])
99      preserve[i] = NULL;
100    else {
101      preserve[i] = mush_strdup(global_eval_context.renv[i], funcname);
102    }
103  }
104}
105
106/** Restore the q-registers, freeing the storage array.
107 * \param funcname name of function calling (for memory leak testing)
108 * \param preserve pointer to array to restore the q-registers from.
109 */
110void
111restore_global_regs(const char *funcname, char *preserve[])
112{
113  int i;
114  for (i = 0; i < NUMQ; i++) {
115    if (preserve[i]) {
116      mush_strncpy(global_eval_context.renv[i], preserve[i], BUFFER_LEN);
117      mush_free(preserve[i], funcname);
118      preserve[i] = NULL;
119    } else {
120      global_eval_context.renv[i][0] = '\0';
121    }
122  }
123}
124
125/** Free the storage array for the q-registers, without restoring
126 * \param funcname name of function calling (for memory leak testing)
127 * \param preserve pointer to array to free q-registers from.
128 */
129void
130free_global_regs(const char *funcname, char *preserve[])
131{
132  int i;
133  for (i = 0; i < NUMQ; i++) {
134    if (preserve[i])
135      mush_free(preserve[i], funcname);
136  }
137}
138
139/** Initilalize an array for the q-registers, setting all NULL.
140 * \param preserve pointer to array to free q-registers from.
141 */
142void
143init_global_regs(char *preserve[])
144{
145  int i;
146  for (i = 0; i < NUMQ; i++) {
147    preserve[i] = NULL;
148  }
149}
150
151/** Restore the q-registers, without freeing the storage array.
152 * \param preserve pointer to array to restore the q-registers from.
153 */
154void
155load_global_regs(char *preserve[])
156{
157  int i;
158  for (i = 0; i < NUMQ; i++) {
159    if (preserve[i]) {
160      strcpy(global_eval_context.renv[i], preserve[i]);
161    } else {
162      global_eval_context.renv[i][0] = '\0';
163    }
164  }
165}
166
167/** Save a copy of the environment (%0-%9)
168 * \param funcname name of function calling (for memory leak testing)
169 * \param preserve pointer to array to store %0-%9 in.
170 */
171void
172save_global_env(const char *funcname __attribute__ ((__unused__)),
173                char *preserve[])
174{
175  int i;
176  for (i = 0; i < 10; i++)
177    preserve[i] = global_eval_context.wenv[i];
178}
179
180/** Restore the environment (%0-%9)
181 * \param funcname name of function calling (for memory leak testing)
182 * \param preserve pointer to array to restore %0-%9 from.
183 */
184void
185restore_global_env(const char *funcname __attribute__ ((__unused__)),
186                   char *preserve[])
187{
188  int i;
189  for (i = 0; i < 10; i++)
190    global_eval_context.wenv[i] = preserve[i];
191}
192
193/** Save a copy of the wnxt and rnxt state
194 * This function must deal with both the addresses and the values
195 * of these variables, because they get modified in all sorts of
196 * nasty ways that we may not account for.
197 * \param funcname name of function calling (for memory leak testing)
198 * \param preservew pointer to array to store the wnxt address in.
199 * \param preserver pointer to array to store the rnxt address in.
200 * \param valw pointer to array to store the wnxt value in.
201 * \param valr pointer to array to store the rnxt value in.
202 */
203void
204save_global_nxt(const char *funcname, char *preservew[], char *preserver[],
205                char *valw[], char *valr[])
206{
207  int i;
208  for (i = 0; i < NUMQ; i++) {
209    preserver[i] = global_eval_context.rnxt[i];
210    if (!global_eval_context.rnxt[i])
211      valr[i] = NULL;
212    else {
213      valr[i] = mush_strdup(global_eval_context.rnxt[i], funcname);
214    }
215  }
216  for (i = 0; i < 10; i++) {
217    preservew[i] = global_eval_context.wnxt[i];
218    if (!global_eval_context.wnxt[i])
219      valw[i] = NULL;
220    else {
221      valw[i] = mush_strdup(global_eval_context.wnxt[i], funcname);
222    }
223  }
224}
225
226/** Restore a copy of the wnxt and rnxt state
227 * \param funcname name of function calling (for memory leak testing)
228 * \param preservew pointer to array to restore the wnxt address from.
229 * \param preserver pointer to array to restore the rnxt address from.
230 * \param valw pointer to array to restore the wnxt value from.
231 * \param valr pointer to array to restore the rnxt value from.
232 */
233void
234restore_global_nxt(const char *funcname, char *preservew[], char *preserver[],
235                   char *valw[], char *valr[])
236{
237  int i;
238  for (i = 0; i < NUMQ; i++) {
239    global_eval_context.rnxt[i] = preserver[i];
240    if (preserver[i]) {
241      /* There was a former address, so we can restore to it */
242      mush_strncpy(global_eval_context.rnxt[i], valr[i], BUFFER_LEN);
243      mush_free(valr[i], funcname);
244      valr[i] = NULL;
245    }
246  }
247  for (i = 0; i < 10; i++) {
248    global_eval_context.wnxt[i] = preservew[i];
249    if (preservew[i]) {
250      /* There was a former address, so we can restore to it */
251      mush_strncpy(global_eval_context.wnxt[i], valw[i], BUFFER_LEN);
252      mush_free(valw[i], funcname);
253      valw[i] = NULL;
254    }
255  }
256}
257
258
259/** Check for a delimiter in an argument of a function call.
260 * This function checks a given argument of a function call and sees
261 * if it could be used as a delimiter. A delimiter must be a single
262 * character. If the argument isn't present or is null, we return
263 * the default delimiter, a space.
264 * \param buff unused.
265 * \param bp unused.
266 * \param nfargs number of arguments to the function.
267 * \param fargs array of function arguments.
268 * \param sep_arg index of the argument to check for a delimiter.
269 * \param sep pointer to separator character, used to return separator.
270 * \retval 0 illegal separator argument.
271 * \retval 1 successfully returned a separator (maybe the default one).
272 */
273int
274delim_check(char *buff, char **bp, int nfargs, char *fargs[], int sep_arg,
275            char *sep)
276{
277  /* Find a delimiter. */
278
279  if (nfargs >= sep_arg) {
280    if (!*fargs[sep_arg - 1])
281      *sep = ' ';
282    else if (strlen(fargs[sep_arg - 1]) != 1) {
283      safe_str(T("#-1 SEPARATOR MUST BE ONE CHARACTER"), buff, bp);
284      return 0;
285    } else
286      *sep = *fargs[sep_arg - 1];
287  } else
288    *sep = ' ';
289
290  return 1;
291}
292
293/* --------------------------------------------------------------------------
294 * The actual function handlers
295 */
296
297/** An entry in the function table.
298 * This structure represents a function's entry in the function table.
299 */
300typedef struct fun_tab {
301  const char *name;     /**< Name of the function, uppercase. */
302  function_func fun;    /**< Pointer to code to call for this function. */
303  int minargs;  /**< Minimum args required. */
304  int maxargs;  /**< Maximum args, or INT_MAX. If <0, last arg may have commas */
305  int flags;    /**< Flags to control how the function is parsed. */
306} FUNTAB;
307
308
309/** The function table. Functions can also be added at runtime with
310 * add_function().
311 */
312FUNTAB flist[] = {
313  {"@@", fun_atat, 1, -1, FN_NOPARSE},
314  {"ABS", fun_abs, 1, 1, FN_REG},
315  {"ACCENT", fun_accent, 2, 2, FN_REG},
316  {"ACCNAME", fun_accname, 1, 1, FN_REG},
317  {"ADD", fun_add, 2, INT_MAX, FN_REG},
318  {"AFTER", fun_after, 2, 2, FN_REG},
319  {"ALIAS", fun_alias, 1, 2, FN_REG},
320  {"ALIGN", fun_align, 2, INT_MAX, FN_REG},
321  {"ALLOF", fun_allof, 2, INT_MAX, FN_NOPARSE},
322  {"ALPHAMAX", fun_alphamax, 1, INT_MAX, FN_REG},
323  {"ALPHAMIN", fun_alphamin, 1, INT_MAX, FN_REG},
324  {"AND", fun_and, 2, INT_MAX, FN_REG},
325  {"ANDFLAGS", fun_andflags, 2, 2, FN_REG},
326  {"ANDLFLAGS", fun_andlflags, 2, 2, FN_REG},
327  {"ANDLPOWERS", fun_andlflags, 2, 2, FN_REG},
328  {"ANDPOWERS", fun_andflags, 2, 2, FN_REG},
329  {"ANSI", fun_ansi, 2, -2, FN_REG},
330#ifdef ANSI_DEBUG
331  {"ANSIINSPECT", fun_ansiinspect, 1, 2, FN_REG},
332#endif
333  {"APOSS", fun_aposs, 1, 1, FN_REG},
334  {"ART", fun_art, 1, 1, FN_REG},
335  {"ATRLOCK", fun_atrlock, 1, 2, FN_REG},
336  {"ATTRIB_SET", fun_attrib_set, 1, -2, FN_REG},
337  {"BAND", fun_band, 1, INT_MAX, FN_REG},
338  {"BASECONV", fun_baseconv, 3, 3, FN_REG},
339  {"BEEP", fun_beep, 0, 1, FN_REG},
340  {"BEFORE", fun_before, 2, 2, FN_REG},
341  {"BNAND", fun_bnand, 2, 2, FN_REG},
342  {"BNOT", fun_bnot, 1, 1, FN_REG},
343  {"BOR", fun_bor, 1, INT_MAX, FN_REG},
344  {"BOUND", fun_bound, 2, 3, FN_REG},
345  {"BRACKETS", fun_brackets, 1, 1, FN_REG},
346  {"BXOR", fun_bxor, 1, INT_MAX, FN_REG},
347  {"CAND", fun_cand, 2, INT_MAX, FN_NOPARSE},
348  {"CAPSTR", fun_capstr, 1, -1, FN_REG},
349  {"CASE", fun_switch, 3, INT_MAX, FN_NOPARSE},
350  {"CASEALL", fun_switch, 3, INT_MAX, FN_NOPARSE},
351  {"CAT", fun_cat, 1, INT_MAX, FN_REG},
352  {"CBUFFER", fun_cinfo, 1, 1, FN_REG},
353  {"CDESC", fun_cinfo, 1, 1, FN_REG},
354  {"CEMIT", fun_cemit, 2, 3, FN_REG},
355  {"CFLAGS", fun_cflags, 1, 2, FN_REG},
356  {"CHANNELS", fun_channels, 0, 2, FN_REG},
357  {"CLFLAGS", fun_cflags, 1, 2, FN_REG},
358  {"CLOCK", fun_clock, 1, 2, FN_REG},
359  {"CMSGS", fun_cinfo, 1, 1, FN_REG},
360  {"COWNER", fun_cowner, 1, 1, FN_REG},
361  {"CRECALL", fun_crecall, 1, 5, FN_REG},
362  {"CSTATUS", fun_cstatus, 2, 2, FN_REG},
363  {"CTITLE", fun_ctitle, 2, 2, FN_REG},
364  {"CUSERS", fun_cinfo, 1, 1, FN_REG},
365  {"CWHO", fun_cwho, 1, 1, FN_REG},
366  {"CENTER", fun_center, 2, 4, FN_REG},
367  {"CHILDREN", fun_lsearch, 1, 1, FN_REG},
368  {"CHR", fun_chr, 1, 1, FN_REG},
369  {"CHECKPASS", fun_checkpass, 2, 2, FN_REG | FN_WIZARD},
370  {"CLONE", fun_clone, 1, 1, FN_REG},
371  {"CMDS", fun_cmds, 1, 1, FN_REG},
372  {"COMP", fun_comp, 2, 3, FN_REG},
373  {"CON", fun_con, 1, 1, FN_REG},
374  {"COND", fun_if, 2, INT_MAX, FN_NOPARSE},
375  {"CONDALL", fun_if, 2, INT_MAX, FN_NOPARSE},
376  {"CONFIG", fun_config, 1, 1, FN_REG},
377  {"CONN", fun_conn, 1, 1, FN_REG},
378  {"CONTROLS", fun_controls, 2, 2, FN_REG},
379  {"CONVSECS", fun_convsecs, 1, 2, FN_REG},
380  {"CONVUTCSECS", fun_convsecs, 1, 1, FN_REG},
381  {"CONVTIME", fun_convtime, 1, 1, FN_REG},
382  {"COR", fun_cor, 2, INT_MAX, FN_NOPARSE},
383  {"CREATE", fun_create, 1, 2, FN_REG},
384  {"CSECS", fun_csecs, 1, 1, FN_REG},
385  {"CTIME", fun_ctime, 1, 2, FN_REG},
386  {"DEC", fun_dec, 1, 1, FN_REG},
387  {"DECODE64", fun_decode64, 1, -1, FN_REG},
388  {"DECOMPOSE", fun_decompose, 1, -1, FN_REG},
389  {"DECRYPT", fun_decrypt, 2, 3, FN_REG},
390  {"DEFAULT", fun_default, 2, INT_MAX, FN_NOPARSE},
391  {"DELETE", fun_delete, 3, 3, FN_REG},
392  {"DIE", fun_die, 2, 3, FN_REG},
393  {"DIG", fun_dig, 1, 3, FN_REG},
394  {"DIGEST", fun_digest, 2, -2, FN_REG},
395  {"DIST2D", fun_dist2d, 4, 4, FN_REG},
396  {"DIST3D", fun_dist3d, 6, 6, FN_REG},
397  {"DIV", fun_div, 2, 2, FN_REG},
398  {"DOING", fun_doing, 1, 1, FN_REG},
399  {"EDEFAULT", fun_edefault, 2, 2, FN_NOPARSE},
400  {"EDIT", fun_edit, 3, INT_MAX, FN_REG},
401  {"ELEMENT", fun_element, 3, 3, FN_REG},
402  {"ELEMENTS", fun_elements, 2, 4, FN_REG},
403  {"ELIST", fun_itemize, 1, 5, FN_REG},
404  {"ELOCK", fun_elock, 2, 2, FN_REG},
405  {"EMIT", fun_emit, 1, -1, FN_REG},
406  {"ENCODE64", fun_encode64, 1, -1, FN_REG},
407  {"ENCRYPT", fun_encrypt, 2, 3, FN_REG},
408  {"ENTRANCES", fun_entrances, 0, 4, FN_REG},
409  {"ETIMEFMT", fun_etimefmt, 2, 2, FN_REG},
410  {"EQ", fun_eq, 2, 2, FN_REG},
411  {"EVAL", fun_eval, 2, 2, FN_REG},
412  {"ESCAPE", fun_escape, 1, -1, FN_REG},
413  {"EXIT", fun_exit, 1, 1, FN_REG},
414  {"EXTRACT", fun_extract, 1, 4, FN_REG},
415  {"FILTER", fun_filter, 2, 4, FN_REG},
416  {"FILTERBOOL", fun_filter, 2, 4, FN_REG},
417  {"FINDABLE", fun_findable, 2, 2, FN_REG},
418  {"FIRST", fun_first, 1, 2, FN_REG},
419  {"FIRSTOF", fun_firstof, 0, INT_MAX, FN_NOPARSE},
420  {"FLAGS", fun_flags, 0, 1, FN_REG},
421  {"FLIP", fun_flip, 1, -1, FN_REG},
422  {"FLOORDIV", fun_floordiv, 2, 2, FN_REG},
423  {"FN", fun_fn, 1, INT_MAX, FN_NOPARSE},
424  {"FOLD", fun_fold, 2, 4, FN_REG},
425  {"FOLDERSTATS", fun_folderstats, 0, 2, FN_REG},
426  {"FOLLOWERS", fun_followers, 1, 1, FN_REG},
427  {"FOLLOWING", fun_following, 1, 1, FN_REG},
428  {"FOREACH", fun_foreach, 2, 4, FN_REG},
429  {"FRACTION", fun_fraction, 1, 1, FN_REG},
430  {"FUNCTIONS", fun_functions, 0, 1, FN_REG},
431  {"FULLALIAS", fun_fullalias, 1, 1, FN_REG},
432  {"FULLNAME", fun_fullname, 1, 1, FN_REG},
433  {"GET", fun_get, 1, 1, FN_REG},
434  {"GET_EVAL", fun_get_eval, 1, 1, FN_REG},
435  {"GRAB", fun_grab, 2, 3, FN_REG},
436  {"GRABALL", fun_graball, 2, 4, FN_REG},
437  {"GREP", fun_grep, 3, 3, FN_REG},
438  {"GREPI", fun_grep, 3, 3, FN_REG},
439  {"GT", fun_gt, 2, 2, FN_REG},
440  {"GTE", fun_gte, 2, 2, FN_REG},
441  {"HASATTR", fun_hasattr, 2, 2, FN_REG},
442  {"HASATTRP", fun_hasattr, 2, 2, FN_REG},
443  {"HASATTRPVAL", fun_hasattr, 2, 2, FN_REG},
444  {"HASATTRVAL", fun_hasattr, 2, 2, FN_REG},
445  {"HASFLAG", fun_hasflag, 2, 2, FN_REG},
446  {"HASPOWER", fun_haspower, 2, 2, FN_REG},
447  {"HASTYPE", fun_hastype, 2, 2, FN_REG},
448  {"HEIGHT", fun_height, 1, 2, FN_REG},
449  {"HIDDEN", fun_hidden, 1, 1, FN_REG},
450  {"HOME", fun_home, 1, 1, FN_REG},
451  {"HOST", fun_hostname, 1, 1, FN_REG},
452  {"HOSTNAME", fun_hostname, 1, 1, FN_REG},
453  {"IDLE", fun_idlesecs, 1, 1, FN_REG},
454  {"IDLESECS", fun_idlesecs, 1, 1, FN_REG},
455  {"IF", fun_if, 2, 3, FN_NOPARSE},
456  {"IFELSE", fun_if, 3, 3, FN_NOPARSE},
457  {"ILEV", fun_ilev, 0, 0, FN_REG},
458  {"INAME", fun_iname, 1, 1, FN_REG},
459  {"INC", fun_inc, 1, 1, FN_REG},
460  {"INDEX", fun_index, 4, 4, FN_REG},
461  {"INSERT", fun_insert, 3, 4, FN_REG},
462  {"INUM", fun_inum, 1, 1, FN_REG},
463  {"IPADDR", fun_ipaddr, 1, 1, FN_REG},
464  {"ISDAYLIGHT", fun_isdaylight, 0, 0, FN_REG},
465  {"ISDBREF", fun_isdbref, 1, 1, FN_REG},
466  {"ISINT", fun_isint, 1, 1, FN_REG},
467  {"ISNUM", fun_isnum, 1, 1, FN_REG},
468  {"ISOBJID", fun_isobjid, 1, 1, FN_REG},
469  {"ISWORD", fun_isword, 1, 1, FN_REG},
470  {"ITER", fun_iter, 2, 4, FN_NOPARSE},
471  {"ITEMS", fun_items, 2, 2, FN_REG},
472  {"ITEMIZE", fun_itemize, 1, 4, FN_REG},
473  {"ITEXT", fun_itext, 1, 1, FN_REG},
474  {"LAST", fun_last, 1, 2, FN_REG},
475  {"LATTR", fun_lattr, 1, 2, FN_REG},
476  {"LATTRP", fun_lattr, 1, 2, FN_REG},
477  {"LCON", fun_dbwalker, 1, 1, FN_REG},
478  {"LCSTR", fun_lcstr, 1, -1, FN_REG},
479  {"LDELETE", fun_ldelete, 2, 3, FN_REG},
480  {"LEFT", fun_left, 2, 2, FN_REG},
481  {"LEMIT", fun_lemit, 1, -1, FN_REG},
482  {"LETQ", fun_letq, 1, INT_MAX, FN_NOPARSE},
483  {"LEXITS", fun_dbwalker, 1, 1, FN_REG},
484  {"LFLAGS", fun_lflags, 0, 1, FN_REG},
485  {"LINK", fun_link, 2, 3, FN_REG},
486  {"LIST", fun_list, 1, 1, FN_REG},
487  {"LIT", fun_lit, 1, -1, FN_LITERAL},
488  {"LJUST", fun_ljust, 2, 3, FN_REG},
489  {"LLOCKFLAGS", fun_lockflags, 0, 1, FN_REG},
490  {"LLOCKS", fun_locks, 1, 1, FN_REG},
491  {"LMATH", fun_lmath, 2, 3, FN_REG},
492  {"LNUM", fun_lnum, 1, 3, FN_REG},
493  {"LOC", fun_loc, 1, 1, FN_REG},
494  {"LOCALIZE", fun_localize, 1, 1, FN_NOPARSE},
495  {"LOCATE", fun_locate, 3, 3, FN_REG},
496  {"LOCK", fun_lock, 1, 2, FN_REG},
497  {"LOCKFLAGS", fun_lockflags, 0, 1, FN_REG},
498  {"LOCKS", fun_locks, 1, 1, FN_REG},
499  {"LPARENT", fun_lparent, 1, 1, FN_REG},
500  {"LPLAYERS", fun_dbwalker, 1, 1, FN_REG},
501  {"LPORTS", fun_lports, 0, 1, FN_REG},
502  {"LPOS", fun_lpos, 2, 2, FN_REG},
503  {"LSEARCH", fun_lsearch, 1, INT_MAX, FN_REG},
504  {"LSEARCHR", fun_lsearch, 1, INT_MAX, FN_REG},
505  {"LSET", fun_lset, 2, 2, FN_REG},
506  {"LSTATS", fun_lstats, 0, 1, FN_REG},
507  {"LT", fun_lt, 2, 2, FN_REG},
508  {"LTE", fun_lte, 2, 2, FN_REG},
509  {"LTHINGS", fun_dbwalker, 1, 1, FN_REG},
510  {"LVCON", fun_dbwalker, 1, 1, FN_REG},
511  {"LVEXITS", fun_dbwalker, 1, 1, FN_REG},
512  {"LVPLAYERS", fun_dbwalker, 1, 1, FN_REG},
513  {"LVTHINGS", fun_dbwalker, 1, 1, FN_REG},
514  {"LWHO", fun_lwho, 0, 1, FN_REG},
515  {"LWHOID", fun_lwho, 0, 1, FN_REG},
516  {"MAIL", fun_mail, 0, 2, FN_REG},
517  {"MAILFROM", fun_mailfrom, 1, 2, FN_REG},
518  {"MAILSEND", fun_mailsend, 2, 2, FN_REG},
519  {"MAILSTATS", fun_mailstats, 1, 1, FN_REG},
520  {"MAILDSTATS", fun_mailstats, 1, 1, FN_REG},
521  {"MAILFSTATS", fun_mailstats, 1, 1, FN_REG},
522  {"MAILSTATUS", fun_mailstatus, 1, 2, FN_REG},
523  {"MAILSUBJECT", fun_mailsubject, 1, 2, FN_REG},
524  {"MAILTIME", fun_mailtime, 1, 2, FN_REG},
525  {"MALIAS", fun_malias, 0, 2, FN_REG},
526  {"MAP", fun_map, 2, 4, FN_REG},
527  {"MAPSQL", fun_mapsql, 2, 4, FN_REG},
528  {"MATCH", fun_match, 2, 3, FN_REG},
529  {"MATCHALL", fun_matchall, 2, 4, FN_REG},
530  {"MAX", fun_max, 1, INT_MAX, FN_REG},
531  {"MEAN", fun_mean, 1, INT_MAX, FN_REG},
532  {"MEDIAN", fun_median, 1, INT_MAX, FN_REG},
533  {"MEMBER", fun_member, 2, 3, FN_REG},
534  {"MERGE", fun_merge, 3, 3, FN_REG},
535  {"MESSAGE", fun_message, 3, 13, FN_REG},
536  {"MID", fun_mid, 3, 3, FN_REG},
537  {"MIN", fun_min, 1, INT_MAX, FN_REG},
538  {"MIX", fun_mix, 3, 12, FN_REG},
539  {"MODULO", fun_modulo, 2, 2, FN_REG},
540  {"MONEY", fun_money, 1, 1, FN_REG},
541  {"MSECS", fun_msecs, 1, 1, FN_REG},
542  {"MTIME", fun_mtime, 1, 2, FN_REG},
543  {"MUDNAME", fun_mudname, 0, 0, FN_REG},
544  {"MUL", fun_mul, 2, INT_MAX, FN_REG},
545  {"MUNGE", fun_munge, 3, 5, FN_REG},
546  {"MWHO", fun_lwho, 0, 0, FN_REG},
547  {"MWHOID", fun_lwho, 0, 0, FN_REG},
548  {"NAME", fun_name, 0, 2, FN_REG},
549  {"NAMELIST", fun_namelist, 1, 1, FN_REG},
550  {"NAMEGRAB", fun_namegrab, 2, 3, FN_REG},
551  {"NAMEGRABALL", fun_namegraball, 2, 3, FN_REG},
552  {"NAND", fun_nand, 1, INT_MAX, FN_REG},
553  {"NATTR", fun_nattr, 1, 1, FN_REG},
554  {"NATTRP", fun_nattr, 1, 1, FN_REG},
555  {"NCHILDREN", fun_lsearch, 1, 1, FN_REG},
556  {"NCON", fun_dbwalker, 1, 1, FN_REG},
557  {"NCOND", fun_if, 2, INT_MAX, FN_NOPARSE},
558  {"NCONDALL", fun_if, 2, INT_MAX, FN_NOPARSE},
559  {"NEXITS", fun_dbwalker, 1, 1, FN_REG},
560  {"NPLAYERS", fun_dbwalker, 1, 1, FN_REG},
561  {"NEARBY", fun_nearby, 2, 2, FN_REG},
562  {"NEQ", fun_neq, 2, 2, FN_REG},
563  {"NEXT", fun_next, 1, 1, FN_REG},
564