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 */
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)
19 char * upstart (char *)
20 char * mungspaces (char *)
21 char * strip_newline (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 *)
34 char * strsubst (char *, const char *, const char *)
35 const char * ordin (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)
52 char * yymmdd (time_t)
53 long yyyymmdd (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)
63 #define Static /* pacify lint */
68 static boolean
FDECL(pmatch_internal
, (const char *, const char *,
69 BOOLEAN_P
, const char *));
76 return (boolean
) ('0' <= c
&& c
<= '9');
79 /* is 'c' a letter? note: '@' classed as letter */
84 return (boolean
) ('@' <= c
&& c
<= 'Z') || ('a' <= c
&& c
<= 'z');
87 /* force 'c' into uppercase */
92 return (char) (('a' <= c
&& c
<= 'z') ? (c
& ~040) : c
);
95 /* force 'c' into lowercase */
100 return (char) (('A' <= c
&& c
<= 'Z') ? (c
| 040) : c
);
103 /* convert a string into all lowercase */
111 if ('A' <= *p
&& *p
<= 'Z')
116 /* convert a string into all uppercase */
124 if ('a' <= *p
&& *p
<= 'z')
129 /* convert first character of a string to uppercase */
139 /* remove excess whitespace from a string buffer (in place) */
144 register char c
, *p
, *p2
;
145 boolean was_space
= TRUE
;
147 for (p
= p2
= bp
; (c
= *p
) != '\0'; p
++) {
149 break; /* treat newline the same as end-of-string */
152 if (c
!= ' ' || !was_space
)
154 was_space
= (c
== ' ');
156 if (was_space
&& p2
> bp
)
162 /* remove \n from end of line; remove \r too if one is there */
167 char *p
= index(str
, '\n');
170 if (p
> str
&& *(p
- 1) == '\r')
177 /* return the end of a string (pointing at '\0') */
183 s
++; /* s += strlen(s); */
187 /* determine whether 'str' ends in 'chkstr' */
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
));
199 /* append a character to a string (in place): strcat(s, {c,'\0'}); */
212 /* truncating string copy */
214 copynchars(dst
, src
, 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') {
229 /* convert char nc into oc's case; mostly used by strcasecpy */
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
;
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) */
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 */
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
)
269 oc
= (int) *(dst
- dst_exhausted
);
270 *dst
++ = chrcasecpy(oc
, ic
);
276 /* return a name converted to possessive */
281 Static
char buf
[BUFSZ
];
284 if (!strcmpi(buf
, "it")) /* it -> its */
286 else if (!strcmpi(buf
, "you")) /* you -> your */
288 else if (*(eos(buf
) - 1) == 's') /* Xs -> Xs' */
295 /* construct a gerund (a verb formed by appending "ing" to a noun) */
300 const char *vowel
= "aeiouy";
301 static char buf
[BUFSZ
];
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
, ' ');
314 if (!index(vowel
, *(p
- 1)) && index(vowel
, *(p
- 2))
315 && !index(vowel
, *(p
- 3))) {
316 /* tip -> tipp + ing */
319 } else if (!strcmpi(p
- 2, "ie")) { /* vie -> vy + ing */
322 } else if (*(p
- 1) == 'e') /* grease -> greas + ing */
330 /* trivial text encryption routine (see makedefs) */
336 register const char *p
;
338 register int bitmask
;
340 for (bitmask
= 1, p
= str
, q
= buf
; *p
; q
++) {
344 if ((bitmask
<<= 1) >= 32)
351 /* is a string entirely whitespace? */
357 if (*s
!= ' ' && *s
!= '\t')
362 /* expand tabs into proper number of spaces */
368 register char *bp
, *s
= sbuf
;
373 /* warning: no bounds checking performed */
374 for (bp
= buf
, idx
= 0; *s
; s
++)
384 return strcpy(sbuf
, buf
);
387 /* make a displayable string from a character */
395 if ((uchar
) c
& 0200) {
402 ccc
[i
++] = c
| 0100; /* letter */
403 } else if (c
== 0177) {
405 ccc
[i
++] = c
& ~0100; /* '?' */
407 ccc
[i
++] = c
; /* printable character */
413 /* substitute a word or phrase in a string (in place) */
414 /* caller is responsible for ensuring that bp points to big enough buffer */
416 strsubst(bp
, orig
, replacement
)
418 const char *orig
, *replacement
;
420 char *found
, buf
[BUFSZ
];
423 found
= strstr(bp
, orig
);
425 Strcpy(buf
, found
+ strlen(orig
));
426 Strcpy(found
, replacement
);
433 /* return the ordinal suffix of a number */
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 */
451 Sprintf(buf
, (n
< 0) ? "%d" : "+%d", n
);
455 /* return the sign of a number: -1, 0, or 1 */
460 return (n
< 0) ? -1 : (n
!= 0);
463 /* calculate x/y, rounding as appropriate */
473 panic("division by zero in rounddiv");
490 /* distance between two points, in moves */
492 distmin(x0
, y0
, x1
, y1
)
495 register int dx
= x0
- x1
, dy
= y0
- y1
;
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
)
512 register int dx
= x0
- x1
, dy
= y0
- y1
;
514 return dx
* dx
+ dy
* dy
;
517 /* integer square root function without using floating point */
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.
540 /* are two points lined up (on a straight line)? */
542 online2(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 */
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 */
562 * Simple pattern matcher: '*' matches 0 or more characters, '?' matches
563 * any single character. Returns TRUE if 'strng' matches 'patrn'.
568 p
= *patrn
++; /* get next chars and pre-advance */
570 /* fuzzy match variant of pmatch; particular characters are ignored */
573 } while (index(sk
, s
));
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
))
584 : s
? pmatch_internal(patrn
- 1, strng
, ci
, sk
)
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 */
596 const char *patrn
, *strng
;
598 return pmatch_internal(patrn
, strng
, FALSE
, (const char *) 0);
601 /* case-insensitive wildcard match */
603 pmatchi(patrn
, strng
)
604 const char *patrn
, *strng
;
606 return pmatch_internal(patrn
, strng
, TRUE
, (const char *) 0);
609 /* case-insensitive wildcard fuzzymatch */
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
);
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
;
631 return (*s1
!= 0); /* s1 >= s2 */
633 return -1; /* s1 < s2 */
637 return (t1
> t2
) ? 1 : -1;
639 return 0; /* s1 == s2 */
641 #endif /* STRNCMPI */
644 /* case insensitive substring search */
650 register const char *s1
, *s2
;
652 #define TABSIZ 0x20 /* 0x40 would be case-sensitive */
653 char tstr
[TABSIZ
], tsub
[TABSIZ
]; /* nibble count tables */
655 assert( (TABSIZ
& ~(TABSIZ
-1)) == TABSIZ
); /* must be exact power of 2 */
656 assert( &lowc
!= 0 ); /* can't be unsafe macro */
659 /* special case: empty substring */
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 */
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
++) {
682 while (lowc(*s1
++) == lowc(*s2
++))
684 return (char *) &str
[i
]; /* full match */
686 return (char *) 0; /* not found */
690 /* compare two strings for equality, ignoring the presence of specified
691 characters (typically whitespace) and possibly ignoring case */
693 fuzzymatch(s1
, s2
, ignore_chars
, caseblind
)
695 const char *ignore_chars
;
698 register char c1
, c2
;
701 while ((c1
= *s1
++) != '\0' && index(ignore_chars
, c1
) != 0)
703 while ((c2
= *s2
++) != '\0' && index(ignore_chars
, c2
) != 0)
706 break; /* stop when end of either string is reached */
714 /* match occurs only when the end of both strings has been reached */
715 return (boolean
) (!c1
&& !c2
);
721 * The time is used for:
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 *
733 #define TIME_type time_t *
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 *
740 #define LOCALTIME_type time_t *
743 #if defined(AMIGA) && !defined(AZTEC_C) && !defined(__SASC_60) \
744 && !defined(_DCC) && !defined(__GNUC__)
745 extern struct tm
*FDECL(localtime
, (time_t *));
747 STATIC_DCL
struct tm
*NDECL(getlt
);
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 */
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
);
773 #if defined(__APPLE__) || defined(BSD) || defined(LINUX) || defined(ULTRIX) \
774 || defined(CYGWIN32) /* system srandom() */
775 #if defined(BSD) && !defined(POSIX_TYPES) && defined(SUNOS4)
780 #ifdef UNIX /* system srand48() */
781 srand48((long) seed
);
782 #else /* poor quality system routine */
794 (void) time((TIME_type
) &datetime
);
798 STATIC_OVL
struct tm
*
801 time_t date
= getnow();
803 return localtime((LOCALTIME_type
) &date
);
809 return (1900 + getlt()->tm_year
);
813 /* This routine is no longer used since in 20YY it yields "1YYmmdd". */
818 Static
char datestr
[10];
824 lt
= localtime((LOCALTIME_type
) &date
);
826 Sprintf(datestr
, "%02d%02d%02d",
827 lt
->tm_year
, lt
->tm_mon
+ 1, lt
->tm_mday
);
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;
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
;
867 lt
= localtime((LOCALTIME_type
) &date
);
869 timenum
= lt
->tm_hour
* 10000L + lt
->tm_min
* 100L + lt
->tm_sec
;
878 static char datestr
[15];
884 #if (defined(ULTRIX) && !(defined(ULTRIX_PROTO) || defined(NHSTDC))) \
886 lt
= localtime((long *) (&date
));
888 lt
= localtime(&date
);
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;
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
);
903 time_from_yyyymmddhhmmss(buf
)
907 time_t timeresult
= (time_t) 0;
909 char *g
, *p
, y
[5], mo
[3], md
[3], h
[3], mi
[3], s
[3];
911 if (buf
&& strlen(buf
) == 14) {
914 for (k
= 0; k
< 4; ++k
)
918 for (k
= 0; k
< 2; ++k
)
922 for (k
= 0; k
< 2; ++k
)
926 for (k
= 0; k
< 2; ++k
)
929 p
= mi
; /* minutes */
930 for (k
= 0; k
< 2; ++k
)
934 for (k
= 0; k
< 2; ++k
)
940 t
.tm_year
= atoi(y
) - 1900;
941 t
.tm_mon
= atoi(mo
) - 1;
942 t
.tm_mday
= atoi(md
);
946 timeresult
= mktime(&t
);
948 if ((int) timeresult
== -1)
949 debugpline1("time_from_yyyymmddhhmmss(%s) would have returned -1",
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
;
977 goldn
= (lt
->tm_year
% 19) + 1;
978 epact
= (11 * goldn
+ 18) % 30;
979 if ((epact
== 25 && goldn
> 11) || epact
== 24)
982 return ((((((diy
+ epact
) * 6) + 11) % 177) / 22) & 7);
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);
997 register int hour
= getlt()->tm_hour
;
999 return (hour
< 6 || hour
> 21);
1005 return (getlt()->tm_hour
== 0);