PennMUSH Community

root/1.8.3/trunk/src/funstr.c

Revision 1117, 49.2 kB (checked in by shawnw, 11 months ago)

Merge with devel

Line 
1 /**
2  * \file funstr.c
3  *
4  * \brief String functions for mushcode.
5  *
6  *
7  */
8 #include "copyrite.h"
9
10 #include "config.h"
11 #include <string.h>
12 #include <ctype.h>
13 #include <limits.h>
14 #include <locale.h>
15 #include <stddef.h>
16 #include "conf.h"
17 #include "externs.h"
18 #include "ansi.h"
19 #include "case.h"
20 #include "match.h"
21 #include "parse.h"
22 #include "pueblo.h"
23 #include "attrib.h"
24 #include "flags.h"
25 #include "dbdefs.h"
26 #include "mushdb.h"
27 #include "htab.h"
28 #include "lock.h"
29 #include "sort.h"
30 #include "confmagic.h"
31
32
33 #ifdef WIN32
34 #pragma warning( disable : 4761)        /* NJG: disable warning re conversion */
35 #endif
36
37 #define MAX_COLS 32  /**< Maximum number of columns for align() */
38 static int wraplen(char *str, size_t maxlen);
39 static int align_one_line(char *buff, char **bp, int ncols,
40                           int cols[MAX_COLS], int calign[MAX_COLS],
41                           char *ptrs[MAX_COLS], ansi_string *as[MAX_COLS],
42                           int linenum, char *fieldsep, int fslen, char *linesep,
43                           int lslen, char filler);
44 static int comp_gencomp(dbref executor, char *left, char *right, char *type);
45 void init_pronouns(void);
46
47 extern signed char qreg_indexes[UCHAR_MAX + 1];
48
49 /** Return an indicator of a player's gender.
50  * \param player player whose gender is to be checked.
51  * \retval 0 neuter.
52  * \retval 1 female.
53  * \retval 2 male.
54  * \retval 3 plural.
55  */
56 int
57 get_gender(dbref player)
58 {
59   ATTR *a;
60
61   a = atr_get(player, "SEX");
62
63   if (!a)
64     return 0;
65
66   switch (*atr_value(a)) {
67   case 'T':
68   case 't':
69   case 'P':
70   case 'p':
71     return 3;
72   case 'M':
73   case 'm':
74     return 2;
75   case 'F':
76   case 'f':
77   case 'W':
78   case 'w':
79     return 1;
80   default:
81     return 0;
82   }
83 }
84
85 char *subj[4];  /**< Subjective pronouns */
86 char *poss[4];  /**< Possessive pronouns */
87 char *obj[4];   /**< Objective pronouns */
88 char *absp[4];  /**< Absolute possessive pronouns */
89
90 /** Macro to set a pronoun entry based on whether we're translating or not */
91 #define SET_PRONOUN(p,v,u)  p = strdup((translate) ? (v) : (u))
92
93 /** Initialize the pronoun translation strings.
94  * This function sets up the values of the arrays of subjective,
95  * possessive, objective, and absolute possessive pronouns with
96  * locale-appropriate values.
97  */
98 void
99 init_pronouns(void)
100 {
101   int translate = 0;
102 #if defined(HAS_SETLOCALE) && defined(LC_MESSAGES)
103   char *loc;
104   if ((loc = setlocale(LC_MESSAGES, NULL))) {
105     if (strcmp(loc, "C") && strncmp(loc, "en", 2))
106       translate = 1;
107   }
108 #endif
109   SET_PRONOUN(subj[0], T("pronoun:neuter,subjective"), "it");
110   SET_PRONOUN(subj[1], T("pronoun:feminine,subjective"), "she");
111   SET_PRONOUN(subj[2], T("pronoun:masculine,subjective"), "he");
112   SET_PRONOUN(subj[3], T("pronoun:plural,subjective"), "they");
113   SET_PRONOUN(poss[0], T("pronoun:neuter,possessive"), "its");
114   SET_PRONOUN(poss[1], T("pronoun:feminine,possessive"), "her");
115   SET_PRONOUN(poss[2], T("pronoun:masculine,possessive"), "his");
116   SET_PRONOUN(poss[3], T("pronoun:plural,possessive"), "their");
117   SET_PRONOUN(obj[0], T("pronoun:neuter,objective"), "it");
118   SET_PRONOUN(obj[1], T("pronoun:feminine,objective"), "her");
119   SET_PRONOUN(obj[2], T("pronoun:masculine,objective"), "him");
120   SET_PRONOUN(obj[3], T("pronoun:plural,objective"), "them");
121   SET_PRONOUN(absp[0], T("pronoun:neuter,absolute possessive"), "its");
122   SET_PRONOUN(absp[1], T("pronoun:feminine,absolute possessive"), "hers");
123   SET_PRONOUN(absp[2], T("pronoun:masculine,absolute possessive"), "his");
124   SET_PRONOUN(absp[3], T("pronoun:plural,absolute possessive "), "theirs");
125 }
126
127 #undef SET_PRONOUN
128
129 /* ARGSUSED */
130 FUNCTION(fun_isword)
131 {
132   /* is every character a letter? */
133   char *p;
134   if (!args[0] || !*args[0]) {
135     safe_chr('0', buff, bp);
136     return;
137   }
138   for (p = args[0]; *p; p++) {
139     if (!isalpha((unsigned char) *p)) {
140       safe_chr('0', buff, bp);
141       return;
142     }
143   }
144   safe_chr('1', buff, bp);
145 }
146
147 /* ARGSUSED */
148 FUNCTION(fun_capstr)
149 {
150   char *p;
151   p = skip_leading_ansi(args[0]);
152   if (!p) {
153     safe_strl(args[0], arglens[0], buff, bp);
154     return;
155   } else if (p != args[0]) {
156     char x = *p;
157     *p = '\0';
158     safe_strl(args[0], p - args[0], buff, bp);
159     *p = x;
160   }
161   if (*p) {
162     safe_chr(UPCASE(*p), buff, bp);
163     p++;
164   }
165   if (*p)
166     safe_str(p, buff, bp);
167 }
168
169 /* ARGSUSED */
170 FUNCTION(fun_art)
171 {
172   /* checks a word and returns the appropriate article, "a" or "an" */
173   char c;
174   char *p = skip_leading_ansi(args[0]);
175
176   if (!p) {
177     safe_chr('a', buff, bp);
178     return;
179   }
180   c = DOWNCASE(*p);
181   if (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u')
182     safe_str("an", buff, bp);
183   else
184     safe_chr('a', buff, bp);
185 }
186
187 /* ARGSUSED */
188 FUNCTION(fun_subj)
189 {
190   dbref thing;
191
192   thing = match_thing(executor, args[0]);
193   if (thing == NOTHING) {
194     safe_str(T(e_match), buff, bp);
195     return;
196   }
197   safe_str(subj[get_gender(thing)], buff, bp);
198 }
199
200 /* ARGSUSED */
201 FUNCTION(fun_poss)
202 {
203   dbref thing;
204
205   thing = match_thing(executor, args[0]);
206   if (thing == NOTHING) {
207     safe_str(T(e_match), buff, bp);
208     return;
209   }
210   safe_str(poss[get_gender(thing)], buff, bp);
211 }
212
213 /* ARGSUSED */
214 FUNCTION(fun_obj)
215 {
216   dbref thing;
217
218   thing = match_thing(executor, args[0]);
219   if (thing == NOTHING) {
220     safe_str(T(e_match), buff, bp);
221     return;
222   }
223   safe_str(obj[get_gender(thing)], buff, bp);
224 }
225
226 /* ARGSUSED */
227 FUNCTION(fun_aposs)
228 {
229   dbref thing;
230
231   thing = match_thing(executor, args[0]);
232   if (thing == NOTHING) {
233     safe_str(T(e_match), buff, bp);
234     return;
235   }
236   safe_str(absp[get_gender(thing)], buff, bp);
237 }
238
239 /* ARGSUSED */
240 FUNCTION(fun_alphamax)
241 {
242   char amax[BUFFER_LEN];
243   char *c;
244   int j, m = 0;
245   size_t len;
246
247   c = remove_markup(args[0], &len);
248   memcpy(amax, c, len);
249   for (j = 1; j < nargs; j++) {
250     c = remove_markup(args[j], &len);
251     if (strcoll(amax, c) < 0) {
252       memcpy(amax, c, len);
253       m = j;
254     }
255   }
256   safe_strl(args[m], arglens[m], buff, bp);
257 }
258
259 /* ARGSUSED */
260 FUNCTION(fun_alphamin)
261 {
262   char amin[BUFFER_LEN];
263   char *c;
264   int j, m = 0;
265   size_t len;
266
267   c = remove_markup(args[0], &len);
268   memcpy(amin, c, len);
269   for (j = 1; j < nargs; j++) {
270     c = remove_markup(args[j], &len);
271     if (strcoll(amin, c) > 0) {
272       memcpy(amin, c, len);
273       m = j;
274     }
275   }
276   safe_strl(args[m], arglens[m], buff, bp);
277 }
278
279 /* ARGSUSED */
280 FUNCTION(fun_strlen)
281 {
282   safe_integer(ansi_strlen(args[0]), buff, bp);
283 }
284
285 /* ARGSUSED */
286 FUNCTION(fun_mid)
287 {
288   ansi_string *as;
289   int pos, len;
290
291   if (!is_integer(args[1]) || !is_integer(args[2])) {
292     safe_str(T(e_ints), buff, bp);
293     return;
294   }
295
296   as = parse_ansi_string(args[0]);
297   pos = parse_integer(args[1]);
298   len = parse_integer(args[2]);
299
300   if (pos < 0) {
301     safe_str(T(e_range), buff, bp);
302     free_ansi_string(as);
303     return;
304   }
305
306   if (len < 0) {
307     pos = pos + len + 1;
308     if (pos < 0)
309       pos = 0;
310     len = -len;
311   }
312
313   safe_ansi_string(as, pos, len, buff, bp);
314   free_ansi_string(as);
315 }
316
317 /* ARGSUSED */
318 FUNCTION(fun_left)
319 {
320   int len;
321   ansi_string *as;
322
323   if (!is_integer(args[1])) {
324     safe_str(T(e_int), buff, bp);
325     return;
326   }
327   len = parse_integer(args[1]);
328
329   if (len < 0) {
330     safe_str(T(e_range), buff, bp);
331     return;
332   }
333
334   as = parse_ansi_string(args[0]);
335   safe_ansi_string(as, 0, len, buff, bp);
336   free_ansi_string(as);
337 }
338
339 /* ARGSUSED */
340 FUNCTION(fun_right)
341 {
342   int len;
343   ansi_string *as;
344
345   if (!is_integer(args[1])) {
346     safe_str(T(e_int), buff, bp);
347     return;
348   }
349   len = parse_integer(args[1]);
350
351   if (len < 0) {
352     safe_str(T(e_range), buff, bp);
353     return;
354   }
355
356   as = parse_ansi_string(args[0]);
357   if (len > as->len)
358     safe_strl(args[0], arglens[0], buff, bp);
359   else
360     safe_ansi_string(as, as->len - len, len, buff, bp);
361   free_ansi_string(as);
362 }
363
364 /* ARGSUSED */
365 FUNCTION(fun_strinsert)
366 {
367   /* Insert a string into another */
368   ansi_string *dst, *src;
369   int pos;
370
371   if (!is_integer(args[1])) {
372     safe_str(e_int, buff, bp);
373     return;
374   }
375
376   pos = parse_integer(args[1]);
377   if (pos < 0) {
378     safe_str(T(e_range), buff, bp);
379     return;
380   }
381
382   dst = parse_ansi_string(args[0]);
383   if (pos > dst->len) {
384     safe_strl(args[0], arglens[0], buff, bp);
385     safe_strl(args[2], arglens[0], buff, bp);
386     free_ansi_string(dst);
387     return;
388   }
389
390   src = parse_ansi_string(args[2]);
391
392   ansi_string_insert(dst, pos, src);
393
394   safe_ansi_string(dst, 0, dst->len, buff, bp);
395
396   free_ansi_string(dst);
397   free_ansi_string(src);
398 }
399
400 /* ARGSUSED */
401 FUNCTION(fun_delete)
402 {
403   ansi_string *as;
404   int pos, pos2, num;
405
406   if (!is_integer(args[1]) || !is_integer(args[2])) {
407     safe_str(T(e_ints), buff, bp);
408     return;
409   }
410
411   pos = parse_integer(args[1]);
412   num = parse_integer(args[2]);
413
414   if (pos < 0) {
415     safe_str(T(e_range), buff, bp);
416     return;
417   }
418
419   as = parse_ansi_string(args[0]);
420
421   if (pos > as->len || num == 0) {
422     safe_strl(args[0], arglens[0], buff, bp);
423     free_ansi_string(as);
424     return;
425   }
426
427   if (num < 0) {
428     pos2 = pos + 1;
429     pos = pos2 + num;
430     if (pos < 0)
431       pos = 0;
432   } else
433     pos2 = pos + num;
434
435   ansi_string_delete(as, pos, num);
436   safe_ansi_string(as, 0, as->len, buff, bp);
437   free_ansi_string(as);
438 }
439
440 /* ARGSUSED */
441 FUNCTION(fun_strreplace)
442 {
443   ansi_string *dst, *src;
444   int start, len;
445
446   if (!is_integer(args[1]) || !is_integer(args[2])) {
447     safe_str(T(e_ints), buff, bp);
448     return;
449   }
450
451   start = parse_integer(args[1]);
452   len = parse_integer(args[2]);
453
454   if (start < 0 || len < 0) {
455     safe_str(T(e_range), buff, bp);
456     return;
457   }
458
459   dst = parse_ansi_string(args[0]);
460   src = parse_ansi_string(args[3]);
461
462   ansi_string_replace(dst, start, len, src);
463
464   safe_ansi_string(dst, 0, dst->len, buff, bp);
465   free_ansi_string(dst);
466   free_ansi_string(src);
467 }
468
469 static int
470 comp_gencomp(dbref executor, char *left, char *right, char *type)
471 {
472   int c;
473   c = gencomp(executor, left, right, type);
474   return (c > 0 ? 1 : (c < 0 ? -1 : 0));
475 }
476
477 /* ARGSUSED */
478 FUNCTION(fun_comp)
479 {
480   char type = 'A';
481
482   if (nargs == 3 && !(args[2] && *args[2])) {
483     safe_str(T("#-1 INVALID THIRD ARGUMENT"), buff, bp);
484     return;
485   } else if (nargs == 3) {
486     type = UPCASE(*args[2]);
487   }
488
489   switch (type) {
490   case 'A':                    /* Case-sensitive lexicographic */
491     {
492       char left[BUFFER_LEN], right[BUFFER_LEN], *l, *r;
493       size_t llen, rlen;
494       l = remove_markup(args[0], &llen);
495       memcpy(left, l, llen);
496       r = remove_markup(args[1], &rlen);
497       memcpy(right, r, rlen);
498       safe_integer(comp_gencomp(executor, left, right, ALPHANUM_LIST), buff,
499                    bp);
500       return;
501     }
502   case 'I':                    /* Case-insensitive lexicographic */
503     {
504       char left[BUFFER_LEN], right[BUFFER_LEN], *l, *r;
505       size_t llen, rlen;
506       l = remove_markup(args[0], &llen);
507       memcpy(left, l, llen);
508       r = remove_markup(args[1], &rlen);
509       memcpy(right, r, rlen);
510       safe_integer(comp_gencomp(executor, left, right, INSENS_ALPHANUM_LIST),
511                    buff, bp);
512       return;
513     }
514   case 'N':                    /* Integers */
515     if (!is_strict_integer(args[0]) || !is_strict_integer(args[1])) {
516       safe_str(T(e_ints), buff, bp);
517       return;
518     }
519     safe_integer(comp_gencomp(executor, args[0], args[1], NUMERIC_LIST), buff,
520                  bp);
521     return;
522   case 'F':
523     if (!is_strict_number(args[0]) || !is_strict_number(args[1])) {
524       safe_str(T(e_nums), buff, bp);
525       return;
526     }
527     safe_integer(comp_gencomp(executor, args[0], args[1], FLOAT_LIST), buff,
528                  bp);
529     return;
530   case 'D':
531     {
532     &nbs