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