PennMUSH Community

root/1.8.3/trunk/src/function.c

Revision 1182, 53.1 kB (checked in by shawnw, 8 months ago)

#7488: *powers() documentation

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
33 static void func_hash_insert(const char *name, FUN *func);
34 extern void local_functions(void);
35 static int apply_restrictions(unsigned int result, const char *restriction);
36 static char *build_function_report(dbref player, FUN *fp);
37
38 USERFN_ENTRY *userfn_tab;   /**< Table of user-defined functions */
39 HASHTAB htab_function;      /**< Function hash table */
40 HASHTAB htab_user_function; /**< User-defined function hash table */
41 slab *function_slab; /**< slab for 'struct fun' allocations */
42 slab *userfun_slab; /**< slab for 'struct userfn_entry' allocations */
43
44 /* -------------------------------------------------------------------------*
45  * Utilities.
46  */
47
48 /* Save and restore regexp data */
49 void
50 save_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
58 void
59 restore_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  */
69 void
70 save_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  */
77 void
78 restore_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  */
93 void
94 save_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  */
110 void
111 restore_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  */
129 void
130 free_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  */
142 void
143 init_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  */
154 void
155 load_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  */
171 void
172 save_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  */
184 void
185 restore_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  */
203 void
204 save_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  */
233 void
234 restore_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  */
273 int
274 delim_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  */
300 typedef 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  */
312 FUNTAB 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   {"ANSI", fun_ansi, 2, -2, FN_REG},
329 #ifdef ANSI_DEBUG
330   {"ANSIINSPECT", fun_ansiinspect, 1, 2, FN_REG},
331 #endif
332   {"APOSS", fun_aposs, 1, 1, FN_REG},
333   {"ART", fun_art, 1, 1, FN_REG},
334   {"ATRLOCK", fun_atrlock, 1, 2, FN_REG},
335   {"ATTRIB_SET", fun_attrib_set, 1, -2, FN_REG},
336   {"BAND", fun_band, 1, INT_MAX, FN_REG},
337   {"BASECONV", fun_baseconv, 3, 3, FN_REG},
338   {"BEEP", fun_beep, 0, 1, FN_REG},
339   {"BEFORE", fun_before, 2, 2, FN_REG},
340   {"BNAND", fun_bnand, 2, 2, FN_REG},
341   {"BNOT", fun_bnot, 1, 1, FN_REG},
342   {"BOR", fun_bor, 1, INT_MAX, FN_REG},
343   {"BOUND", fun_bound, 2, 3, FN_REG},
344   {"BRACKETS", fun_brackets, 1, 1, FN_REG},
345   {"BXOR", fun_bxor, 1, INT_MAX, FN_REG},
346   {"CAND", fun_cand, 2, INT_MAX, FN_NOPARSE},
347   {"CAPSTR", fun_capstr, 1, -1, FN_REG},
348   {"CASE", fun_switch, 3, INT_MAX, FN_NOPARSE},
349   {"CASEALL", fun_switch, 3, INT_MAX, FN_NOPARSE},
350   {"CAT", fun_cat, 1, INT_MAX, FN_REG},
351   {"CBUFFER", fun_cinfo, 1, 1, FN_REG},
352   {"CDESC", fun_cinfo, 1, 1, FN_REG},
353   {"CEMIT", fun_cemit, 2, 3, FN_REG},
354   {"CFLAGS", fun_cflags, 1, 2, FN_REG},
355   {"CHANNELS", fun_channels, 0, 2, FN_REG},
356   {"CLFLAGS", fun_cflags, 1, 2, FN_REG},
357   {"CLOCK", fun_clock, 1, 2, FN_REG},
358   {"CMSGS", fun_cinfo, 1, 1, FN_REG},
359   {"COWNER", fun_cowner, 1, 1, FN_REG},
360   {"CRECALL", fun_crecall, 1, 5, FN_REG},
361   {"CSTATUS", fun_cstatus, 2, 2, FN_REG},
362   {"CTITLE", fun_ctitle, 2, 2, FN_REG},
363   {"CUSERS", fun_cinfo, 1, 1, FN_REG},
364   {"CWHO", fun_cwho, 1, 1, FN_REG},
365   {"CENTER", fun_center, 2, 4, FN_REG},
366   {"CHILDREN", fun_lsearch, 1, 1, FN_REG},
367   {"CHR", fun_chr, 1, 1, FN_REG},
368   {"CHECKPASS", fun_checkpass, 2, 2, FN_REG | FN_WIZARD},
369   {"CLONE", fun_clone, 1, 1, FN_REG},
370   {"CMDS", fun_cmds, 1, 1, FN_REG},
371   {"COMP", fun_comp, 2, 3, FN_REG},
372   {"CON", fun_con, 1, 1, FN_REG},
373   {"COND", fun_if, 2, INT_MAX, FN_NOPARSE},
374   {"CONDALL", fun_if, 2, INT_MAX, FN_NOPARSE},
375   {"CONFIG", fun_config, 1, 1, FN_REG},
376   {"CONN", fun_conn, 1, 1, FN_REG},
377   {"CONTROLS", fun_controls, 2, 2, FN_REG},
378   {"CONVSECS", fun_convsecs, 1, 2, FN_REG},
379   {"CONVUTCSECS", fun_convsecs, 1, 1, FN_REG},
380   {"CONVTIME", fun_convtime, 1, 1, FN_REG},
381   {"COR", fun_cor, 2, INT_MAX, FN_NOPARSE},
382   {"CREATE", fun_create, 1, 2, FN_REG},
383   {"CSECS", fun_csecs, 1, 1, FN_REG},
384   {"CTIME", fun_ctime, 1, 2, FN_REG},
385   {"DEC", fun_dec, 1, 1, FN_REG},
386   {"DECODE64", fun_decode64, 1, -1, FN_REG},
387   {"DECOMPOSE", fun_decompose, 1, -1, FN_REG},
388   {"DECRYPT", fun_decrypt, 2, 3, FN_REG},
389   {"DEFAULT", fun_default, 2, INT_MAX, FN_NOPARSE},
390   {"DELETE", fun_delete, 3, 3, FN_REG},
391   {"DIE", fun_die, 2, 3, FN_REG},
392   {"DIG", fun_dig, 1, 3, FN_REG},
393   {"DIGEST", fun_digest, 2, -2, FN_REG},
394   {"DIST2D", fun_dist2d, 4, 4, FN_REG},
395   {"DIST3D", fun_dist3d, 6, 6, FN_REG},
396   {"DIV", fun_div, 2, 2, FN_REG},
397   {"DOING", fun_doing, 1, 1, FN_REG},
398   {"EDEFAULT", fun_edefault, 2, 2, FN_NOPARSE},
399   {"EDIT", fun_edit, 3, INT_MAX, FN_REG},
400   {"ELEMENT", fun_element, 3, 3, FN_REG},
401   {"ELEMENTS", fun_elements, 2, 4, FN_REG},
402   {"ELIST", fun_itemize, 1, 5, FN_REG},
403   {"ELOCK", fun_elock, 2, 2, FN_REG},
404   {"EMIT", fun_emit, 1, -1, FN_REG},
405   {"ENCODE64", fun_encode64, 1, -1, FN_REG},
406   {"ENCRYPT", fun_encrypt, 2, 3, FN_REG},
407   {"ENTRANCES", fun_entrances, 0, 4, FN_REG},
408   {"ETIMEFMT", fun_etimefmt, 2, 2, FN_REG},
409   {"EQ", fun_eq, 2, 2, FN_REG},
410   {"EVAL", fun_eval, 2, 2, FN_REG},
411   {"ESCAPE", fun_escape, 1, -1, FN_REG},
412   {"EXIT", fun_exit, 1, 1, FN_REG},
413   {"EXTRACT", fun_extract, 1, 4, FN_REG},
414   {"FILTER", fun_filter, 2, 4, FN_REG},
415   {"FILTERBOOL", fun_filter, 2, 4, FN_REG},
416   {"FINDABLE", fun_findable, 2, 2, FN_REG},
417   {"FIRST", fun_first, 1, 2, FN_REG},
418   {"FIRSTOF", fun_firstof, 0, INT_MAX, FN_NOPARSE},
419   {"FLAGS", fun_flags, 0, 1, FN_REG},
420   {"FLIP", fun_flip, 1, -1, FN_REG},
421   {"FLOORDIV", fun_floordiv, 2, 2, FN_REG},
422   {"FN", fun_fn, 1, INT_MAX, FN_NOPARSE},
423   {"FOLD", fun_fold, 2, 4, FN_REG},
424   {"FOLDERSTATS", fun_folderstats, 0, 2, FN_REG},
425   {"FOLLOWERS", fun_followers, 1, 1, FN_REG},
426   {"FOLLOWING", fun_following, 1, 1, FN_REG},
427   {"FOREACH", fun_foreach, 2, 4, FN_REG},
428   {"FRACTION", fun_fraction, 1, 1, FN_REG},
429   {"FUNCTIONS", fun_functions, 0, 1, FN_REG},
430   {"FULLALIAS", fun_fullalias, 1, 1, FN_REG},
431   {"FULLNAME", fun_fullname, 1, 1, FN_REG},
432   {"GET", fun_get, 1, 1, FN_REG},
433   {"GET_EVAL", fun_get_eval, 1, 1, FN_REG},
434   {"GRAB", fun_grab, 2, 3, FN_REG},
435   {"GRABALL", fun_graball, 2, 4, FN_REG},
436   {"GREP", fun_grep, 3, 3, FN_REG},
437   {"GREPI", fun_grep, 3, 3, FN_REG},
438   {"GT", fun_gt