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