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