OSDN Git Service

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