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
digit(c)53 digit(c)		/* is 'c' a digit? */
54     char c;
55 {
56     return((boolean)('0' <= c && c <= '9'));
57 }
58 
59 boolean
letter(c)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
highc(c)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
lowc(c)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 *
lcase(s)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 *
mungspaces(bp)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 *
eos(s)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 *
s_suffix(s)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 *
xcrypt(str,buf)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
onlyspace(s)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 *
tabexpand(sbuf)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 *
visctrl(c)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 *
ordin(n)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 *
sitoa(n)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
sgn(n)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
rounddiv(x,y)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
distmin(x0,y0,x1,y1)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
dist2(x0,y0,x1,y1)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
online2(x0,y0,x1,y1)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
pmatch(patrn,strng)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
strncmpi(s1,s2,n)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 *
strstri(str,sub)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
fuzzymatch(s1,s2,ignore_chars,caseblind)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
setrandom()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 *
getlt()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
getyear()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
yyyymmdd(date)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
phase_of_the_moon()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
friday_13th()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
night()578 night()
579 {
580 	register int hour = getlt()->tm_hour;
581 
582 	return(hour < 6 || hour > 21);
583 }
584 
585 int
midnight()586 midnight()
587 {
588 	return(getlt()->tm_hour == 0);
589 }
590 #endif /* OVL2 */
591 
592 /*hacklib.c*/
593