1 /* aNetHack 0.0.1 hacklib.c $ANH-Date: 1472006251 2016/08/24 02:37:31 $ $ANH-Branch: master $:$ANH-Revision: 1.48 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* Copyright (c) Robert Patrick Rankin, 1991 */
4 /* aNetHack 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 aNetHack, 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 * trimspaces (char *)
22 char * strip_newline (char *)
24 boolean str_end_is (const char *, const char *)
25 char * strkitten (char *,char)
26 void copynchars (char *,const char *,int)
27 char chrcasecpy (int,int)
28 char * strcasecpy (char *,const char *)
29 char * s_suffix (const char *)
30 char * ing_suffix (const char *)
31 char * xcrypt (const char *, char *)
32 boolean onlyspace (const char *)
33 char * tabexpand (char *)
35 char * strsubst (char *, const char *, const char *)
36 const char * ordin (int)
39 int rounddiv (long, int)
40 int distmin (int, int, int, int)
41 int dist2 (int, int, int, int)
42 boolean online2 (int, int)
43 boolean pmatch (const char *, const char *)
44 boolean pmatchi (const char *, const char *)
45 boolean pmatchz (const char *, const char *)
46 int strncmpi (const char *, const char *, int)
47 char * strstri (const char *, const char *)
48 boolean fuzzymatch (const char *,const char *,
49 const char *, boolean)
53 char * yymmdd (time_t)
54 long yyyymmdd (time_t)
56 char * yyyymmddhhmmss (time_t)
57 time_t time_from_yyyymmddhhmmss (char *)
58 int phase_of_the_moon (void)
59 boolean friday_13th (void)
64 #define Static /* pacify lint */
69 static boolean
FDECL(pmatch_internal
, (const char *, const char *,
70 BOOLEAN_P
, const char *));
77 return (boolean
) ('0' <= c
&& c
<= '9');
80 /* is 'c' a letter? note: '@' classed as letter */
85 return (boolean
) ('@' <= c
&& c
<= 'Z') || ('a' <= c
&& c
<= 'z');
88 /* force 'c' into uppercase */
93 return (char) (('a' <= c
&& c
<= 'z') ? (c
& ~040) : c
);
96 /* force 'c' into lowercase */
101 return (char) (('A' <= c
&& c
<= 'Z') ? (c
| 040) : c
);
104 /* convert a string into all lowercase */
112 if ('A' <= *p
&& *p
<= 'Z')
117 /* convert a string into all uppercase */
125 if ('a' <= *p
&& *p
<= 'z')
130 /* convert first character of a string to uppercase */
140 /* remove excess whitespace from a string buffer (in place) */
145 register char c
, *p
, *p2
;
146 boolean was_space
= TRUE
;
148 for (p
= p2
= bp
; (c
= *p
) != '\0'; p
++) {
150 break; /* treat newline the same as end-of-string */
153 if (c
!= ' ' || !was_space
)
155 was_space
= (c
== ' ');
157 if (was_space
&& p2
> bp
)
163 /* remove leading and trailing whitespace, in place */
170 while (*txt
== ' ' || *txt
== '\t')
173 while (--end
>= txt
&& (*end
== ' ' || *end
== '\t'))
179 /* remove \n from end of line; remove \r too if one is there */
184 char *p
= index(str
, '\n');
187 if (p
> str
&& *(p
- 1) == '\r')
194 /* return the end of a string (pointing at '\0') */
200 s
++; /* s += strlen(s); */
204 /* determine whether 'str' ends in 'chkstr' */
206 str_end_is(str
, chkstr
)
207 const char *str
, *chkstr
;
209 int clen
= (int) strlen(chkstr
);
211 if ((int) strlen(str
) >= clen
)
212 return (boolean
) (!strncmp(eos((char *) str
) - clen
, chkstr
, clen
));
216 /* append a character to a string (in place): strcat(s, {c,'\0'}); */
229 /* truncating string copy */
231 copynchars(dst
, src
, n
)
236 /* copies at most n characters, stopping sooner if terminator reached;
237 treats newline as input terminator; unlike strncpy, always supplies
238 '\0' terminator so dst must be able to hold at least n+1 characters */
239 while (n
> 0 && *src
!= '\0' && *src
!= '\n') {
246 /* convert char nc into oc's case; mostly used by strcasecpy */
251 #if 0 /* this will be necessary if we switch to <ctype.h> */
252 oc
= (int) (unsigned char) oc
;
253 nc
= (int) (unsigned char) nc
;
255 if ('a' <= oc
&& oc
<= 'z') {
256 /* old char is lower case; if new char is upper case, downcase it */
257 if ('A' <= nc
&& nc
<= 'Z')
258 nc
+= 'a' - 'A'; /* lowc(nc) */
259 } else if ('A' <= oc
&& oc
<= 'Z') {
260 /* old char is upper case; if new char is lower case, upcase it */
261 if ('a' <= nc
&& nc
<= 'z')
262 nc
+= 'A' - 'a'; /* highc(nc) */
267 /* overwrite string, preserving old chars' case;
268 for case-insensitive editions of makeplural() and makesingular();
269 src might be shorter, same length, or longer than dst */
276 int ic
, oc
, dst_exhausted
= 0;
278 /* while dst has characters, replace each one with corresponding
279 character from src, converting case in the process if they differ;
280 once dst runs out, propagate the case of its last character to any
281 remaining src; if dst starts empty, it must be a pointer to the
282 tail of some other string because we examine the char at dst[-1] */
283 while ((ic
= (int) *src
++) != '\0') {
284 if (!dst_exhausted
&& !*dst
)
286 oc
= (int) *(dst
- dst_exhausted
);
287 *dst
++ = chrcasecpy(oc
, ic
);
293 /* return a name converted to possessive */
298 Static
char buf
[BUFSZ
];
301 if (!strcmpi(buf
, "it")) /* it -> its */
303 else if (!strcmpi(buf
, "you")) /* you -> your */
305 else if (*(eos(buf
) - 1) == 's') /* Xs -> Xs' */
312 /* construct a gerund (a verb formed by appending "ing" to a noun) */
317 static const char vowel
[] = "aeiouwy";
318 static char buf
[BUFSZ
];
324 onoff
[0] = *p
= *(p
+ 1) = '\0';
325 if ((p
>= &buf
[3] && !strcmpi(p
- 3, " on"))
326 || (p
>= &buf
[4] && !strcmpi(p
- 4, " off"))
327 || (p
>= &buf
[5] && !strcmpi(p
- 5, " with"))) {
328 p
= rindex(buf
, ' ');
332 if (p
>= &buf
[3] && !index(vowel
, *(p
- 1))
333 && index(vowel
, *(p
- 2)) && !index(vowel
, *(p
- 3))) {
334 /* tip -> tipp + ing */
337 } else if (p
>= &buf
[2] && !strcmpi(p
- 2, "ie")) { /* vie -> vy + ing */
340 } else if (p
>= &buf
[1] && *(p
- 1) == 'e') /* grease -> greas + ing */
348 /* trivial text encryption routine (see makedefs) */
354 register const char *p
;
356 register int bitmask
;
358 for (bitmask
= 1, p
= str
, q
= buf
; *p
; q
++) {
362 if ((bitmask
<<= 1) >= 32)
369 /* is a string entirely whitespace? */
375 if (*s
!= ' ' && *s
!= '\t')
380 /* expand tabs into proper number of spaces */
386 register char *bp
, *s
= sbuf
;
391 /* warning: no bounds checking performed */
392 for (bp
= buf
, idx
= 0; *s
; s
++)
402 return strcpy(sbuf
, buf
);
405 #define VISCTRL_NBUF 5
406 /* make a displayable string from a character */
411 Static
char visctrl_bufs
[VISCTRL_NBUF
][5];
414 char *ccc
= visctrl_bufs
[nbuf
];
415 nbuf
= (nbuf
+ 1) % VISCTRL_NBUF
;
417 if ((uchar
) c
& 0200) {
424 ccc
[i
++] = c
| 0100; /* letter */
425 } else if (c
== 0177) {
427 ccc
[i
++] = c
& ~0100; /* '?' */
429 ccc
[i
++] = c
; /* printable character */
435 /* substitute a word or phrase in a string (in place) */
436 /* caller is responsible for ensuring that bp points to big enough buffer */
438 strsubst(bp
, orig
, replacement
)
440 const char *orig
, *replacement
;
442 char *found
, buf
[BUFSZ
];
445 found
= strstr(bp
, orig
);
447 Strcpy(buf
, found
+ strlen(orig
));
448 Strcpy(found
, replacement
);
455 /* return the ordinal suffix of a number */
458 int n
; /* note: should be non-negative */
460 register int dd
= n
% 10;
462 return (dd
== 0 || dd
> 3 || (n
% 100) / 10 == 1) ? "th"
463 : (dd
== 1) ? "st" : (dd
== 2) ? "nd" : "rd";
466 /* make a signed digit string from a number */
473 Sprintf(buf
, (n
< 0) ? "%d" : "+%d", n
);
477 /* return the sign of a number: -1, 0, or 1 */
482 return (n
< 0) ? -1 : (n
!= 0);
485 /* calculate x/y, rounding as appropriate */
495 panic("division by zero in rounddiv");
512 /* distance between two points, in moves */
514 distmin(x0
, y0
, x1
, y1
)
517 register int dx
= x0
- x1
, dy
= y0
- y1
;
523 /* The minimum number of moves to get from (x0,y0) to (x1,y1) is the
524 * larger of the [absolute value of the] two deltas.
526 return (dx
< dy
) ? dy
: dx
;
529 /* square of euclidean distance between pair of pts */
531 dist2(x0
, y0
, x1
, y1
)
534 register int dx
= x0
- x1
, dy
= y0
- y1
;
536 return dx
* dx
+ dy
* dy
;
539 /* integer square root function without using floating point */
547 * This could be replaced by a faster algorithm, but has not been because:
548 * + the simple algorithm is easy to read;
549 * + this algorithm does not require 64-bit support;
550 * + in current usage, the values passed to isqrt() are not really that
551 * large, so the performance difference is negligible;
552 * + isqrt() is used in only few places, which are not bottle-necks.
562 /* are two points lined up (on a straight line)? */
564 online2(x0
, y0
, x1
, y1
)
567 int dx
= x0
- x1
, dy
= y0
- y1
;
568 /* If either delta is zero then they're on an orthogonal line,
569 * else if the deltas are equal (signs ignored) they're on a diagonal.
571 return (boolean
) (!dy
|| !dx
|| dy
== dx
|| dy
== -dx
);
574 /* guts of pmatch(), pmatchi(), and pmatchz();
575 match a string against a pattern */
577 pmatch_internal(patrn
, strng
, ci
, sk
)
578 const char *patrn
, *strng
;
579 boolean ci
; /* True => case-insensitive, False => case-sensitive */
580 const char *sk
; /* set of characters to skip */
584 * Simple pattern matcher: '*' matches 0 or more characters, '?' matches
585 * any single character. Returns TRUE if 'strng' matches 'patrn'.
590 p
= *patrn
++; /* get next chars and pre-advance */
592 /* fuzzy match variant of pmatch; particular characters are ignored */
595 } while (index(sk
, s
));
598 } while (index(sk
, p
));
600 if (!p
) /* end of pattern */
601 return (boolean
) (s
== '\0'); /* matches iff end of string too */
602 else if (p
== '*') /* wildcard reached */
603 return (boolean
) ((!*patrn
604 || pmatch_internal(patrn
, strng
- 1, ci
, sk
))
606 : s
? pmatch_internal(patrn
- 1, strng
, ci
, sk
)
608 else if ((ci
? lowc(p
) != lowc(s
) : p
!= s
) /* check single character */
609 && (p
!= '?' || !s
)) /* & single-char wildcard */
610 return FALSE
; /* doesn't match */
611 else /* return pmatch_internal(patrn, strng, ci, sk); */
612 goto pmatch_top
; /* optimize tail recursion */
615 /* case-sensitive wildcard match */
618 const char *patrn
, *strng
;
620 return pmatch_internal(patrn
, strng
, FALSE
, (const char *) 0);
623 /* case-insensitive wildcard match */
625 pmatchi(patrn
, strng
)
626 const char *patrn
, *strng
;
628 return pmatch_internal(patrn
, strng
, TRUE
, (const char *) 0);
631 /* case-insensitive wildcard fuzzymatch */
633 pmatchz(patrn
, strng
)
634 const char *patrn
, *strng
;
636 /* ignore spaces, tabs (just in case), dashes, and underscores */
637 static const char fuzzychars
[] = " \t-_";
639 return pmatch_internal(patrn
, strng
, TRUE
, fuzzychars
);
643 /* case insensitive counted string comparison */
645 strncmpi(s1
, s2
, n
) /*{ aka strncasecmp }*/
646 register const char *s1
, *s2
;
647 register int n
; /*(should probably be size_t, which is unsigned)*/
649 register char t1
, t2
;
653 return (*s1
!= 0); /* s1 >= s2 */
655 return -1; /* s1 < s2 */
659 return (t1
> t2
) ? 1 : -1;
661 return 0; /* s1 == s2 */
663 #endif /* STRNCMPI */
666 /* case insensitive substring search */
672 register const char *s1
, *s2
;
674 #define TABSIZ 0x20 /* 0x40 would be case-sensitive */
675 char tstr
[TABSIZ
], tsub
[TABSIZ
]; /* nibble count tables */
677 assert( (TABSIZ
& ~(TABSIZ
-1)) == TABSIZ
); /* must be exact power of 2 */
678 assert( &lowc
!= 0 ); /* can't be unsafe macro */
681 /* special case: empty substring */
685 /* do some useful work while determining relative lengths */
686 for (i
= 0; i
< TABSIZ
; i
++)
687 tstr
[i
] = tsub
[i
] = 0; /* init */
688 for (k
= 0, s1
= str
; *s1
; k
++)
689 tstr
[*s1
++ & (TABSIZ
- 1)]++;
690 for (s2
= sub
; *s2
; --k
)
691 tsub
[*s2
++ & (TABSIZ
- 1)]++;
693 /* evaluate the info we've collected */
695 return (char *) 0; /* sub longer than str, so can't match */
696 for (i
= 0; i
< TABSIZ
; i
++) /* does sub have more 'x's than str? */
697 if (tsub
[i
] > tstr
[i
])
698 return (char *) 0; /* match not possible */
700 /* now actually compare the substring repeatedly to parts of the string */
701 for (i
= 0; i
<= k
; i
++) {
704 while (lowc(*s1
++) == lowc(*s2
++))
706 return (char *) &str
[i
]; /* full match */
708 return (char *) 0; /* not found */
712 /* compare two strings for equality, ignoring the presence of specified
713 characters (typically whitespace) and possibly ignoring case */
715 fuzzymatch(s1
, s2
, ignore_chars
, caseblind
)
717 const char *ignore_chars
;
720 register char c1
, c2
;
723 while ((c1
= *s1
++) != '\0' && index(ignore_chars
, c1
) != 0)
725 while ((c2
= *s2
++) != '\0' && index(ignore_chars
, c2
) != 0)
728 break; /* stop when end of either string is reached */
736 /* match occurs only when the end of both strings has been reached */
737 return (boolean
) (!c1
&& !c2
);
743 * The time is used for:
745 * - year on tombstone and yyyymmdd in record file
746 * - phase of the moon (various monsters react to NEW_MOON or FULL_MOON)
747 * - night and midnight (the undead are dangerous at midnight)
748 * - determination of what files are "very old"
751 /* TIME_type: type of the argument to time(); we actually use &(time_t) */
752 #if defined(BSD) && !defined(POSIX_TYPES)
753 #define TIME_type long *
755 #define TIME_type time_t *
757 /* LOCALTIME_type: type of the argument to localtime() */
758 #if (defined(ULTRIX) && !(defined(ULTRIX_PROTO) || defined(NHSTDC))) \
759 || (defined(BSD) && !defined(POSIX_TYPES))
760 #define LOCALTIME_type long *
762 #define LOCALTIME_type time_t *
765 #if defined(AMIGA) && !defined(AZTEC_C) && !defined(__SASC_60) \
766 && !defined(_DCC) && !defined(__GNUC__)
767 extern struct tm
*FDECL(localtime
, (time_t *));
769 STATIC_DCL
struct tm
*NDECL(getlt
);
774 unsigned long seed
= (unsigned long) getnow(); /* time((TIME_type) 0) */
776 #if defined(UNIX) || defined(VMS)
778 unsigned long pid
= (unsigned long) getpid();
780 /* Quick dirty band-aid to prevent PRNG prediction */
789 /* the types are different enough here that sweeping the different
790 * routine names into one via #defines is even more confusing
792 #ifdef RANDOM /* srandom() from sys/share/random.c */
793 srandom((unsigned int) seed
);
795 #if defined(__APPLE__) || defined(BSD) || defined(LINUX) || defined(ULTRIX) \
796 || defined(CYGWIN32) /* system srandom() */
797 #if defined(BSD) && !defined(POSIX_TYPES) && defined(SUNOS4)
802 #ifdef UNIX /* system srand48() */
803 srand48((long) seed
);
804 #else /* poor quality system routine */
816 (void) time((TIME_type
) &datetime
);
820 STATIC_OVL
struct tm
*
823 time_t date
= getnow();
825 return localtime((LOCALTIME_type
) &date
);
831 return (1900 + getlt()->tm_year
);
835 /* This routine is no longer used since in 20YY it yields "1YYmmdd". */
840 Static
char datestr
[10];
846 lt
= localtime((LOCALTIME_type
) &date
);
848 Sprintf(datestr
, "%02d%02d%02d",
849 lt
->tm_year
, lt
->tm_mon
+ 1, lt
->tm_mday
);
864 lt
= localtime((LOCALTIME_type
) &date
);
866 /* just in case somebody's localtime supplies (year % 100)
867 rather than the expected (year - 1900) */
868 if (lt
->tm_year
< 70)
869 datenum
= (long) lt
->tm_year
+ 2000L;
871 datenum
= (long) lt
->tm_year
+ 1900L;
872 /* yyyy --> yyyymm */
873 datenum
= datenum
* 100L + (long) (lt
->tm_mon
+ 1);
874 /* yyyymm --> yyyymmdd */
875 datenum
= datenum
* 100L + (long) lt
->tm_mday
;
889 lt
= localtime((LOCALTIME_type
) &date
);
891 timenum
= lt
->tm_hour
* 10000L + lt
->tm_min
* 100L + lt
->tm_sec
;
900 static char datestr
[15];
906 #if (defined(ULTRIX) && !(defined(ULTRIX_PROTO) || defined(NHSTDC))) \
908 lt
= localtime((long *) (&date
));
910 lt
= localtime(&date
);
912 /* just in case somebody's localtime supplies (year % 100)
913 rather than the expected (year - 1900) */
914 if (lt
->tm_year
< 70)
915 datenum
= (long) lt
->tm_year
+ 2000L;
917 datenum
= (long) lt
->tm_year
+ 1900L;
918 Sprintf(datestr
, "%04ld%02d%02d%02d%02d%02d", datenum
, lt
->tm_mon
+ 1,
919 lt
->tm_mday
, lt
->tm_hour
, lt
->tm_min
, lt
->tm_sec
);
920 debugpline1("yyyymmddhhmmss() produced date string %s", datestr
);
925 time_from_yyyymmddhhmmss(buf
)
929 time_t timeresult
= (time_t) 0;
931 char *g
, *p
, y
[5], mo
[3], md
[3], h
[3], mi
[3], s
[3];
933 if (buf
&& strlen(buf
) == 14) {
936 for (k
= 0; k
< 4; ++k
)
940 for (k
= 0; k
< 2; ++k
)
944 for (k
= 0; k
< 2; ++k
)
948 for (k
= 0; k
< 2; ++k
)
951 p
= mi
; /* minutes */
952 for (k
= 0; k
< 2; ++k
)
956 for (k
= 0; k
< 2; ++k
)
962 t
.tm_year
= atoi(y
) - 1900;
963 t
.tm_mon
= atoi(mo
) - 1;
964 t
.tm_mday
= atoi(md
);
968 timeresult
= mktime(&t
);
970 if ((int) timeresult
== -1)
971 debugpline1("time_from_yyyymmddhhmmss(%s) would have returned -1",
980 * moon period = 29.53058 days ~= 30, year = 365.2422 days
981 * days moon phase advances on first day of year compared to preceding year
982 * = 365.2422 - 12*29.53058 ~= 11
983 * years in Metonic cycle (time until same phases fall on the same days of
984 * the month) = 18.6 ~= 19
985 * moon phase on first day of year (epact) ~= (11*(year%19) + 29) % 30
986 * (29 as initial condition)
987 * current phase in days = first day phase + days elapsed in year
988 * 6 moons ~= 177 days
989 * 177 ~= 8 reported phases * 22
990 * + 11/22 for rounding
993 phase_of_the_moon() /* 0-7, with 0: new, 4: full */
995 register struct tm
*lt
= getlt();
996 register int epact
, diy
, goldn
;
999 goldn
= (lt
->tm_year
% 19) + 1;
1000 epact
= (11 * goldn
+ 18) % 30;
1001 if ((epact
== 25 && goldn
> 11) || epact
== 24)
1004 return ((((((diy
+ epact
) * 6) + 11) % 177) / 22) & 7);
1010 register struct tm
*lt
= getlt();
1012 /* tm_wday (day of week; 0==Sunday) == 5 => Friday */
1013 return (boolean
) (lt
->tm_wday
== 5 && lt
->tm_mday
== 13);
1019 register int hour
= getlt()->tm_hour
;
1021 return (hour
< 6 || hour
> 21);
1027 return (getlt()->tm_hour
== 0);