OSDN Git Service

update year to 2019
[jnethack/source.git] / src / hacklib.c
1 /* NetHack 3.6  hacklib.c       $NHDT-Date: 1518922474 2018/02/18 02:54:34 $  $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.54 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /*-Copyright (c) Michael Allison, 2007. */
4 /* Copyright (c) Robert Patrick Rankin, 1991                      */
5 /* NetHack may be freely redistributed.  See license for details. */
6
7 /* JNetHack Copyright */
8 /* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000  */
9 /* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2019            */
10 /* JNetHack may be freely redistributed.  See license for details. */
11
12 #include "hack.h" /* for config.h+extern.h */
13 /*=
14     Assorted 'small' utility routines.  They're virtually independent of
15     NetHack, except that rounddiv may call panic().  setrandom calls one
16     of srandom(), srand48(), or srand() depending upon configuration.
17
18       return type     routine name    argument type(s)
19         boolean         digit           (char)
20         boolean         letter          (char)
21         char            highc           (char)
22         char            lowc            (char)
23         char *          lcase           (char *)
24         char *          ucase           (char *)
25         char *          upstart         (char *)
26         char *          mungspaces      (char *)
27         char *          trimspaces      (char *)
28         char *          strip_newline   (char *)
29         char *          stripchars      (char *, const char *, const char *)
30         char *          eos             (char *)
31         boolean         str_end_is      (const char *, const char *)
32         char *          strkitten       (char *,char)
33         void            copynchars      (char *,const char *,int)
34         char            chrcasecpy      (int,int)
35         char *          strcasecpy      (char *,const char *)
36         char *          s_suffix        (const char *)
37         char *          ing_suffix      (const char *)
38         char *          xcrypt          (const char *, char *)
39         boolean         onlyspace       (const char *)
40         char *          tabexpand       (char *)
41         char *          visctrl         (char)
42         char *          strsubst        (char *, const char *, const char *)
43         int             strNsubst       (char *,const char *,const char *,int)
44         const char *    ordin           (int)
45         char *          sitoa           (int)
46         int             sgn             (int)
47         int             rounddiv        (long, int)
48         int             distmin         (int, int, int, int)
49         int             dist2           (int, int, int, int)
50         boolean         online2         (int, int)
51         boolean         pmatch          (const char *, const char *)
52         boolean         pmatchi         (const char *, const char *)
53         boolean         pmatchz         (const char *, const char *)
54         int             strncmpi        (const char *, const char *, int)
55         char *          strstri         (const char *, const char *)
56         boolean         fuzzymatch      (const char *, const char *,
57                                          const char *, boolean)
58         void            setrandom       (void)
59         time_t          getnow          (void)
60         int             getyear         (void)
61         char *          yymmdd          (time_t)
62         long            yyyymmdd        (time_t)
63         long            hhmmss          (time_t)
64         char *          yyyymmddhhmmss  (time_t)
65         time_t          time_from_yyyymmddhhmmss (char *)
66         int             phase_of_the_moon (void)
67         boolean         friday_13th     (void)
68         int             night           (void)
69         int             midnight        (void)
70         void            strbuf_init     (strbuf *, const char *)
71         void            strbuf_append   (strbuf *, const char *)
72         void            strbuf_reserve  (strbuf *, int)
73         void            strbuf_empty    (strbuf *)
74         void            strbuf_nl_to_crlf (strbuf_t *)
75 =*/
76 #ifdef LINT
77 #define Static /* pacify lint */
78 #else
79 #define Static static
80 #endif
81
82 static boolean FDECL(pmatch_internal, (const char *, const char *,
83                                        BOOLEAN_P, const char *));
84
85 /* is 'c' a digit? */
86 boolean
87 digit(c)
88 char c;
89 {
90     return (boolean) ('0' <= c && c <= '9');
91 }
92
93 /* is 'c' a letter?  note: '@' classed as letter */
94 boolean
95 letter(c)
96 char c;
97 {
98     return (boolean) ('@' <= c && c <= 'Z') || ('a' <= c && c <= 'z');
99 }
100
101 /* force 'c' into uppercase */
102 char
103 highc(c)
104 char c;
105 {
106     return (char) (('a' <= c && c <= 'z') ? (c & ~040) : c);
107 }
108
109 /* force 'c' into lowercase */
110 char
111 lowc(c)
112 char c;
113 {
114     return (char) (('A' <= c && c <= 'Z') ? (c | 040) : c);
115 }
116
117 /* convert a string into all lowercase */
118 char *
119 lcase(s)
120 char *s;
121 {
122     register char *p;
123
124     for (p = s; *p; p++)
125 #if 1 /*JP*//*\8a¿\8e\9a\82Í\8f¬\95\8e\9a\89»\82µ\82È\82¢*/
126         if (is_kanji(*(unsigned char *)p)) p++; else
127 #endif
128         if ('A' <= *p && *p <= 'Z')
129             *p |= 040;
130     return s;
131 }
132
133 /* convert a string into all uppercase */
134 char *
135 ucase(s)
136 char *s;
137 {
138     register char *p;
139
140     for (p = s; *p; p++)
141 #if 1 /*JP*//*\8a¿\8e\9a\82Í\91å\95\8e\9a\89»\82µ\82È\82¢*/
142         if (is_kanji(*(unsigned char *)p)) p++; else
143 #endif
144         if ('a' <= *p && *p <= 'z')
145             *p &= ~040;
146     return s;
147 }
148
149 /* convert first character of a string to uppercase */
150 char *
151 upstart(s)
152 char *s;
153 {
154     if (s)
155         *s = highc(*s);
156     return s;
157 }
158
159 /* remove excess whitespace from a string buffer (in place) */
160 char *
161 mungspaces(bp)
162 char *bp;
163 {
164     register char c, *p, *p2;
165     boolean was_space = TRUE;
166
167     for (p = p2 = bp; (c = *p) != '\0'; p++) {
168         if (c == '\n')
169             break; /* treat newline the same as end-of-string */
170         if (c == '\t')
171             c = ' ';
172         if (c != ' ' || !was_space)
173             *p2++ = c;
174         was_space = (c == ' ');
175     }
176     if (was_space && p2 > bp)
177         p2--;
178     *p2 = '\0';
179     return bp;
180 }
181
182 /* remove leading and trailing whitespace, in place */
183 char*
184 trimspaces(txt)
185 char* txt;
186 {
187     char* end;
188
189     while (*txt == ' ' || *txt == '\t')
190         txt++;
191     end = eos(txt);
192     while (--end >= txt && (*end == ' ' || *end == '\t'))
193         *end = '\0';
194
195     return txt;
196 }
197
198 /* remove \n from end of line; remove \r too if one is there */
199 char *
200 strip_newline(str)
201 char *str;
202 {
203     char *p = rindex(str, '\n');
204
205     if (p) {
206         if (p > str && *(p - 1) == '\r')
207             --p;
208         *p = '\0';
209     }
210     return str;
211 }
212
213 /* return the end of a string (pointing at '\0') */
214 char *
215 eos(s)
216 register char *s;
217 {
218     while (*s)
219         s++; /* s += strlen(s); */
220     return s;
221 }
222
223 /* determine whether 'str' ends in 'chkstr' */
224 boolean
225 str_end_is(str, chkstr)
226 const char *str, *chkstr;
227 {
228     int clen = (int) strlen(chkstr);
229
230     if ((int) strlen(str) >= clen)
231         return (boolean) (!strncmp(eos((char *) str) - clen, chkstr, clen));
232     return FALSE;
233 }
234
235 /* append a character to a string (in place): strcat(s, {c,'\0'}); */
236 char *
237 strkitten(s, c)
238 char *s;
239 char c;
240 {
241     char *p = eos(s);
242
243     *p++ = c;
244     *p = '\0';
245     return s;
246 }
247
248 /* truncating string copy */
249 void
250 copynchars(dst, src, n)
251 char *dst;
252 const char *src;
253 int n;
254 {
255     /* copies at most n characters, stopping sooner if terminator reached;
256        treats newline as input terminator; unlike strncpy, always supplies
257        '\0' terminator so dst must be able to hold at least n+1 characters */
258     while (n > 0 && *src != '\0' && *src != '\n') {
259         *dst++ = *src++;
260         --n;
261     }
262     *dst = '\0';
263 }
264
265 /* convert char nc into oc's case; mostly used by strcasecpy */
266 char
267 chrcasecpy(oc, nc)
268 int oc, nc;
269 {
270 #if 0 /* this will be necessary if we switch to <ctype.h> */
271     oc = (int) (unsigned char) oc;
272     nc = (int) (unsigned char) nc;
273 #endif
274     if ('a' <= oc && oc <= 'z') {
275         /* old char is lower case; if new char is upper case, downcase it */
276         if ('A' <= nc && nc <= 'Z')
277             nc += 'a' - 'A'; /* lowc(nc) */
278     } else if ('A' <= oc && oc <= 'Z') {
279         /* old char is upper case; if new char is lower case, upcase it */
280         if ('a' <= nc && nc <= 'z')
281             nc += 'A' - 'a'; /* highc(nc) */
282     }
283     return (char) nc;
284 }
285
286 /* overwrite string, preserving old chars' case;
287    for case-insensitive editions of makeplural() and makesingular();
288    src might be shorter, same length, or longer than dst */
289 char *
290 strcasecpy(dst, src)
291 char *dst;
292 const char *src;
293 {
294     char *result = dst;
295     int ic, oc, dst_exhausted = 0;
296
297     /* while dst has characters, replace each one with corresponding
298        character from src, converting case in the process if they differ;
299        once dst runs out, propagate the case of its last character to any
300        remaining src; if dst starts empty, it must be a pointer to the
301        tail of some other string because we examine the char at dst[-1] */
302     while ((ic = (int) *src++) != '\0') {
303         if (!dst_exhausted && !*dst)
304             dst_exhausted = 1;
305         oc = (int) *(dst - dst_exhausted);
306         *dst++ = chrcasecpy(oc, ic);
307     }
308     *dst = '\0';
309     return result;
310 }
311
312 /* return a name converted to possessive */
313 char *
314 s_suffix(s)
315 const char *s;
316 {
317     Static char buf[BUFSZ];
318
319     Strcpy(buf, s);
320 #if 0 /*JP*/
321     if (!strcmpi(buf, "it")) /* it -> its */
322         Strcat(buf, "s");
323     else if (!strcmpi(buf, "you")) /* you -> your */
324         Strcat(buf, "r");
325     else if (*(eos(buf) - 1) == 's') /* Xs -> Xs' */
326         Strcat(buf, "'");
327     else /* X -> X's */
328         Strcat(buf, "'s");
329 #else /* X -> X\82Ì */
330     Strcat(buf, "\82Ì");
331 #endif
332     return buf;
333 }
334
335 /* construct a gerund (a verb formed by appending "ing" to a noun) */
336 char *
337 ing_suffix(s)
338 const char *s;
339 {
340     static const char vowel[] = "aeiouwy";
341     static char buf[BUFSZ];
342     char onoff[10];
343     char *p;
344
345     Strcpy(buf, s);
346     p = eos(buf);
347     onoff[0] = *p = *(p + 1) = '\0';
348     if ((p >= &buf[3] && !strcmpi(p - 3, " on"))
349         || (p >= &buf[4] && !strcmpi(p - 4, " off"))
350         || (p >= &buf[5] && !strcmpi(p - 5, " with"))) {
351         p = rindex(buf, ' ');
352         Strcpy(onoff, p);
353         *p = '\0';
354     }
355     if (p >= &buf[3] && !index(vowel, *(p - 1))
356         && index(vowel, *(p - 2)) && !index(vowel, *(p - 3))) {
357         /* tip -> tipp + ing */
358         *p = *(p - 1);
359         *(p + 1) = '\0';
360     } else if (p >= &buf[2] && !strcmpi(p - 2, "ie")) { /* vie -> vy + ing */
361         *(p - 2) = 'y';
362         *(p - 1) = '\0';
363     } else if (p >= &buf[1] && *(p - 1) == 'e') /* grease -> greas + ing */
364         *(p - 1) = '\0';
365     Strcat(buf, "ing");
366     if (onoff[0])
367         Strcat(buf, onoff);
368     return buf;
369 }
370
371 /* trivial text encryption routine (see makedefs) */
372 char *
373 xcrypt(str, buf)
374 const char *str;
375 char *buf;
376 {
377     register const char *p;
378     register char *q;
379     register int bitmask;
380
381     for (bitmask = 1, p = str, q = buf; *p; q++) {
382         *q = *p++;
383         if (*q & (32 | 64))
384             *q ^= bitmask;
385         if ((bitmask <<= 1) >= 32)
386             bitmask = 1;
387     }
388     *q = '\0';
389     return buf;
390 }
391
392 /* is a string entirely whitespace? */
393 boolean
394 onlyspace(s)
395 const char *s;
396 {
397     for (; *s; s++)
398         if (*s != ' ' && *s != '\t')
399             return FALSE;
400     return TRUE;
401 }
402
403 /* expand tabs into proper number of spaces */
404 char *
405 tabexpand(sbuf)
406 char *sbuf;
407 {
408     char buf[BUFSZ];
409     register char *bp, *s = sbuf;
410     register int idx;
411
412     if (!*s)
413         return sbuf;
414     /* warning: no bounds checking performed */
415     for (bp = buf, idx = 0; *s; s++)
416         if (*s == '\t') {
417             do
418                 *bp++ = ' ';
419             while (++idx % 8);
420         } else {
421             *bp++ = *s;
422             idx++;
423         }
424     *bp = 0;
425     return strcpy(sbuf, buf);
426 }
427
428 #define VISCTRL_NBUF 5
429 /* make a displayable string from a character */
430 char *
431 visctrl(c)
432 char c;
433 {
434     Static char visctrl_bufs[VISCTRL_NBUF][5];
435     static int nbuf = 0;
436     register int i = 0;
437     char *ccc = visctrl_bufs[nbuf];
438     nbuf = (nbuf + 1) % VISCTRL_NBUF;
439
440     if ((uchar) c & 0200) {
441         ccc[i++] = 'M';
442         ccc[i++] = '-';
443     }
444     c &= 0177;
445     if (c < 040) {
446         ccc[i++] = '^';
447         ccc[i++] = c | 0100; /* letter */
448     } else if (c == 0177) {
449         ccc[i++] = '^';
450         ccc[i++] = c & ~0100; /* '?' */
451     } else {
452         ccc[i++] = c; /* printable character */
453     }
454     ccc[i] = '\0';
455     return ccc;
456 }
457
458 /* strip all the chars in stuff_to_strip from orig */
459 /* caller is responsible for ensuring that bp is a
460    valid pointer to a BUFSZ buffer */
461 char *
462 stripchars(bp, stuff_to_strip, orig)
463 char *bp;
464 const char *stuff_to_strip, *orig;
465 {
466     int i = 0;
467     char *s = bp;
468
469     if (s) {
470         while (*orig && i < (BUFSZ - 1)) {
471             if (!index(stuff_to_strip, *orig)) {
472                 *s++ = *orig;
473                 i++;
474             }
475             orig++;
476         }
477         *s = '\0';
478     } else
479         impossible("no output buf in stripchars");
480     return bp;
481 }
482
483 /* substitute a word or phrase in a string (in place) */
484 /* caller is responsible for ensuring that bp points to big enough buffer */
485 char *
486 strsubst(bp, orig, replacement)
487 char *bp;
488 const char *orig, *replacement;
489 {
490     char *found, buf[BUFSZ];
491
492     if (bp) {
493         /* [this could be replaced by strNsubst(bp, orig, replacement, 1)] */
494         found = strstr(bp, orig);
495         if (found) {
496             Strcpy(buf, found + strlen(orig));
497             Strcpy(found, replacement);
498             Strcat(bp, buf);
499         }
500     }
501     return bp;
502 }
503
504 /* substitute the Nth occurrence of a substring within a string (in place);
505    if N is 0, substitute all occurrences; returns the number of subsitutions;
506    maximum output length is BUFSZ (BUFSZ-1 chars + terminating '\0') */
507 int
508 strNsubst(inoutbuf, orig, replacement, n)
509 char *inoutbuf; /* current string, and result buffer */
510 const char *orig, /* old substring; if "" then insert in front of Nth char */
511            *replacement; /* new substring; if "" then delete old substring */
512 int n; /* which occurrence to replace; 0 => all */
513 {
514     char *bp, *op, workbuf[BUFSZ];
515     const char *rp;
516     unsigned len = (unsigned) strlen(orig);
517     int ocount = 0, /* number of times 'orig' has been matched */
518         rcount = 0; /* number of subsitutions made */
519
520     for (bp = inoutbuf, op = workbuf; *bp && op < &workbuf[BUFSZ - 1]; ) {
521         if ((!len || !strncmp(bp, orig, len)) && (++ocount == n || n == 0)) {
522             /* Nth match found */
523             for (rp = replacement; *rp && op < &workbuf[BUFSZ - 1]; )
524                 *op++ = *rp++;
525             ++rcount;
526             if (len) {
527                 bp += len; /* skip 'orig' */
528                 continue;
529             }
530         }
531         /* no match (or len==0) so retain current character */
532         *op++ = *bp++;
533     }
534     if (!len && n == ocount + 1) {
535         /* special case: orig=="" (!len) and n==strlen(inoutbuf)+1,
536            insert in front of terminator (in other words, append);
537            [when orig=="", ocount will have been incremented once for
538            each input char] */
539         for (rp = replacement; *rp && op < &workbuf[BUFSZ - 1]; )
540             *op++ = *rp++;
541         ++rcount;
542     }
543     if (rcount) {
544         *op = '\0';
545         Strcpy(inoutbuf, workbuf);
546     }
547     return rcount;
548 }
549
550 /* return the ordinal suffix of a number */
551 const char *
552 ordin(n)
553 int n;               /* note: should be non-negative */
554 {
555     register int dd = n % 10;
556
557     return (dd == 0 || dd > 3 || (n % 100) / 10 == 1) ? "th"
558                : (dd == 1) ? "st" : (dd == 2) ? "nd" : "rd";
559 }
560
561 /* make a signed digit string from a number */
562 char *
563 sitoa(n)
564 int n;
565 {
566     Static char buf[13];
567
568     Sprintf(buf, (n < 0) ? "%d" : "+%d", n);
569     return buf;
570 }
571
572 /* return the sign of a number: -1, 0, or 1 */
573 int
574 sgn(n)
575 int n;
576 {
577     return (n < 0) ? -1 : (n != 0);
578 }
579
580 /* calculate x/y, rounding as appropriate */
581 int
582 rounddiv(x, y)
583 long x;
584 int y;
585 {
586     int r, m;
587     int divsgn = 1;
588
589     if (y == 0)
590         panic("division by zero in rounddiv");
591     else if (y < 0) {
592         divsgn = -divsgn;
593         y = -y;
594     }
595     if (x < 0) {
596         divsgn = -divsgn;
597         x = -x;
598     }
599     r = x / y;
600     m = x % y;
601     if (2 * m >= y)
602         r++;
603
604     return divsgn * r;
605 }
606
607 /* distance between two points, in moves */
608 int
609 distmin(x0, y0, x1, y1)
610 int x0, y0, x1, y1;
611 {
612     register int dx = x0 - x1, dy = y0 - y1;
613
614     if (dx < 0)
615         dx = -dx;
616     if (dy < 0)
617         dy = -dy;
618     /*  The minimum number of moves to get from (x0,y0) to (x1,y1) is the
619      *  larger of the [absolute value of the] two deltas.
620      */
621     return (dx < dy) ? dy : dx;
622 }
623
624 /* square of euclidean distance between pair of pts */
625 int
626 dist2(x0, y0, x1, y1)
627 int x0, y0, x1, y1;
628 {
629     register int dx = x0 - x1, dy = y0 - y1;
630
631     return dx * dx + dy * dy;
632 }
633
634 /* integer square root function without using floating point */
635 int
636 isqrt(val)
637 int val;
638 {
639     int rt = 0;
640     int odd = 1;
641     /*
642      * This could be replaced by a faster algorithm, but has not been because:
643      * + the simple algorithm is easy to read;
644      * + this algorithm does not require 64-bit support;
645      * + in current usage, the values passed to isqrt() are not really that
646      *   large, so the performance difference is negligible;
647      * + isqrt() is used in only few places, which are not bottle-necks.
648      */
649     while (val >= odd) {
650         val = val - odd;
651         odd = odd + 2;
652         rt = rt + 1;
653     }
654     return rt;
655 }
656
657 /* are two points lined up (on a straight line)? */
658 boolean
659 online2(x0, y0, x1, y1)
660 int x0, y0, x1, y1;
661 {
662     int dx = x0 - x1, dy = y0 - y1;
663     /*  If either delta is zero then they're on an orthogonal line,
664      *  else if the deltas are equal (signs ignored) they're on a diagonal.
665      */
666     return (boolean) (!dy || !dx || dy == dx || dy == -dx);
667 }
668
669 /* guts of pmatch(), pmatchi(), and pmatchz();
670    match a string against a pattern */
671 static boolean
672 pmatch_internal(patrn, strng, ci, sk)
673 const char *patrn, *strng;
674 boolean ci;     /* True => case-insensitive, False => case-sensitive */
675 const char *sk; /* set of characters to skip */
676 {
677     char s, p;
678     /*
679      *  Simple pattern matcher:  '*' matches 0 or more characters, '?' matches
680      *  any single character.  Returns TRUE if 'strng' matches 'patrn'.
681      */
682 pmatch_top:
683     if (!sk) {
684         s = *strng++;
685         p = *patrn++; /* get next chars and pre-advance */
686     } else {
687         /* fuzzy match variant of pmatch; particular characters are ignored */
688         do {
689             s = *strng++;
690         } while (index(sk, s));
691         do {
692             p = *patrn++;
693         } while (index(sk, p));
694     }
695     if (!p)                           /* end of pattern */
696         return (boolean) (s == '\0'); /* matches iff end of string too */
697     else if (p == '*')                /* wildcard reached */
698         return (boolean) ((!*patrn
699                            || pmatch_internal(patrn, strng - 1, ci, sk))
700                           ? TRUE
701                           : s ? pmatch_internal(patrn - 1, strng, ci, sk)
702                               : FALSE);
703     else if ((ci ? lowc(p) != lowc(s) : p != s) /* check single character */
704              && (p != '?' || !s))               /* & single-char wildcard */
705         return FALSE;                           /* doesn't match */
706     else                 /* return pmatch_internal(patrn, strng, ci, sk); */
707         goto pmatch_top; /* optimize tail recursion */
708 }
709
710 /* case-sensitive wildcard match */
711 boolean
712 pmatch(patrn, strng)
713 const char *patrn, *strng;
714 {
715     return pmatch_internal(patrn, strng, FALSE, (const char *) 0);
716 }
717
718 /* case-insensitive wildcard match */
719 boolean
720 pmatchi(patrn, strng)
721 const char *patrn, *strng;
722 {
723     return pmatch_internal(patrn, strng, TRUE, (const char *) 0);
724 }
725
726 /* case-insensitive wildcard fuzzymatch */
727 boolean
728 pmatchz(patrn, strng)
729 const char *patrn, *strng;
730 {
731     /* ignore spaces, tabs (just in case), dashes, and underscores */
732     static const char fuzzychars[] = " \t-_";
733
734     return pmatch_internal(patrn, strng, TRUE, fuzzychars);
735 }
736
737 #ifndef STRNCMPI
738 /* case insensitive counted string comparison */
739 int
740 strncmpi(s1, s2, n) /*{ aka strncasecmp }*/
741 register const char *s1, *s2;
742 register int n; /*(should probably be size_t, which is unsigned)*/
743 {
744     register char t1, t2;
745
746     while (n--) {
747         if (!*s2)
748             return (*s1 != 0); /* s1 >= s2 */
749         else if (!*s1)
750             return -1; /* s1  < s2 */
751         t1 = lowc(*s1++);
752         t2 = lowc(*s2++);
753         if (t1 != t2)
754             return (t1 > t2) ? 1 : -1;
755     }
756     return 0; /* s1 == s2 */
757 }
758 #endif /* STRNCMPI */
759
760 #ifndef STRSTRI
761 /* case insensitive substring search */
762 char *
763 strstri(str, sub)
764 const char *str;
765 const char *sub;
766 {
767     register const char *s1, *s2;
768     register int i, k;
769 #define TABSIZ 0x20                  /* 0x40 would be case-sensitive */
770     char tstr[TABSIZ], tsub[TABSIZ]; /* nibble count tables */
771 #if 0
772     assert( (TABSIZ & ~(TABSIZ-1)) == TABSIZ ); /* must be exact power of 2 */
773     assert( &lowc != 0 );                       /* can't be unsafe macro */
774 #endif
775
776     /* special case: empty substring */
777     if (!*sub)
778         return (char *) str;
779
780     /* do some useful work while determining relative lengths */
781     for (i = 0; i < TABSIZ; i++)
782         tstr[i] = tsub[i] = 0; /* init */
783     for (k = 0, s1 = str; *s1; k++)
784         tstr[*s1++ & (TABSIZ - 1)]++;
785     for (s2 = sub; *s2; --k)
786         tsub[*s2++ & (TABSIZ - 1)]++;
787
788     /* evaluate the info we've collected */
789     if (k < 0)
790         return (char *) 0;       /* sub longer than str, so can't match */
791     for (i = 0; i < TABSIZ; i++) /* does sub have more 'x's than str? */
792         if (tsub[i] > tstr[i])
793             return (char *) 0; /* match not possible */
794
795     /* now actually compare the substring repeatedly to parts of the string */
796     for (i = 0; i <= k; i++) {
797         s1 = &str[i];
798         s2 = sub;
799         while (lowc(*s1++) == lowc(*s2++))
800             if (!*s2)
801                 return (char *) &str[i]; /* full match */
802     }
803     return (char *) 0; /* not found */
804 }
805 #endif /* STRSTRI */
806
807 /* compare two strings for equality, ignoring the presence of specified
808    characters (typically whitespace) and possibly ignoring case */
809 boolean
810 fuzzymatch(s1, s2, ignore_chars, caseblind)
811 const char *s1, *s2;
812 const char *ignore_chars;
813 boolean caseblind;
814 {
815     register char c1, c2;
816
817     do {
818         while ((c1 = *s1++) != '\0' && index(ignore_chars, c1) != 0)
819             continue;
820         while ((c2 = *s2++) != '\0' && index(ignore_chars, c2) != 0)
821             continue;
822         if (!c1 || !c2)
823             break; /* stop when end of either string is reached */
824
825         if (caseblind) {
826             c1 = lowc(c1);
827             c2 = lowc(c2);
828         }
829     } while (c1 == c2);
830
831     /* match occurs only when the end of both strings has been reached */
832     return (boolean) (!c1 && !c2);
833 }
834
835 /*
836  * Time routines
837  *
838  * The time is used for:
839  *  - seed for rand()
840  *  - year on tombstone and yyyymmdd in record file
841  *  - phase of the moon (various monsters react to NEW_MOON or FULL_MOON)
842  *  - night and midnight (the undead are dangerous at midnight)
843  *  - determination of what files are "very old"
844  */
845
846 /* TIME_type: type of the argument to time(); we actually use &(time_t) */
847 #if defined(BSD) && !defined(POSIX_TYPES)
848 #define TIME_type long *
849 #else
850 #define TIME_type time_t *
851 #endif
852 /* LOCALTIME_type: type of the argument to localtime() */
853 #if (defined(ULTRIX) && !(defined(ULTRIX_PROTO) || defined(NHSTDC))) \
854     || (defined(BSD) && !defined(POSIX_TYPES))
855 #define LOCALTIME_type long *
856 #else
857 #define LOCALTIME_type time_t *
858 #endif
859
860 #if defined(AMIGA) && !defined(AZTEC_C) && !defined(__SASC_60) \
861     && !defined(_DCC) && !defined(__GNUC__)
862 extern struct tm *FDECL(localtime, (time_t *));
863 #endif
864 STATIC_DCL struct tm *NDECL(getlt);
865
866 void
867 setrandom()
868 {
869     unsigned long seed = (unsigned long) getnow(); /* time((TIME_type) 0) */
870
871 #if defined(UNIX) || defined(VMS)
872     {
873         unsigned long pid = (unsigned long) getpid();
874
875         /* Quick dirty band-aid to prevent PRNG prediction */
876         if (pid) {
877             if (!(pid & 3L))
878                 pid -= 1L;
879             seed *= pid;
880         }
881     }
882 #endif
883
884     /* the types are different enough here that sweeping the different
885      * routine names into one via #defines is even more confusing
886      */
887 #ifdef RANDOM /* srandom() from sys/share/random.c */
888     srandom((unsigned int) seed);
889 #else
890 #if defined(__APPLE__) || defined(BSD) || defined(LINUX) || defined(ULTRIX) \
891     || defined(CYGWIN32) /* system srandom() */
892 #if defined(BSD) && !defined(POSIX_TYPES) && defined(SUNOS4)
893     (void)
894 #endif
895         srandom((int) seed);
896 #else
897 #ifdef UNIX /* system srand48() */
898     srand48((long) seed);
899 #else       /* poor quality system routine */
900     srand((int) seed);
901 #endif
902 #endif
903 #endif
904 }
905
906 time_t
907 getnow()
908 {
909     time_t datetime = 0;
910
911     (void) time((TIME_type) &datetime);
912     return datetime;
913 }
914
915 STATIC_OVL struct tm *
916 getlt()
917 {
918     time_t date = getnow();
919
920     return localtime((LOCALTIME_type) &date);
921 }
922
923 int
924 getyear()
925 {
926     return (1900 + getlt()->tm_year);
927 }
928
929 #if 0
930 /* This routine is no longer used since in 20YY it yields "1YYmmdd". */
931 char *
932 yymmdd(date)
933 time_t date;
934 {
935     Static char datestr[10];
936     struct tm *lt;
937
938     if (date == 0)
939         lt = getlt();
940     else
941         lt = localtime((LOCALTIME_type) &date);
942
943     Sprintf(datestr, "%02d%02d%02d",
944             lt->tm_year, lt->tm_mon + 1, lt->tm_mday);
945     return datestr;
946 }
947 #endif
948
949 long
950 yyyymmdd(date)
951 time_t date;
952 {
953     long datenum;
954     struct tm *lt;
955
956     if (date == 0)
957         lt = getlt();
958     else
959         lt = localtime((LOCALTIME_type) &date);
960
961     /* just in case somebody's localtime supplies (year % 100)
962        rather than the expected (year - 1900) */
963     if (lt->tm_year < 70)
964         datenum = (long) lt->tm_year + 2000L;
965     else
966         datenum = (long) lt->tm_year + 1900L;
967     /* yyyy --> yyyymm */
968     datenum = datenum * 100L + (long) (lt->tm_mon + 1);
969     /* yyyymm --> yyyymmdd */
970     datenum = datenum * 100L + (long) lt->tm_mday;
971     return datenum;
972 }
973
974 long
975 hhmmss(date)
976 time_t date;
977 {
978     long timenum;
979     struct tm *lt;
980
981     if (date == 0)
982         lt = getlt();
983     else
984         lt = localtime((LOCALTIME_type) &date);
985
986     timenum = lt->tm_hour * 10000L + lt->tm_min * 100L + lt->tm_sec;
987     return timenum;
988 }
989
990 char *
991 yyyymmddhhmmss(date)
992 time_t date;
993 {
994     long datenum;
995     static char datestr[15];
996     struct tm *lt;
997
998     if (date == 0)
999         lt = getlt();
1000     else
1001 #if (defined(ULTRIX) && !(defined(ULTRIX_PROTO) || defined(NHSTDC))) \
1002     || defined(BSD)
1003         lt = localtime((long *) (&date));
1004 #else
1005         lt = localtime(&date);
1006 #endif
1007     /* just in case somebody's localtime supplies (year % 100)
1008        rather than the expected (year - 1900) */
1009     if (lt->tm_year < 70)
1010         datenum = (long) lt->tm_year + 2000L;
1011     else
1012         datenum = (long) lt->tm_year + 1900L;
1013     Sprintf(datestr, "%04ld%02d%02d%02d%02d%02d", datenum, lt->tm_mon + 1,
1014             lt->tm_mday, lt->tm_hour, lt->tm_min, lt->tm_sec);
1015     debugpline1("yyyymmddhhmmss() produced date string %s", datestr);
1016     return datestr;
1017 }
1018
1019 time_t
1020 time_from_yyyymmddhhmmss(buf)
1021 char *buf;
1022 {
1023     int k;
1024     time_t timeresult = (time_t) 0;
1025     struct tm t, *lt;
1026     char *g, *p, y[5], mo[3], md[3], h[3], mi[3], s[3];
1027
1028     if (buf && strlen(buf) == 14) {
1029         g = buf;
1030         p = y; /* year */
1031         for (k = 0; k < 4; ++k)
1032             *p++ = *g++;
1033         *p = '\0';
1034         p = mo; /* month */
1035         for (k = 0; k < 2; ++k)
1036             *p++ = *g++;
1037         *p = '\0';
1038         p = md; /* day */
1039         for (k = 0; k < 2; ++k)
1040             *p++ = *g++;
1041         *p = '\0';
1042         p = h; /* hour */
1043         for (k = 0; k < 2; ++k)
1044             *p++ = *g++;
1045         *p = '\0';
1046         p = mi; /* minutes */
1047         for (k = 0; k < 2; ++k)
1048             *p++ = *g++;
1049         *p = '\0';
1050         p = s; /* seconds */
1051         for (k = 0; k < 2; ++k)
1052             *p++ = *g++;
1053         *p = '\0';
1054         lt = getlt();
1055         if (lt) {
1056             t = *lt;
1057             t.tm_year = atoi(y) - 1900;
1058             t.tm_mon = atoi(mo) - 1;
1059             t.tm_mday = atoi(md);
1060             t.tm_hour = atoi(h);
1061             t.tm_min = atoi(mi);
1062             t.tm_sec = atoi(s);
1063             timeresult = mktime(&t);
1064         }
1065         if ((int) timeresult == -1)
1066             debugpline1("time_from_yyyymmddhhmmss(%s) would have returned -1",
1067                         buf ? buf : "");
1068         else
1069             return timeresult;
1070     }
1071     return (time_t) 0;
1072 }
1073
1074 /*
1075  * moon period = 29.53058 days ~= 30, year = 365.2422 days
1076  * days moon phase advances on first day of year compared to preceding year
1077  *      = 365.2422 - 12*29.53058 ~= 11
1078  * years in Metonic cycle (time until same phases fall on the same days of
1079  *      the month) = 18.6 ~= 19
1080  * moon phase on first day of year (epact) ~= (11*(year%19) + 29) % 30
1081  *      (29 as initial condition)
1082  * current phase in days = first day phase + days elapsed in year
1083  * 6 moons ~= 177 days
1084  * 177 ~= 8 reported phases * 22
1085  * + 11/22 for rounding
1086  */
1087 int
1088 phase_of_the_moon() /* 0-7, with 0: new, 4: full */
1089 {
1090     register struct tm *lt = getlt();
1091     register int epact, diy, goldn;
1092
1093     diy = lt->tm_yday;
1094     goldn = (lt->tm_year % 19) + 1;
1095     epact = (11 * goldn + 18) % 30;
1096     if ((epact == 25 && goldn > 11) || epact == 24)
1097         epact++;
1098
1099     return ((((((diy + epact) * 6) + 11) % 177) / 22) & 7);
1100 }
1101
1102 boolean
1103 friday_13th()
1104 {
1105     register struct tm *lt = getlt();
1106
1107     /* tm_wday (day of week; 0==Sunday) == 5 => Friday */
1108     return (boolean) (lt->tm_wday == 5 && lt->tm_mday == 13);
1109 }
1110
1111 int
1112 night()
1113 {
1114     register int hour = getlt()->tm_hour;
1115
1116     return (hour < 6 || hour > 21);
1117 }
1118
1119 int
1120 midnight()
1121 {
1122     return (getlt()->tm_hour == 0);
1123 }
1124
1125 /* strbuf_init() initializes strbuf state for use */
1126 void
1127 strbuf_init(strbuf)
1128 strbuf_t *strbuf;
1129 {
1130     strbuf->str = NULL;
1131     strbuf->len = 0;
1132 }
1133
1134 /* strbuf_append() appends given str to strbuf->str */
1135 void
1136 strbuf_append(strbuf, str)
1137 strbuf_t *strbuf;
1138 const char *str;
1139 {
1140     int len = (int) strlen(str) + 1;
1141
1142     strbuf_reserve(strbuf,
1143                    len + (strbuf->str ? (int) strlen(strbuf->str) : 0));
1144     Strcat(strbuf->str, str);
1145 }
1146
1147 /* strbuf_reserve() ensure strbuf->str has storage for len characters */
1148 void
1149 strbuf_reserve(strbuf, len)
1150 strbuf_t *strbuf;
1151 int len;
1152 {
1153     if (strbuf->str == NULL) {
1154         strbuf->str = strbuf->buf;
1155         strbuf->str[0] = '\0';
1156         strbuf->len = (int) sizeof strbuf->buf;
1157     }
1158
1159     if (len > strbuf->len) {
1160         char *oldbuf = strbuf->str;
1161
1162         strbuf->len = len + (int) sizeof strbuf->buf;
1163         strbuf->str = (char *) alloc(strbuf->len);
1164         Strcpy(strbuf->str, oldbuf);
1165         if (oldbuf != strbuf->buf)
1166             free((genericptr_t) oldbuf);
1167     }
1168 }
1169
1170 /* strbuf_empty() frees allocated memory and set strbuf to initial state */
1171 void
1172 strbuf_empty(strbuf)
1173 strbuf_t *strbuf;
1174 {
1175     if (strbuf->str != NULL && strbuf->str != strbuf->buf)
1176         free((genericptr_t) strbuf->str);
1177     strbuf_init(strbuf);
1178 }
1179
1180 /* strbuf_nl_to_crlf() converts all occurences of \n to \r\n */
1181 void
1182 strbuf_nl_to_crlf(strbuf)
1183 strbuf_t *strbuf;
1184 {
1185     if (strbuf->str) {
1186         int len = (int) strlen(strbuf->str);
1187         int count = 0;
1188         char *cp = strbuf->str;
1189
1190         while (*cp)
1191             if (*cp++ == '\n')
1192                 count++;
1193         if (count) {
1194             strbuf_reserve(strbuf, len + count + 1);
1195             for (cp = strbuf->str + len + count; count; --cp)
1196                 if ((*cp = cp[-count]) == '\n') {
1197                     *--cp = '\r';
1198                     --count;
1199                 }
1200         }
1201     }
1202 }
1203
1204 /*hacklib.c*/