1    | /*	SCCS Id: @(#)hacklib.c	3.3	99/04/10	*/
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    | /* We could include only config.h, except for the overlay definitions... */
7    | #include "hack.h"
8    | /*=
9    |     Assorted 'small' utility routines.	They're virtually independent of
10   | NetHack, except that rounddiv may call panic().
11   | 
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 *		mungspaces	(char *)
19   | 	char *		eos		(char *)
20   | 	char *		s_suffix	(const char *)
21   | 	char *		xcrypt		(const char *, char *)
22   | 	boolean		onlyspace	(const char *)
23   | 	char *		tabexpand	(char *)
24   | 	char *		visctrl		(char)
25   | 	const char *	ordin		(int)
26   | 	char *		sitoa		(int)
27   | 	int		sgn		(int)
28   | 	int		rounddiv	(long, int)
29   | 	int		distmin		(int, int, int, int)
30   | 	int		dist2		(int, int, int, int)
31   | 	boolean		online2		(int, int)
32   | 	boolean		pmatch		(const char *, const char *)
33   | 	int		strncmpi	(const char *, const char *, int)
34   | 	char *		strstri		(const char *, const char *)
35   | 	boolean		fuzzymatch	(const char *,const char *,const char *,boolean)
36   | 	void		setrandom	(void)
37   | 	int		getyear		(void)
38   | 	char *		yymmdd		(time_t)
39   | 	long		yyyymmdd	(time_t)
40   | 	int		phase_of_the_moon	(void)
41   | 	boolean		friday_13th	(void)
42   | 	int		night		(void)
43   | 	int		midnight	(void)
44   | =*/
45   | #ifdef LINT
46   | # define Static		/* pacify lint */
47   | #else
48   | # define Static static
49   | #endif
50   | 
51   | #ifdef OVLB
52   | boolean
53   | digit(c)		/* is 'c' a digit? */
54   |     char c;
55   | {
56   |     return((boolean)('0' <= c && c <= '9'));
57   | }
58   | 
59   | boolean
60   | letter(c)		/* is 'c' a letter?  note: '@' classed as letter */
61   |     char c;
62   | {
63   |     return((boolean)(('@' <= c && c <= 'Z') || ('a' <= c && c <= 'z')));
64   | }
65   | #endif /* OVLB */
66   | 
67   | #ifdef OVL1
68   | char
69   | highc(c)			/* force 'c' into uppercase */
70   |     char c;
71   | {
72   |     return((char)(('a' <= c && c <= 'z') ? (c & ~040) : c));
73   | }
74   | 
75   | char
76   | lowc(c)			/* force 'c' into lowercase */
77   |     char c;
78   | {
79   |     return((char)(('A' <= c && c <= 'Z') ? (c | 040) : c));
80   | }
81   | #endif /* OVL1 */
82   | 
83   | #ifdef OVLB
84   | char *
85   | lcase(s)		/* convert a string into all lowercase */
86   |     char *s;
87   | {
88   |     register char *p;
89   | 
90   |     for (p = s; *p; p++)
91   | 	if ('A' <= *p && *p <= 'Z') *p |= 040;
92   |     return s;
93   | }
94   | 
95   | /* remove excess whitespace from a string buffer (in place) */
96   | char *
97   | mungspaces(bp)
98   | char *bp;
99   | {
100  |     register char c, *p, *p2;
101  |     boolean was_space = TRUE;
102  | 
103  |     for (p = p2 = bp; (c = *p) != '\0'; p++) {
104  | 	if (c == '\t') c = ' ';
105  | 	if (c != ' ' || !was_space) *p2++ = c;
106  | 	was_space = (c == ' ');
107  |     }
108  |     if (was_space && p2 > bp) p2--;
109  |     *p2 = '\0';
110  |     return bp;
111  | }
112  | 
113  | #endif /* OVLB */
114  | 
115  | #ifdef OVL0
116  | char *
117  | eos(s)			/* return the end of a string (pointing at '\0') */
118  |     register char *s;
119  | {
120  |     while (*s) s++;	/* s += strlen(s); */
121  |     return s;
122  | }
123  | 
124  | char *
125  | s_suffix(s)		/* return a name converted to possessive */
126  |     const char *s;
127  | {
128  |     Static char buf[BUFSZ];
129  | 
130  |     Strcpy(buf, s);
131  |     if(!strcmpi(buf, "it"))
132  | 	Strcat(buf, "s");
133  |     else if(*(eos(buf)-1) == 's')
134  | 	Strcat(buf, "'");
135  |     else
136  | 	Strcat(buf, "'s");
137  |     return buf;
138  | }
139  | 
140  | char *
141  | xcrypt(str, buf)	/* trivial text encryption routine (see makedefs) */
142  | const char *str;
143  | char *buf;
144  | {
145  |     register const char *p;
146  |     register char *q;
147  |     register int bitmask;
148  | 
149  |     for (bitmask = 1, p = str, q = buf; *p; q++) {
150  | 	*q = *p++;
151  | 	if (*q & (32|64)) *q ^= bitmask;
152  | 	if ((bitmask <<= 1) >= 32) bitmask = 1;
153  |     }
154  |     *q = '\0';
155  |     return buf;
156  | }
157  | #endif /* OVL0 */
158  | 
159  | #ifdef OVL2
160  | boolean
161  | onlyspace(s)		/* is a string entirely whitespace? */
162  |     const char *s;
163  | {
164  |     for (; *s; s++)
165  | 	if (*s != ' ' && *s != '\t') return FALSE;
166  |     return TRUE;
167  | }
168  | #endif /* OVL2 */
169  | 
170  | #ifdef OVLB
171  | char *
172  | tabexpand(sbuf)		/* expand tabs into proper number of spaces */
173  |     char *sbuf;
174  | {
175  |     char buf[BUFSZ];
176  |     register char *bp, *s = sbuf;
177  |     register int idx;
178  | 
179  |     if (!*s) return sbuf;
180  | 
181  |     /* warning: no bounds checking performed */
182  |     for (bp = buf, idx = 0; *s; s++)
183  | 	if (*s == '\t') {
184  | 	    do *bp++ = ' '; while (++idx % 8);
185  | 	} else {
186  | 	    *bp++ = *s;
187  | 	    idx++;
188  | 	}
189  |     *bp = 0;
190  |     return strcpy(sbuf, buf);
191  | }
192  | 
193  | char *
194  | visctrl(c)		/* make a displayable string from a character */
195  |     char c;
196  | {
197  |     Static char ccc[3];
198  | 
199  |     c &= 0177;
200  | 
201  |     ccc[2] = '\0';
202  |     if (c < 040) {
203  | 	ccc[0] = '^';
204  | 	ccc[1] = c | 0100;	/* letter */
205  |     } else if (c == 0177) {
206  | 	ccc[0] = '^';
207  | 	ccc[1] = c & ~0100;	/* '?' */
208  |     } else {
209  | 	ccc[0] = c;		/* printable character */
210  | 	ccc[1] = '\0';
211  |     }
212  |     return ccc;
213  | }
214  | #endif /* OVLB */
215  | 
216  | #ifdef OVL2
217  | const char *
218  | ordin(n)		/* return the ordinal suffix of a number */
219  |     int n;			/* note: should be non-negative */
220  | {
221  |     register int dd = n % 10;
222  | 
223  |     return (dd == 0 || dd > 3 || (n % 100) / 10 == 1) ? "th" :
224  | 	    (dd == 1) ? "st" : (dd == 2) ? "nd" : "rd";
225  | }
226  | #endif /* OVL2 */
227  | 
228  | #ifdef OVL1
229  | char *
230  | sitoa(n)		/* make a signed digit string from a number */
231  |     int n;
232  | {
233  |     Static char buf[13];
234  | 
235  |     Sprintf(buf, (n < 0) ? "%d" : "+%d", n);
236  |     return buf;
237  | }
238  | 
239  | int
240  | sgn(n)			/* return the sign of a number: -1, 0, or 1 */
241  |     int n;
242  | {
243  |     return (n < 0) ? -1 : (n != 0);
244  | }
245  | #endif /* OVL1 */
246  | 
247  | #ifdef OVLB
248  | int
249  | rounddiv(x, y)		/* calculate x/y, rounding as appropriate */
250  |     long x;
251  |     int  y;
252  | {
253  |     int r, m;
254  |     int divsgn = 1;
255  | 
256  |     if (y == 0)
257  | 	panic("division by zero in rounddiv");
258  |     else if (y < 0) {
259  | 	divsgn = -divsgn;  y = -y;
260  |     }
261  |     if (x < 0) {
262  | 	divsgn = -divsgn;  x = -x;
263  |     }
264  |     r = x / y;
265  |     m = x % y;
266  |     if (2*m >= y) r++;
267  | 
268  |     return divsgn * r;
269  | }
270  | #endif /* OVLB */
271  | 
272  | #ifdef OVL0
273  | int
274  | distmin(x0, y0, x1, y1) /* distance between two points, in moves */
275  |     int x0, y0, x1, y1;
276  | {
277  |     register int dx = x0 - x1, dy = y0 - y1;
278  |     if (dx < 0) dx = -dx;
279  |     if (dy < 0) dy = -dy;
280  |   /*  The minimum number of moves to get from (x0,y0) to (x1,y1) is the
281  |    :  larger of the [absolute value of the] two deltas.
282  |    */
283  |     return (dx < dy) ? dy : dx;
284  | }
285  | 
286  | int
287  | dist2(x0, y0, x1, y1)	/* square of euclidean distance between pair of pts */
288  |     int x0, y0, x1, y1;
289  | {
290  |     register int dx = x0 - x1, dy = y0 - y1;
291  |     return dx * dx + dy * dy;
292  | }
293  | 
294  | boolean
295  | online2(x0, y0, x1, y1) /* are two points lined up (on a straight line)? */
296  |     int x0, y0, x1, y1;
297  | {
298  |     int dx = x0 - x1, dy = y0 - y1;
299  |     /*  If either delta is zero then they're on an orthogonal line,
300  |      *  else if the deltas are equal (signs ignored) they're on a diagonal.
301  |      */
302  |     return((boolean)(!dy || !dx || (dy == dx) || (dy + dx == 0)));	/* (dy == -dx) */
303  | }
304  | 
305  | #endif /* OVL0 */
306  | #ifdef OVLB
307  | 
308  | boolean
309  | pmatch(patrn, strng)	/* match a string against a pattern */
310  |     const char *patrn, *strng;
311  | {
312  |     char s, p;
313  |   /*
314  |    :  Simple pattern matcher:  '*' matches 0 or more characters, '?' matches
315  |    :  any single character.  Returns TRUE if 'strng' matches 'patrn'.
316  |    */
317  | pmatch_top:
318  |     s = *strng++;  p = *patrn++;	/* get next chars and pre-advance */
319  |     if (!p)			/* end of pattern */
320  | 	return((boolean)(s == '\0'));		/* matches iff end of string too */
321  |     else if (p == '*')		/* wildcard reached */
322  | 	return((boolean)((!*patrn || pmatch(patrn, strng-1)) ? TRUE :
323  | 		s ? pmatch(patrn-1, strng) : FALSE));
324  |     else if (p != s && (p != '?' || !s))  /* check single character */
325  | 	return FALSE;		/* doesn't match */
326  |     else				/* return pmatch(patrn, strng); */
327  | 	goto pmatch_top;	/* optimize tail recursion */
328  | }
329  | #endif /* OVLB */
330  | 
331  | #ifdef OVL2
332  | #ifndef STRNCMPI
333  | int
334  | strncmpi(s1, s2, n)	/* case insensitive counted string comparison */
335  |     register const char *s1, *s2;
336  |     register int n; /*(should probably be size_t, which is usually unsigned)*/
337  | {					/*{ aka strncasecmp }*/
338  |     register char t1, t2;
339  | 
340  |     while (n--) {
341  | 	if (!*s2) return (*s1 != 0);	/* s1 >= s2 */
342  | 	else if (!*s1) return -1;	/* s1  < s2 */
343  | 	t1 = lowc(*s1++);
344  | 	t2 = lowc(*s2++);
345  | 	if (t1 != t2) return (t1 > t2) ? 1 : -1;
346  |     }
347  |     return 0;				/* s1 == s2 */
348  | }
349  | #endif	/* STRNCMPI */
350  | #endif /* OVL2 */
351  | 
352  | #ifdef OVLB
353  | #ifndef STRSTRI
354  | 
355  | char *
356  | strstri(str, sub)	/* case insensitive substring search */
357  |     const char *str;
358  |     const char *sub;
359  | {
360  |     register const char *s1, *s2;
361  |     register int i, k;
362  | # define TABSIZ 0x20	/* 0x40 would be case-sensitive */
363  |     char tstr[TABSIZ], tsub[TABSIZ];	/* nibble count tables */
364  | # if 0
365  |     assert( (TABSIZ & ~(TABSIZ-1)) == TABSIZ ); /* must be exact power of 2 */
366  |     assert( &lowc != 0 );			/* can't be unsafe macro */
367  | # endif
368  | 
369  |     /* special case: empty substring */
370  |     if (!*sub)	return (char *) str;
371  | 
372  |     /* do some useful work while determining relative lengths */
373  |     for (i = 0; i < TABSIZ; i++)  tstr[i] = tsub[i] = 0;	/* init */
374  |     for (k = 0, s1 = str; *s1; k++)  tstr[*s1++ & (TABSIZ-1)]++;
375  |     for (	s2 = sub; *s2; --k)  tsub[*s2++ & (TABSIZ-1)]++;
376  | 
377  |     /* evaluate the info we've collected */
378  |     if (k < 0)	return (char *) 0;  /* sub longer than str, so can't match */
379  |     for (i = 0; i < TABSIZ; i++)	/* does sub have more 'x's than str? */
380  | 	if (tsub[i] > tstr[i])	return (char *) 0;  /* match not possible */
381  | 
382  |     /* now actually compare the substring repeatedly to parts of the string */
383  |     for (i = 0; i <= k; i++) {
384  | 	s1 = &str[i];
385  | 	s2 = sub;
386  | 	while (lowc(*s1++) == lowc(*s2++))
387  | 	    if (!*s2)  return (char *) &str[i];		/* full match */
388  |     }
389  |     return (char *) 0;	/* not found */
390  | }
391  | #endif	/* STRSTRI */
392  | 
393  | /* compare two strings for equality, ignoring the presence of specified
394  |    characters (typically whitespace) and possibly ignoring case */
395  | boolean
396  | fuzzymatch(s1, s2, ignore_chars, caseblind)
397  |     const char *s1, *s2;
398  |     const char *ignore_chars;
399  |     boolean caseblind;
400  | {
401  |     register char c1, c2;
402  | 
403  |     do {
404  | 	while ((c1 = *s1++) != '\0' && index(ignore_chars, c1) != 0) continue;
405  | 	while ((c2 = *s2++) != '\0' && index(ignore_chars, c2) != 0) continue;
406  | 	if (!c1 || !c2) break;	/* stop when end of either string is reached */
407  | 
408  | 	if (caseblind) {
409  | 	    c1 = lowc(c1);
410  | 	    c2 = lowc(c2);
411  | 	}
412  |     } while (c1 == c2);
413  | 
414  |     /* match occurs only when the end of both strings has been reached */
415  |     return (boolean)(!c1 && !c2);
416  | }
417  | 
418  | #endif /* OVLB */
419  | #ifdef OVL2
420  | 
421  | /*
422  |  * Time routines
423  |  *
424  |  * The time is used for:
425  |  *	- seed for rand()
426  |  *	- year on tombstone and yyyymmdd in record file
427  |  *	- phase of the moon (various monsters react to NEW_MOON or FULL_MOON)
428  |  *	- night and midnight (the undead are dangerous at midnight)
429  |  *	- determination of what files are "very old"
430  |  */
431  | 
432  | #if defined(AMIGA) && !defined(AZTEC_C) && !defined(__SASC_60) && !defined(_DCC)
433  | extern struct tm *FDECL(localtime,(time_t *));
434  | #endif
435  | static struct tm *NDECL(getlt);
436  | 
437  | void
438  | setrandom()
439  | {
440  | 	/* the types are different enough here that sweeping the different
441  | 	 * routine names into one via #defines is even more confusing
442  | 	 */
443  | #ifdef RANDOM	/* srandom() from sys/share/random.c */
444  | 	srandom((unsigned int) time((time_t *)0));
445  | #else
446  | # if defined(BSD) || defined(ULTRIX) || defined(CYGWIN32) /* system srandom() */
447  | #  ifdef BSD
448  | #   if defined(SUNOS4)
449  | 	(void)
450  | #   endif
451  | 		srandom((int) time((long *)0));
452  | #  else
453  | 		srandom((int) time((time_t *)0));
454  | #  endif
455  | # else
456  | #  ifdef UNIX	/* system srand48() */
457  | 	srand48((long) time((time_t *)0));
458  | #  else		/* poor quality system routine */
459  | 	srand((int) time((time_t *)0));
460  | #  endif
461  | # endif
462  | #endif
463  | }
464  | 
465  | static struct tm *
466  | getlt()
467  | {
468  | 	time_t date;
469  | 
470  | #ifdef BSD
471  | 	(void) time((long *)(&date));
472  | #else
473  | 	(void) time(&date);
474  | #endif
475  | #if (defined(ULTRIX) && !(defined(ULTRIX_PROTO) || defined(NHSTDC))) || defined(BSD)
476  | 	return(localtime((long *)(&date)));
477  | #else
478  | 	return(localtime(&date));
479  | #endif
480  | }
481  | 
482  | int
483  | getyear()
484  | {
485  | 	return(1900 + getlt()->tm_year);
486  | }
487  | 
488  | #if 0
489  | /* This routine is no longer used since in 2000 it will yield "100mmdd". */
490  | char *
491  | yymmdd(date)
492  | time_t date;
493  | {
494  | 	Static char datestr[10];
495  | 	struct tm *lt;
496  | 
497  | 	if (date == 0)
498  | 		lt = getlt();
499  | 	else
500  | #if (defined(ULTRIX) && !(defined(ULTRIX_PROTO) || defined(NHSTDC))) || defined(BSD)
501  | 		lt = localtime((long *)(&date));
502  | #else
503  | 		lt = localtime(&date);
504  | #endif
505  | 
506  | 	Sprintf(datestr, "%02d%02d%02d",
507  | 		lt->tm_year, lt->tm_mon + 1, lt->tm_mday);
508  | 	return(datestr);
509  | }
510  | #endif
511  | 
512  | long
513  | yyyymmdd(date)
514  | time_t date;
515  | {
516  | 	long datenum;
517  | 	struct tm *lt;
518  | 
519  | 	if (date == 0)
520  | 		lt = getlt();
521  | 	else
522  | #if (defined(ULTRIX) && !(defined(ULTRIX_PROTO) || defined(NHSTDC))) || defined(BSD)
523  | 		lt = localtime((long *)(&date));
524  | #else
525  | 		lt = localtime(&date);
526  | #endif
527  | 
528  | 	/* just in case somebody's localtime supplies (year % 100)
529  | 	   rather than the expected (year - 1900) */
530  | 	if (lt->tm_year < 70)
531  | 	    datenum = (long)lt->tm_year + 2000L;
532  | 	else
533  | 	    datenum = (long)lt->tm_year + 1900L;
534  | 	/* yyyy --> yyyymm */
535  | 	datenum = datenum * 100L + (long)(lt->tm_mon + 1);
536  | 	/* yyyymm --> yyyymmdd */
537  | 	datenum = datenum * 100L + (long)lt->tm_mday;
538  | 	return datenum;
539  | }
540  | 
541  | /*
542  |  * moon period = 29.53058 days ~= 30, year = 365.2422 days
543  |  * days moon phase advances on first day of year compared to preceding year
544  |  *	= 365.2422 - 12*29.53058 ~= 11
545  |  * years in Metonic cycle (time until same phases fall on the same days of
546  |  *	the month) = 18.6 ~= 19
547  |  * moon phase on first day of year (epact) ~= (11*(year%19) + 29) % 30
548  |  *	(29 as initial condition)
549  |  * current phase in days = first day phase + days elapsed in year
550  |  * 6 moons ~= 177 days
551  |  * 177 ~= 8 reported phases * 22
552  |  * + 11/22 for rounding
553  |  */
554  | int
555  | phase_of_the_moon()		/* 0-7, with 0: new, 4: full */
556  | {
557  | 	register struct tm *lt = getlt();
558  | 	register int epact, diy, goldn;
559  | 
560  | 	diy = lt->tm_yday;
561  | 	goldn = (lt->tm_year % 19) + 1;
562  | 	epact = (11 * goldn + 18) % 30;
563  | 	if ((epact == 25 && goldn > 11) || epact == 24)
564  | 		epact++;
565  | 
566  | 	return( (((((diy + epact) * 6) + 11) % 177) / 22) & 7 );
567  | }
568  | 
569  | boolean
570  | friday_13th()
571  | {
572  | 	register struct tm *lt = getlt();
573  | 
574  | 	return((boolean)(lt->tm_wday == 5 /* friday */ && lt->tm_mday == 13));
575  | }
576  | 
577  | int
578  | night()
579  | {
580  | 	register int hour = getlt()->tm_hour;
581  | 
582  | 	return(hour < 6 || hour > 21);
583  | }
584  | 
585  | int
586  | midnight()
587  | {
588  | 	return(getlt()->tm_hour == 0);
589  | }
590  | #endif /* OVL2 */
591  | 
592  | /*hacklib.c*/