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