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