PennMUSH Community

root/1.8.3/trunk/src/funmisc.c

Revision 1117, 20.5 kB (checked in by shawnw, 1 year ago)

Merge with devel

Line 
1 /**
2  * \file funmisc.c
3  *
4  * \brief Miscellaneous functions for mushcode.
5  *
6  *
7  */
8 #include "copyrite.h"
9
10 #include "config.h"
11 #include <time.h>
12 #include <string.h>
13 #include <ctype.h>
14 #include "conf.h"
15 #include "case.h"
16 #include "externs.h"
17 #include "version.h"
18 #include "htab.h"
19 #include "flags.h"
20 #include "lock.h"
21 #include "match.h"
22 #include "mushdb.h"
23 #include "dbdefs.h"
24 #include "parse.h"
25 #include "function.h"
26 #include "command.h"
27 #include "game.h"
28 #include "attrib.h"
29 #include "confmagic.h"
30 #include "ansi.h"
31
32 #ifdef WIN32
33 #pragma warning( disable : 4761)        /* NJG: disable warning re conversion */
34 #endif
35
36 extern FUN flist[];
37 static char *soundex(char *str);
38 extern char cf_motd_msg[BUFFER_LEN], cf_wizmotd_msg[BUFFER_LEN],
39   cf_downmotd_msg[BUFFER_LEN], cf_fullmotd_msg[BUFFER_LEN];
40 extern HASHTAB htab_function;
41
42 /* ARGSUSED */
43 FUNCTION(fun_valid)
44 {
45   /* Checks to see if a given <something> is valid as a parameter of a
46    * given type (such as an object name.)
47    */
48
49   if (!args[0] || !*args[0])
50     safe_str("#-1", buff, bp);
51   else if (!strcasecmp(args[0], "name"))
52     safe_boolean(ok_name(args[1]), buff, bp);
53   else if (!strcasecmp(args[0], "attrname"))
54     safe_boolean(good_atr_name(upcasestr(args[1])), buff, bp);
55   else if (!strcasecmp(args[0], "playername"))
56     safe_boolean(ok_player_name(args[1], executor, executor), buff, bp);
57   else if (!strcasecmp(args[0], "password"))
58     safe_boolean(ok_password(args[1]), buff, bp);
59   else if (!strcasecmp(args[0], "command"))
60     safe_boolean(ok_command_name(upcasestr(args[1])), buff, bp);
61   else if (!strcasecmp(args[0], "function"))
62     safe_boolean(ok_function_name(upcasestr(args[1])), buff, bp);
63   else
64     safe_str("#-1", buff, bp);
65 }
66
67 /* ARGSUSED */
68 FUNCTION(fun_pemit)
69 {
70   int ns = string_prefix(called_as, "NS");
71   int flags = PEMIT_LIST;
72   dbref saved_orator = orator;
73   if (!command_check_byname(executor, ns ? "@nspemit" : "@pemit") ||
74       fun->flags & FN_NOSIDEFX) {
75     safe_str(T(e_perm), buff, bp);
76     return;
77   }
78   orator = executor;
79   if (ns)
80     flags |= PEMIT_SPOOF;
81   do_pemit_list(executor, args[0], args[1], flags);
82   orator = saved_orator;
83 }
84
85 FUNCTION(fun_message)
86 {
87   int i;
88   char *argv[10];
89
90   for (i = 0; (i + 3) < nargs; i++) {
91     argv[i] = args[i + 3];
92   }
93
94   do_message_list(executor, executor, args[0], args[2], args[1], 0, i, argv);
95 }
96
97 /* ARGSUSED */
98 FUNCTION(fun_oemit)
99 {
100   int ns = string_prefix(called_as, "NS");
101   int flags = ns ? PEMIT_SPOOF : 0;
102   if (!command_check_byname(executor, ns ? "@nsoemit" : "@oemit") ||
103       fun->flags & FN_NOSIDEFX) {
104     safe_str(T(e_perm), buff, bp);
105     return;
106   }
107   orator = executor;
108   do_oemit_list(executor, args[0], args[1], flags);
109 }
110
111 /* ARGSUSED */
112 FUNCTION(fun_emit)
113 {
114   int ns = string_prefix(called_as, "NS");
115   int flags = ns ? PEMIT_SPOOF : 0;
116   if (!command_check_byname(executor, ns ? "@nsemit" : "@emit") ||
117       fun->flags & FN_NOSIDEFX) {
118     safe_str(T(e_perm), buff, bp);
119     return;
120   }
121   orator = executor;
122   do_emit(executor, args[0], flags);
123 }
124
125 /* ARGSUSED */
126 FUNCTION(fun_remit)
127 {
128   int ns = string_prefix(called_as, "NS");
129   int flags = ns ? PEMIT_SPOOF : 0;
130   if (!command_check_byname(executor, ns ? "@nsremit" : "@remit") ||
131       fun->flags & FN_NOSIDEFX) {
132     safe_str(T(e_perm), buff, bp);
133     return;
134   }
135   orator = executor;
136   do_remit(executor, args[0], args[1], flags);
137 }
138
139 /* ARGSUSED */
140 FUNCTION(fun_lemit)
141 {
142   int ns = string_prefix(called_as, "NS");
143   int flags = ns ? PEMIT_SPOOF : 0;
144   if (!command_check_byname(executor, ns ? "@nslemit" : "@lemit") ||
145       fun->flags & FN_NOSIDEFX) {
146     safe_str(T(e_perm), buff, bp);
147     return;
148   }
149   orator = executor;
150   do_lemit(executor, args[0], flags);
151 }
152
153 /* ARGSUSED */
154 FUNCTION(fun_zemit)
155 {
156   int ns = string_prefix(called_as, "NS");
157   int flags = ns ? PEMIT_SPOOF : 0;
158   if (!command_check_byname(executor, ns ? "@nszemit" : "@zemit") ||
159       fun->flags & FN_NOSIDEFX) {
160     safe_str(T(e_perm), buff, bp);
161     return;
162   }
163   orator = executor;
164   do_zemit(executor, args[0], args[1], flags);
165 }
166
167 /* ARGSUSED */
168 FUNCTION(fun_prompt)
169 {
170   int ns = string_prefix(called_as, "NS");
171   int flags = PEMIT_LIST | PEMIT_PROMPT;
172   if (!command_check_byname(executor, ns ? "@nspemit" : "@pemit") ||
173       fun->flags & FN_NOSIDEFX) {
174     safe_str(T(e_perm), buff, bp);
175     return;
176   }
177   orator = executor;
178   if (ns)
179     flags |= PEMIT_SPOOF;
180   do_pemit_list(executor, args[0], args[1], flags);
181 }
182
183
184 extern signed char qreg_indexes[UCHAR_MAX + 1];
185 /* ARGSUSED */
186 FUNCTION(fun_setq)
187 {
188   /* sets a variable into a local register */
189   int qindex;
190   int n;
191
192   if ((nargs % 2) != 0) {
193     safe_format(buff, bp,
194                 T("#-1 FUNCTION (%s) EXPECTS AN EVEN NUMBER OF ARGUMENTS"),
195                 called_as);
196     return;
197   }
198
199   for (n = 0; n < nargs; n += 2) {
200     if (*args[n] && (*(args[n] + 1) == '\0') &&
201         ((qindex = qreg_indexes[(unsigned char) args[n][0]]) != -1)
202         && global_eval_context.renv[qindex]) {
203       strcpy(global_eval_context.renv[qindex], args[n + 1]);
204       if (n == 0 && !strcmp(called_as, "SETR"))
205         safe_strl(args[n + 1], arglens[n + 1], buff, bp);
206     } else
207       safe_str(T("#-1 REGISTER OUT OF RANGE"), buff, bp);
208   }
209 }
210
211 FUNCTION(fun_letq)
212 {
213   char **values = NULL;
214   int *regs = NULL;
215   int npairs;
216   int n;
217   char tbuf[BUFFER_LEN], *tbp;
218   char *preserve[NUMQ];
219   const char *p;
220
221   if ((nargs % 2) != 1) {
222     safe_str(T("#-1 FUNCTION (letq) EXPECTS AN ODD NUMBER OF ARGUMENTS"),
223              buff, bp);
224     return;
225   }
226
227   npairs = (nargs - 1) / 2;
228
229   for (n = 0; n < NUMQ; n++)
230     preserve[n] = NULL;
231
232   if (npairs) {
233     values = mush_calloc(npairs, sizeof(char *), "letq.values");
234     if (!values) {
235       safe_str(T("#-1 UNABLE TO ALLOCATE MEMORY"), buff, bp);
236       return;
237     }
238
239     regs = mush_calloc(npairs, sizeof(int), "letq.registers");
240     if (!regs) {
241       safe_str(T("#-1 UNABLE TO ALLOCATE MEMORY"), buff, bp);
242       mush_free(values, "letq.values");
243       return;
244     }
245
246     for (n = 0; n < npairs; n++) {
247       int i = n * 2;
248
249       tbp = tbuf;
250       p = args[i];
251       process_expression(tbuf, &tbp, &p, executor, caller, enactor, PE_DEFAULT,
252                          PT_DEFAULT, pe_info);
253       *tbp = '\0';
254       regs[n] = qreg_indexes[(unsigned char) tbuf[0]];
255       if (regs[n] < 0) {
256         safe_str(T("#-1 REGISTER OUT OF RANGE"), buff, bp);
257         goto cleanup;
258       }
259
260       tbp = tbuf;
261       p = args[i + 1];
262       process_expression(tbuf, &tbp, &p, executor, caller, enactor, PE_DEFAULT,
263                          PT_DEFAULT, pe_info);
264       *tbp = '\0';
265       values[n] = mush_strdup(tbuf, "letq.value");
266       if (!values[n]) {
267         safe_str(T("#-1 UNABLE TO ALLOCATE MEMORY"), buff, bp);
268         goto cleanup;
269       }
270     }
271
272     for (n = 0; n < npairs; n++) {
273       save_partial_global_reg("letq", preserve, regs[n]);
274       mush_strncpy(global_eval_context.renv[regs[n]], values[n], BUFFER_LEN);
275     }
276   }
277   p = args[nargs - 1];
278   process_expression(buff, bp, &p, executor, caller, enactor, PE_DEFAULT,
279                      PT_DEFAULT, pe_info);
280
281 cleanup:
282   if (regs)
283     mush_free(regs, "letq.registers");
284   if (values) {
285     restore_partial_global_regs("letq", preserve);
286     for (n = 0; n < npairs; n++)
287       mush_free(values[n], "letq.value");
288     mush_free(values, "letq.values");
289   }
290 }
291
292 /* ARGSUSED */
293 FUNCTION(fun_r)
294 {
295   /* returns a local register */
296   int qindex;
297
298   if (*args[0] && (*(args[0] + 1) == '\0') &&
299       ((qindex = qreg_indexes[(unsigned char) args[0][0]]) != -1)
300       && global_eval_context.renv[qindex])
301     safe_str(global_eval_context.renv[qindex], buff, bp);
302   else
303     safe_str(T("#-1 REGISTER OUT OF RANGE"), buff, bp);
304 }
305
306 /* --------------------------------------------------------------------------
307  * Utility functions: RAND, DIE, SECURE, SPACE, BEEP, SWITCH, EDIT,
308  *      ESCAPE, SQUISH, ENCRYPT, DECRYPT, LIT
309  */
310
311 /* ARGSUSED */
312 FUNCTION(fun_rand)
313 {
314   /*
315    * Uses Sh'dow's random number generator, found in utils.c.  Better
316    * distribution than original, w/ minimal speed losses.
317    */
318   int low, high;
319   if (!is_integer(args[0])) {
320     safe_str(T(e_int), buff, bp);
321     return;
322   }
323   if (nargs == 1) {
324     low = 0;
325     high = parse_integer(args[0]) - 1;
326   } else {
327     if (!is_integer(args[1])) {
328       safe_str(T(e_ints), buff, bp);
329       return;
330     }
331     low = parse_integer(args[0]);
332     high = parse_integer(args[1]);
333   }
334
335   if (low > high) {
336     safe_str(T(e_range), buff, bp);
337     return;
338   }
339
340   safe_integer(get_random_long(low, high), buff, bp);
341 }
342
343 /* ARGSUSED */
344 FUNCTION(fun_die)
345 {
346   unsigned int n;
347   unsigned int die;
348   unsigned int count;
349   unsigned int total = 0;
350   int show_all = 0, first = 1;
351
352   if (!is_uinteger(args[0]) || !is_uinteger(args[1])) {
353     safe_str(T(e_uints), buff, bp);
354     return;
355   }
356   n = parse_uinteger(args[0]);
357   die = parse_uinteger(args[1]);
358   if (nargs == 3)
359     show_all = parse_boolean(args[2]);
360
361   if (n == 0 || n > 20) {
362     safe_str(T("#-1 NUMBER OUT OF RANGE"), buff, bp);
363     return;
364   }
365   if (show_all) {
366     for (count = 0; count < n; count++) {
367       if (first)
368         first = 0;
369       else
370         safe_chr(' ', buff, bp);
371       safe_uinteger(get_random_long(1, die), buff, bp);
372     }
373   } else {
374     for (count = 0; count < n; count++)
375       total += get_random_long(1, die);
376
377     safe_uinteger(total, buff, bp);
378   }
379 }
380
381 /* ARGSUSED */
382 FUNCTION(fun_switch)
383 {
384   /* this works a bit like the @switch command: it returns the string
385    * appropriate to the match. It picks the first match, like @select
386    * does, though.
387    * Args to this function are passed unparsed. Args are not evaluated
388    * until they are needed.
389    */
390
391   int j, per;
392   char mstr[BUFFER_LEN], pstr[BUFFER_LEN], *dp;
393   char const *sp;
394   char *tbuf1 = NULL;
395   int first = 1, found = 0, exact = 0;
396
397   if (strstr(called_as, "ALL"))
398     first = 0;
399
400   if (string_prefix(called_as, "CASE"))
401     exact = 1;
402
403   dp = mstr;
404   sp = args[0];
405   process_expression(mstr, &dp, &sp, executor, caller, enactor,
406                      PE_DEFAULT, PT_DEFAULT, pe_info);
407   *dp = '\0';
408
409   /* try matching, return match immediately when found */
410
411   for (j = 1; j < (nargs - 1); j += 2) {
412     dp = pstr;
413     sp = args[j];
414     process_expression(pstr, &dp, &sp, executor, caller, enactor,
415                        PE_DEFAULT, PT_DEFAULT, pe_info);
416     *dp = '\0';
417
418     if ((!exact)
419         ? local_wild_match(pstr, mstr)
420         : (strcmp(pstr, mstr) == 0)) {
421       /* If there's a #$ in a switch's action-part, replace it with
422        * the value of the conditional (mstr) before evaluating it.
423        */
424       if (!exact)
425         tbuf1 = replace_string("#$", mstr, args[j + 1]);
426       else
427         tbuf1 = args[j + 1];
428
429       sp = tbuf1;
430
431       per = process_expression(buff, bp, &sp,
432                                executor, caller, enactor,
433                                PE_DEFAULT, PT_DEFAULT, pe_info);
434       if (!exact)
435         mush_free((Malloc_t) tbuf1, "replace_string.buff");
436       found = 1;
437       if (per || first)
438         return;
439     }
440   }
441
442   if (!(nargs & 1) && !found) {
443     /* Default case */
444     if (!exact) {
445       tbuf1 = replace_string("#$", mstr, args[nargs - 1]);
446       sp = tbuf1;
447     } else
448       sp = args[nargs - 1];
449     process_expression(buff, bp, &sp, executor, caller, enactor,
450                        PE_DEFAULT, PT_DEFAULT, pe_info);
451     if (!exact)
452       mush_free((Malloc_t) tbuf1, "replace_string.buff");
453   }
454 }
455
456 FUNCTION(fun_reswitch)
457 {
458   /* this works a bit like the @switch/regexp command */
459
460   int j, per;
461   char mstr[BUFFER_LEN], pstr[BUFFER_LEN], *dp;
462   char const *sp;
463   char *tbuf1;
464   int first = 1, found = 0, cs = 1;
465
466   if (strstr(called_as, "ALL"))
467     first = 0;
468
469   if (strcmp(called_as, "RESWITCHI") == 0
470       || strcmp(called_as, "RESWITCHALLI") == 0)
471     cs = 0;
472
473   dp = mstr;
474   sp = args[0];
475   process_expression(mstr, &dp, &sp, executor, caller, enactor,
476                      PE_DEFAULT, PT_DEFAULT, pe_info);
477   *dp = '\0';
478
479   /* try matching, return match immediately when found */
480
481   for (j = 1; j < (nargs - 1); j += 2) {
482     dp = pstr;
483     sp = args[j];
484     process_expression(pstr, &dp, &sp, executor, caller, enactor,
485                        PE_DEFAULT, PT_DEFAULT, pe_info);
486     *dp = '\0';
487
488     if (quick_regexp_match(pstr, mstr, cs)) {
489       /* If there's a #$ in a switch's action-part, replace it with
490        * the value of the conditional (mstr) before evaluating it.
491        */
492       tbuf1 = replace_string("#$", mstr, args[j + 1]);
493
494       sp = tbuf1;
495
496       per = process_expression(buff, bp, &sp,
497