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