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... */
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)
18 char * upstart (char *)
19 char * mungspaces (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 *)
27 const char * ordin (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)
40 char * yymmdd (time_t)
41 long yyyymmdd (time_t)
42 int phase_of_the_moon (void)
43 boolean friday_13th (void)
48 # define Static /* pacify lint */
50 # define Static static
55 digit(c) /* is 'c' a digit? */
58 return((boolean)('0' <= c && c <= '9'));
62 letter(c) /* is 'c' a letter? note: '@' classed as letter */
65 return((boolean)(('@' <= c && c <= 'Z') || ('a' <= c && c <= 'z')));
71 highc(c) /* force 'c' into uppercase */
74 return((char)(('a' <= c && c <= 'z') ? (c & ~040) : c));
78 lowc(c) /* force 'c' into lowercase */
81 return((char)(('A' <= c && c <= 'Z') ? (c | 040) : c));
87 lcase(s) /* convert a string into all lowercase */
93 if ('A' <= *p && *p <= 'Z') *p |= 040;
98 upstart(s) /* convert first character of a string to uppercase */
101 if (s) *s = highc(*s);
105 /* remove excess whitespace from a string buffer (in place) */
110 register char c, *p, *p2;
111 boolean was_space = TRUE;
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 == ' ');
118 if (was_space && p2 > bp) p2--;
127 eos(s) /* return the end of a string (pointing at '\0') */
130 while (*s) s++; /* s += strlen(s); */
134 /* strcat(s, {c,'\0'}); */
136 strkitten(s, c) /* append a character to a string (in place) */
148 s_suffix(s) /* return a name converted to possessive */
151 Static char buf[BUFSZ];
154 if(!strcmpi(buf, "it"))
156 else if(*(eos(buf)-1) == 's')
164 xcrypt(str, buf) /* trivial text encryption routine (see makedefs) */
168 register const char *p;
170 register int bitmask;
172 for (bitmask = 1, p = str, q = buf; *p; q++) {
174 if (*q & (32|64)) *q ^= bitmask;
175 if ((bitmask <<= 1) >= 32) bitmask = 1;
184 onlyspace(s) /* is a string entirely whitespace? */
188 if (*s != ' ' && *s != '\t') return FALSE;
195 tabexpand(sbuf) /* expand tabs into proper number of spaces */
199 register char *bp, *s = sbuf;
202 if (!*s) return sbuf;
204 /* warning: no bounds checking performed */
205 for (bp = buf, idx = 0; *s; s++)
207 do *bp++ = ' '; while (++idx % 8);
213 return strcpy(sbuf, buf);
217 visctrl(c) /* make a displayable string from a character */
227 ccc[1] = c | 0100; /* letter */
228 } else if (c == 0177) {
230 ccc[1] = c & ~0100; /* '?' */
232 ccc[0] = c; /* printable character */
241 ordin(n) /* return the ordinal suffix of a number */
242 int n; /* note: should be non-negative */
244 register int dd = n % 10;
246 return (dd == 0 || dd > 3 || (n % 100) / 10 == 1) ? "th" :
247 (dd == 1) ? "st" : (dd == 2) ? "nd" : "rd";
253 sitoa(n) /* make a signed digit string from a number */
258 Sprintf(buf, (n < 0) ? "%d" : "+%d", n);
263 sgn(n) /* return the sign of a number: -1, 0, or 1 */
266 return (n < 0) ? -1 : (n != 0);
272 rounddiv(x, y) /* calculate x/y, rounding as appropriate */
280 panic("division by zero in rounddiv");
282 divsgn = -divsgn; y = -y;
285 divsgn = -divsgn; x = -x;
297 distmin(x0, y0, x1, y1) /* distance between two points, in moves */
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.
306 return (dx < dy) ? dy : dx;
310 dist2(x0, y0, x1, y1) /* square of euclidean distance between pair of pts */
313 register int dx = x0 - x1, dy = y0 - y1;
314 return dx * dx + dy * dy;
318 online2(x0, y0, x1, y1) /* are two points lined up (on a straight line)? */
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.
325 return((boolean)(!dy || !dx || (dy == dx) || (dy + dx == 0))); /* (dy == -dx) */
332 pmatch(patrn, strng) /* match a string against a pattern */
333 const char *patrn, *strng;
337 : Simple pattern matcher: '*' matches 0 or more characters, '?' matches
338 : any single character. Returns TRUE if 'strng' matches 'patrn'.
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 */
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;
364 if (!*s2) return (*s1 != 0); /* s1 >= s2 */
365 else if (!*s1) return -1; /* s1 < s2 */
368 if (t1 != t2) return (t1 > t2) ? 1 : -1;
370 return 0; /* s1 == s2 */
372 #endif /* STRNCMPI */
379 strstri(str, sub) /* case insensitive substring search */
383 register const char *s1, *s2;
385 # define TABSIZ 0x20 /* 0x40 would be case-sensitive */
386 char tstr[TABSIZ], tsub[TABSIZ]; /* nibble count tables */
388 assert( (TABSIZ & ~(TABSIZ-1)) == TABSIZ ); /* must be exact power of 2 */
389 assert( &lowc != 0 ); /* can't be unsafe macro */
392 /* special case: empty substring */
393 if (!*sub) return (char *) str;
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)]++;
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 */
405 /* now actually compare the substring repeatedly to parts of the string */
406 for (i = 0; i <= k; i++) {
409 while (lowc(*s1++) == lowc(*s2++))
410 if (!*s2) return (char *) &str[i]; /* full match */
412 return (char *) 0; /* not found */
416 /* compare two strings for equality, ignoring the presence of specified
417 characters (typically whitespace) and possibly ignoring case */
419 fuzzymatch(s1, s2, ignore_chars, caseblind)
421 const char *ignore_chars;
424 register char c1, c2;
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 */
437 /* match occurs only when the end of both strings has been reached */
438 return (boolean)(!c1 && !c2);
447 * The time is used for:
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"
455 #if defined(AMIGA) && !defined(AZTEC_C) && !defined(__SASC_60) && !defined(_DCC) && !defined(__GNUC__)
456 extern struct tm *FDECL(localtime,(time_t *));
458 static struct tm *NDECL(getlt);
463 /* the types are different enough here that sweeping the different
464 * routine names into one via #defines is even more confusing
466 #ifdef RANDOM /* srandom() from sys/share/random.c */
467 srandom((unsigned int) time((time_t *)0));
469 # if defined(__APPLE__) || defined(BSD) || defined(LINUX) || defined(ULTRIX) || defined(CYGWIN32) /* system srandom() */
470 # if defined(BSD) && !defined(POSIX_TYPES)
474 srandom((int) time((long *)0));
476 srandom((int) time((time_t *)0));
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));
493 #if defined(BSD) && !defined(POSIX_TYPES)
494 (void) time((long *)(&date));
498 #if (defined(ULTRIX) && !(defined(ULTRIX_PROTO) || defined(NHSTDC))) || (defined(BSD) && !defined(POSIX_TYPES))
499 return(localtime((long *)(&date)));
501 return(localtime(&date));
508 return(1900 + getlt()->tm_year);
512 /* This routine is no longer used since in 2000 it will yield "100mmdd". */
517 Static char datestr[10];
523 #if (defined(ULTRIX) && !(defined(ULTRIX_PROTO) || defined(NHSTDC))) || defined(BSD)
524 lt = localtime((long *)(&date));
526 lt = localtime(&date);
529 Sprintf(datestr, "%02d%02d%02d",
530 lt->tm_year, lt->tm_mon + 1, lt->tm_mday);
545 #if (defined(ULTRIX) && !(defined(ULTRIX_PROTO) || defined(NHSTDC))) || (defined(BSD) && !defined(POSIX_TYPES))
546 lt = localtime((long *)(&date));
548 lt = localtime(&date);
551 /* just in case somebody's localtime supplies (year % 100)
552 rather than the expected (year - 1900) */
553 if (lt->tm_year < 70)
554 datenum = (long)lt->tm_year + 2000L;
556 datenum = (long)lt->tm_year + 1900L;
557 /* yyyy --> yyyymm */
558 datenum = datenum * 100L + (long)(lt->tm_mon + 1);
559 /* yyyymm --> yyyymmdd */
560 datenum = datenum * 100L + (long)lt->tm_mday;
565 * moon period = 29.53058 days ~= 30, year = 365.2422 days
566 * days moon phase advances on first day of year compared to preceding year
567 * = 365.2422 - 12*29.53058 ~= 11
568 * years in Metonic cycle (time until same phases fall on the same days of
569 * the month) = 18.6 ~= 19
570 * moon phase on first day of year (epact) ~= (11*(year%19) + 29) % 30
571 * (29 as initial condition)
572 * current phase in days = first day phase + days elapsed in year
573 * 6 moons ~= 177 days
574 * 177 ~= 8 reported phases * 22
575 * + 11/22 for rounding
578 phase_of_the_moon() /* 0-7, with 0: new, 4: full */
580 register struct tm *lt = getlt();
581 register int epact, diy, goldn;
584 goldn = (lt->tm_year % 19) + 1;
585 epact = (11 * goldn + 18) % 30;
586 if ((epact == 25 && goldn > 11) || epact == 24)
589 return( (((((diy + epact) * 6) + 11) % 177) / 22) & 7 );
595 register struct tm *lt = getlt();
597 return((boolean)(lt->tm_wday == 5 /* friday */ && lt->tm_mday == 13));
603 register int hour = getlt()->tm_hour;
605 return(hour < 6 || hour > 21);
611 return(getlt()->tm_hour == 0);