OSDN Git Service

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