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