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(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 /* KMH -- Used by gypsies */
512 int
getmonth()513 getmonth()
514 {
515 return (getlt()->tm_mon);
516 }
517
518 #if 0
519 /* This routine is no longer used since in 2000 it will yield "100mmdd". */
520 char *
521 yymmdd(date)
522 time_t date;
523 {
524 Static char datestr[10];
525 struct tm *lt;
526
527 if (date == 0)
528 lt = getlt();
529 else
530 #if (defined(ULTRIX) && !(defined(ULTRIX_PROTO) || defined(NHSTDC))) || defined(BSD)
531 lt = localtime((long *)(&date));
532 #else
533 lt = localtime(&date);
534 #endif
535
536 Sprintf(datestr, "%02d%02d%02d",
537 lt->tm_year, lt->tm_mon + 1, lt->tm_mday);
538 return(datestr);
539 }
540 #endif
541
542 long
yyyymmdd(date)543 yyyymmdd(date)
544 time_t date;
545 {
546 long datenum;
547 struct tm *lt;
548
549 if (date == 0)
550 lt = getlt();
551 else
552 #if (defined(ULTRIX) && !(defined(ULTRIX_PROTO) || defined(NHSTDC))) || (defined(BSD) && !defined(POSIX_TYPES))
553 lt = localtime((long *)(&date));
554 #else
555 lt = localtime(&date);
556 #endif
557
558 /* just in case somebody's localtime supplies (year % 100)
559 rather than the expected (year - 1900) */
560 if (lt->tm_year < 70)
561 datenum = (long)lt->tm_year + 2000L;
562 else
563 datenum = (long)lt->tm_year + 1900L;
564 /* yyyy --> yyyymm */
565 datenum = datenum * 100L + (long)(lt->tm_mon + 1);
566 /* yyyymm --> yyyymmdd */
567 datenum = datenum * 100L + (long)lt->tm_mday;
568 return datenum;
569 }
570
571 /*
572 * moon period = 29.53058 days ~= 30, year = 365.2422 days
573 * days moon phase advances on first day of year compared to preceding year
574 * = 365.2422 - 12*29.53058 ~= 11
575 * years in Metonic cycle (time until same phases fall on the same days of
576 * the month) = 18.6 ~= 19
577 * moon phase on first day of year (epact) ~= (11*(year%19) + 29) % 30
578 * (29 as initial condition)
579 * current phase in days = first day phase + days elapsed in year
580 * 6 moons ~= 177 days
581 * 177 ~= 8 reported phases * 22
582 * + 11/22 for rounding
583 */
584 int
phase_of_the_moon()585 phase_of_the_moon() /* 0-7, with 0: new, 4: full */
586 {
587 register struct tm *lt = getlt();
588 register int epact, diy, goldn;
589
590 diy = lt->tm_yday;
591 goldn = (lt->tm_year % 19) + 1;
592 epact = (11 * goldn + 18) % 30;
593 if ((epact == 25 && goldn > 11) || epact == 24)
594 epact++;
595
596 return( (((((diy + epact) * 6) + 11) % 177) / 22) & 7 );
597 }
598
599 boolean
friday_13th()600 friday_13th()
601 {
602 register struct tm *lt = getlt();
603
604 return((boolean)(lt->tm_wday == 5 /* friday */ && lt->tm_mday == 13));
605 }
606
607 boolean
groundhog_day()608 groundhog_day()
609 {
610 register struct tm *lt = getlt();
611
612 /* KMH -- Groundhog Day is February 2 */
613 return((boolean)(lt->tm_mon == 1 && lt->tm_mday == 2));
614 }
615
616 int
night()617 night()
618 {
619 register int hour = getlt()->tm_hour;
620
621 return(hour < 6 || hour > 21);
622 }
623
624 int
midnight()625 midnight()
626 {
627 return(getlt()->tm_hour == 0);
628 }
629 #endif /* OVL2 */
630
631 /*hacklib.c*/
632