Blindfold removal fix
[slashemextended.git] / src / hacklib.c
blob6100af1d7b1e5db455e74a4348369a7a012c78c2
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. */
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().
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 char * reversestring (char *)
38 boolean fuzzymatch (const char *,const char *,const char *,boolean)
39 void setrandom (void)
40 int getyear (void)
41 char * yymmdd (time_t)
42 long yyyymmdd (time_t)
43 int phase_of_the_moon (void)
44 boolean friday_13th (void)
45 int night (void)
46 int midnight (void)
47 =*/
48 #ifdef LINT
49 # define Static /* pacify lint */
50 #else
51 # define Static static
52 #endif
54 #ifdef OVLB
55 boolean
56 digit(c) /* is 'c' a digit? */
57 char c;
59 return((boolean)('0' <= c && c <= '9'));
62 boolean
63 letter(c) /* is 'c' a letter? note: '@' classed as letter */
64 char c;
66 return((boolean)(('@' <= c && c <= 'Z') || ('a' <= c && c <= 'z')));
68 #endif /* OVLB */
70 #ifdef OVL1
71 char
72 highc(c) /* force 'c' into uppercase */
73 char c;
75 return((char)(('a' <= c && c <= 'z') ? (c & ~040) : c));
78 char
79 lowc(c) /* force 'c' into lowercase */
80 char c;
82 return((char)(('A' <= c && c <= 'Z') ? (c | 040) : c));
84 #endif /* OVL1 */
86 #ifdef OVLB
87 char *
88 lcase(s) /* convert a string into all lowercase */
89 char *s;
91 register char *p;
93 for (p = s; *p; p++)
94 if ('A' <= *p && *p <= 'Z') *p |= 040;
95 return s;
98 char *
99 upstart(s) /* convert first character of a string to uppercase */
100 char *s;
102 if (s) *s = highc(*s);
103 return s;
106 /* remove excess whitespace from a string buffer (in place) */
107 char *
108 mungspaces(bp)
109 char *bp;
111 register char c, *p, *p2;
112 boolean was_space = TRUE;
114 for (p = p2 = bp; (c = *p) != '\0'; p++) {
115 if (c == '\t') c = ' ';
116 if (c != ' ' || !was_space) *p2++ = c;
117 was_space = (c == ' ');
119 if (was_space && p2 > bp) p2--;
120 *p2 = '\0';
121 return bp;
124 #endif /* OVLB */
126 #ifdef OVL0
127 char *
128 eos(s) /* return the end of a string (pointing at '\0') */
129 register char *s;
131 while (*s) s++; /* s += strlen(s); */
132 return s;
135 /* strcat(s, {c,'\0'}); */
136 char *
137 strkitten(s, c) /* append a character to a string (in place) */
138 char *s;
139 char c;
141 char *p = eos(s);
143 *p++ = c;
144 *p = '\0';
145 return s;
148 char *
149 reversestring(char *str)
151 char *p1, *p2;
153 if (!str || !*str)
154 return str;
155 for (p1 = str, p2 = str + strlen(str) - 1; p2 > p1; ++p1, --p2)
157 *p1 ^= *p2;
158 *p2 ^= *p1;
159 *p1 ^= *p2;
161 return str;
164 char *
165 s_suffix(s) /* return a name converted to possessive */
166 const char *s;
168 Static char buf[BUFSZ];
170 strcpy(buf, s);
171 if(!strcmpi(buf, "it"))
172 strcat(buf, "s");
173 else if(*(eos(buf)-1) == 's')
174 strcat(buf, "'");
175 else
176 strcat(buf, "'s");
177 return buf;
180 char *
181 xcrypt(str, buf) /* trivial text encryption routine (see makedefs) */
182 const char *str;
183 char *buf;
185 register const char *p;
186 register char *q;
187 register int bitmask;
189 for (bitmask = 1, p = str, q = buf; *p; q++) {
190 *q = *p++;
191 if (*q & (32|64)) *q ^= bitmask;
192 if ((bitmask <<= 1) >= 32) bitmask = 1;
194 *q = '\0';
195 return buf;
197 #endif /* OVL0 */
199 #ifdef OVL2
200 boolean
201 onlyspace(s) /* is a string entirely whitespace? */
202 const char *s;
204 for (; *s; s++)
205 if (*s != ' ' && *s != '\t') return FALSE;
206 return TRUE;
208 #endif /* OVL2 */
210 #ifdef OVLB
211 char *
212 tabexpand(sbuf) /* expand tabs into proper number of spaces */
213 char *sbuf;
215 char buf[BUFSZ];
216 register char *bp, *s = sbuf;
217 register int idx;
219 if (!*s) return sbuf;
221 /* warning: no bounds checking performed */
222 for (bp = buf, idx = 0; *s; s++)
223 if (*s == '\t') {
224 do *bp++ = ' '; while (++idx % 8);
225 } else {
226 *bp++ = *s;
227 idx++;
229 *bp = 0;
230 return strcpy(sbuf, buf);
233 char *
234 visctrl(c) /* make a displayable string from a character */
235 char c;
237 Static char ccc[3];
239 c &= 0177;
241 ccc[2] = '\0';
242 if (c < 040) {
243 ccc[0] = '^';
244 ccc[1] = c | 0100; /* letter */
245 } else if (c == 0177) {
246 ccc[0] = '^';
247 ccc[1] = c & ~0100; /* '?' */
248 } else {
249 ccc[0] = c; /* printable character */
250 ccc[1] = '\0';
252 return ccc;
254 #endif /* OVLB */
256 #ifdef OVL2
257 const char *
258 ordin(n) /* return the ordinal suffix of a number */
259 int n; /* note: should be non-negative */
261 register int dd = n % 10;
263 return (dd == 0 || dd > 3 || (n % 100) / 10 == 1) ? "th" :
264 (dd == 1) ? "st" : (dd == 2) ? "nd" : "rd";
266 #endif /* OVL2 */
268 #ifdef OVL1
269 char *
270 sitoa(n) /* make a signed digit string from a number */
271 int n;
273 Static char buf[13];
275 sprintf(buf, (n < 0) ? "%d" : "+%d", n);
276 return buf;
280 sgn(n) /* return the sign of a number: -1, 0, or 1 */
281 int n;
283 return (n < 0) ? -1 : (n != 0);
285 #endif /* OVL1 */
287 #ifdef OVLB
289 rounddiv(x, y) /* calculate x/y, rounding as appropriate */
290 long x;
291 int y;
293 int r, m;
294 int divsgn = 1;
296 if (y == 0)
297 panic("division by zero in rounddiv");
298 else if (y < 0) {
299 divsgn = -divsgn; y = -y;
301 if (x < 0) {
302 divsgn = -divsgn; x = -x;
304 r = x / y;
305 m = x % y;
306 if (2*m >= y) r++;
308 return divsgn * r;
310 #endif /* OVLB */
312 #ifdef OVL0
314 distmin(x0, y0, x1, y1) /* distance between two points, in moves */
315 int x0, y0, x1, y1;
317 register int dx = x0 - x1, dy = y0 - y1;
318 if (dx < 0) dx = -dx;
319 if (dy < 0) dy = -dy;
320 /* The minimum number of moves to get from (x0,y0) to (x1,y1) is the
321 : larger of the [absolute value of the] two deltas.
323 return (dx < dy) ? dy : dx;
327 dist2(x0, y0, x1, y1) /* square of euclidean distance between pair of pts */
328 int x0, y0, x1, y1;
330 register int dx = x0 - x1, dy = y0 - y1;
331 return dx * dx + dy * dy;
334 boolean
335 online2(x0, y0, x1, y1) /* are two points lined up (on a straight line)? */
336 int x0, y0, x1, y1;
338 int dx = x0 - x1, dy = y0 - y1;
339 /* If either delta is zero then they're on an orthogonal line,
340 * else if the deltas are equal (signs ignored) they're on a diagonal.
342 return((boolean)(!dy || !dx || (dy == dx) || (dy + dx == 0))); /* (dy == -dx) */
345 #endif /* OVL0 */
346 #ifdef OVLB
348 boolean
349 pmatch(patrn, strng) /* match a string against a pattern */
350 const char *patrn, *strng;
352 char s, p;
354 : Simple pattern matcher: '*' matches 0 or more characters, '?' matches
355 : any single character. Returns TRUE if 'strng' matches 'patrn'.
357 pmatch_top:
358 s = *strng++; p = *patrn++; /* get next chars and pre-advance */
359 if (!p) /* end of pattern */
360 return((boolean)(s == '\0')); /* matches iff end of string too */
361 else if (p == '*') /* wildcard reached */
362 return((boolean)((!*patrn || pmatch(patrn, strng-1)) ? TRUE :
363 s ? pmatch(patrn-1, strng) : FALSE));
364 else if (p != s && (p != '?' || !s)) /* check single character */
365 return FALSE; /* doesn't match */
366 else /* return pmatch(patrn, strng); */
367 goto pmatch_top; /* optimize tail recursion */
369 #endif /* OVLB */
371 #ifdef OVL2
372 #ifndef STRNCMPI
374 strncmpi(s1, s2, n) /* case insensitive counted string comparison */
375 register const char *s1, *s2;
376 register int n; /*(should probably be size_t, which is usually unsigned)*/
377 { /*{ aka strncasecmp }*/
378 register char t1, t2;
380 while (n--) {
381 if (!*s2) return (*s1 != 0); /* s1 >= s2 */
382 else if (!*s1) return -1; /* s1 < s2 */
383 t1 = lowc(*s1++);
384 t2 = lowc(*s2++);
385 if (t1 != t2) return (t1 > t2) ? 1 : -1;
387 return 0; /* s1 == s2 */
389 #endif /* STRNCMPI */
390 #endif /* OVL2 */
392 #ifdef OVLB
393 #ifndef STRSTRI
395 char *
396 strstri(str, sub) /* case insensitive substring search */
397 const char *str;
398 const char *sub;
400 register const char *s1, *s2;
401 register int i, k;
402 # define TABSIZ 0x20 /* 0x40 would be case-sensitive */
403 char tstr[TABSIZ], tsub[TABSIZ]; /* nibble count tables */
404 # if 0
405 assert( (TABSIZ & ~(TABSIZ-1)) == TABSIZ ); /* must be exact power of 2 */
406 assert( &lowc != 0 ); /* can't be unsafe macro */
407 # endif
409 /* special case: empty substring */
410 if (!*sub) return (char *) str;
412 /* do some useful work while determining relative lengths */
413 for (i = 0; i < TABSIZ; i++) tstr[i] = tsub[i] = 0; /* init */
414 for (k = 0, s1 = str; *s1; k++) tstr[*s1++ & (TABSIZ-1)]++;
415 for ( s2 = sub; *s2; --k) tsub[*s2++ & (TABSIZ-1)]++;
417 /* evaluate the info we've collected */
418 if (k < 0) return (char *) 0; /* sub longer than str, so can't match */
419 for (i = 0; i < TABSIZ; i++) /* does sub have more 'x's than str? */
420 if (tsub[i] > tstr[i]) return (char *) 0; /* match not possible */
422 /* now actually compare the substring repeatedly to parts of the string */
423 for (i = 0; i <= k; i++) {
424 s1 = &str[i];
425 s2 = sub;
426 while (lowc(*s1++) == lowc(*s2++))
427 if (!*s2) return (char *) &str[i]; /* full match */
429 return (char *) 0; /* not found */
431 #endif /* STRSTRI */
433 /* compare two strings for equality, ignoring the presence of specified
434 characters (typically whitespace) and possibly ignoring case */
435 boolean
436 fuzzymatch(s1, s2, ignore_chars, caseblind)
437 const char *s1, *s2;
438 const char *ignore_chars;
439 boolean caseblind;
441 register char c1, c2;
443 do {
444 while ((c1 = *s1++) != '\0' && index(ignore_chars, c1) != 0) continue;
445 while ((c2 = *s2++) != '\0' && index(ignore_chars, c2) != 0) continue;
446 if (!c1 || !c2) break; /* stop when end of either string is reached */
448 if (caseblind) {
449 c1 = lowc(c1);
450 c2 = lowc(c2);
452 } while (c1 == c2);
454 /* match occurs only when the end of both strings has been reached */
455 return (boolean)(!c1 && !c2);
458 #endif /* OVLB */
459 #ifdef OVL2
462 * Time routines
464 * The time is used for:
465 * - seed for rand()
466 * - year on tombstone and yyyymmdd in record file
467 * - phase of the moon (various monsters react to NEW_MOON or FULL_MOON)
468 * - night and midnight (the undead are dangerous at midnight)
469 * - determination of what files are "very old"
472 #if defined(AMIGA) && !defined(AZTEC_C) && !defined(__SASC_60) && !defined(_DCC) && !defined(__GNUC__)
473 extern struct tm *localtime(time_t *);
474 #endif
475 struct tm *getlt(void);
477 void
478 setrandom()
480 /* the types are different enough here that sweeping the different
481 * routine names into one via #defines is even more confusing
483 #ifdef RANDOM /* srandom() from sys/share/random.c */
484 srandom((unsigned int) time((time_t *)0));
485 #else
486 # if defined(BSD) || defined(LINUX) || defined(ULTRIX) || defined(CYGWIN32) /* system srandom() */
487 # if defined(BSD) && !defined(POSIX_TYPES)
488 # if defined(SUNOS4)
489 (void)
490 # endif
491 srandom((int) time((long *)0));
492 # else
493 srandom((int) time((time_t *)0));
494 # endif
495 # else
496 # ifdef UNIX /* system srand48() */
497 srand48((long) time((time_t *)0));
498 # else /* poor quality system routine */
499 srand((int) time((time_t *)0));
500 # endif
501 # endif
502 #endif
505 struct tm *
506 getlt()
508 time_t date;
510 #if defined(BSD) && !defined(POSIX_TYPES)
511 (void) time((long *)(&date));
512 #else
513 (void) time(&date);
514 #endif
515 #if (defined(ULTRIX) && !(defined(ULTRIX_PROTO) || defined(NHSTDC))) || (defined(BSD) && !defined(POSIX_TYPES))
516 return(localtime((long *)(&date)));
517 #else
518 return(localtime(&date));
519 #endif
523 getyear()
525 return(1900 + getlt()->tm_year);
528 /* KMH -- Used by gypsies */
530 getmonth()
532 return (getlt()->tm_mon);
535 #if 0
536 /* This routine is no longer used since in 2000 it will yield "100mmdd". */
537 char *
538 yymmdd(date)
539 time_t date;
541 Static char datestr[10];
542 struct tm *lt;
544 if (date == 0)
545 lt = getlt();
546 else
547 #if (defined(ULTRIX) && !(defined(ULTRIX_PROTO) || defined(NHSTDC))) || defined(BSD)
548 lt = localtime((long *)(&date));
549 #else
550 lt = localtime(&date);
551 #endif
553 sprintf(datestr, "%02d%02d%02d",
554 lt->tm_year, lt->tm_mon + 1, lt->tm_mday);
555 return(datestr);
557 #endif
559 long
560 yyyymmdd(date)
561 time_t date;
563 long datenum;
564 struct tm *lt;
566 if (date == 0)
567 lt = getlt();
568 else
569 #if (defined(ULTRIX) && !(defined(ULTRIX_PROTO) || defined(NHSTDC))) || (defined(BSD) && !defined(POSIX_TYPES))
570 lt = localtime((long *)(&date));
571 #else
572 lt = localtime(&date);
573 #endif
575 /* just in case somebody's localtime supplies (year % 100)
576 rather than the expected (year - 1900) */
577 if (lt->tm_year < 70)
578 datenum = (long)lt->tm_year + 2000L;
579 else
580 datenum = (long)lt->tm_year + 1900L;
581 /* yyyy --> yyyymm */
582 datenum = datenum * 100L + (long)(lt->tm_mon + 1);
583 /* yyyymm --> yyyymmdd */
584 datenum = datenum * 100L + (long)lt->tm_mday;
585 return datenum;
589 * moon period = 29.53058 days ~= 30, year = 365.2422 days
590 * days moon phase advances on first day of year compared to preceding year
591 * = 365.2422 - 12*29.53058 ~= 11
592 * years in Metonic cycle (time until same phases fall on the same days of
593 * the month) = 18.6 ~= 19
594 * moon phase on first day of year (epact) ~= (11*(year%19) + 29) % 30
595 * (29 as initial condition)
596 * current phase in days = first day phase + days elapsed in year
597 * 6 moons ~= 177 days
598 * 177 ~= 8 reported phases * 22
599 * + 11/22 for rounding
602 phase_of_the_moon() /* 0-7, with 0: new, 4: full */
604 register struct tm *lt = getlt();
605 register int epact, diy, goldn;
607 diy = lt->tm_yday;
608 goldn = (lt->tm_year % 19) + 1;
609 epact = (11 * goldn + 18) % 30;
610 if ((epact == 25 && goldn > 11) || epact == 24)
611 epact++;
613 return( (((((diy + epact) * 6) + 11) % 177) / 22) & 7 );
616 boolean
617 friday_13th()
619 register struct tm *lt = getlt();
621 return((boolean)(lt->tm_wday == 5 /* friday */ && lt->tm_mday == 13));
624 boolean
625 groundhog_day()
627 register struct tm *lt = getlt();
629 /* KMH -- Groundhog Day is February 2 */
630 return((boolean)(lt->tm_mon == 1 && lt->tm_mday == 2));
634 night()
636 register int hour = getlt()->tm_hour;
638 return(hour < 6 || hour > 21);
642 midnight()
644 return(getlt()->tm_hour == 0);
646 #endif /* OVL2 */
648 /*hacklib.c*/