From e322cbb0431879d21934e9d9b727b76b2a4c1b95 Mon Sep 17 00:00:00 2001 From: jwalz Date: Sat, 5 Jan 2002 21:05:49 +0000 Subject: [PATCH] *** empty log message *** --- src/hacklib.c | 601 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 601 insertions(+) create mode 100644 src/hacklib.c diff --git a/src/hacklib.c b/src/hacklib.c new file mode 100644 index 000000000..dc074ec21 --- /dev/null +++ b/src/hacklib.c @@ -0,0 +1,601 @@ +/* SCCS Id: @(#)hacklib.c 3.3 99/04/10 */ +/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ +/* Copyright (c) Robert Patrick Rankin, 1991 */ +/* NetHack may be freely redistributed. See license for details. */ + +/* We could include only config.h, except for the overlay definitions... */ +#include "hack.h" +/*= + Assorted 'small' utility routines. They're virtually independent of +NetHack, except that rounddiv may call panic(). + + return type routine name argument type(s) + boolean digit (char) + boolean letter (char) + char highc (char) + char lowc (char) + char * lcase (char *) + char * upstart (char *) + char * mungspaces (char *) + char * eos (char *) + char * s_suffix (const char *) + char * xcrypt (const char *, char *) + boolean onlyspace (const char *) + char * tabexpand (char *) + char * visctrl (char) + const char * ordin (int) + char * sitoa (int) + int sgn (int) + int rounddiv (long, int) + int distmin (int, int, int, int) + int dist2 (int, int, int, int) + boolean online2 (int, int) + boolean pmatch (const char *, const char *) + int strncmpi (const char *, const char *, int) + char * strstri (const char *, const char *) + boolean fuzzymatch (const char *,const char *,const char *,boolean) + void setrandom (void) + int getyear (void) + char * yymmdd (time_t) + long yyyymmdd (time_t) + int phase_of_the_moon (void) + boolean friday_13th (void) + int night (void) + int midnight (void) +=*/ +#ifdef LINT +# define Static /* pacify lint */ +#else +# define Static static +#endif + +#ifdef OVLB +boolean +digit(c) /* is 'c' a digit? */ + char c; +{ + return((boolean)('0' <= c && c <= '9')); +} + +boolean +letter(c) /* is 'c' a letter? note: '@' classed as letter */ + char c; +{ + return((boolean)(('@' <= c && c <= 'Z') || ('a' <= c && c <= 'z'))); +} +#endif /* OVLB */ + +#ifdef OVL1 +char +highc(c) /* force 'c' into uppercase */ + char c; +{ + return((char)(('a' <= c && c <= 'z') ? (c & ~040) : c)); +} + +char +lowc(c) /* force 'c' into lowercase */ + char c; +{ + return((char)(('A' <= c && c <= 'Z') ? (c | 040) : c)); +} +#endif /* OVL1 */ + +#ifdef OVLB +char * +lcase(s) /* convert a string into all lowercase */ + char *s; +{ + register char *p; + + for (p = s; *p; p++) + if ('A' <= *p && *p <= 'Z') *p |= 040; + return s; +} + +char * +upstart(s) /* convert first character of a string to uppercase */ + char *s; +{ + if (s) *s = highc(*s); + return s; +} + +/* remove excess whitespace from a string buffer (in place) */ +char * +mungspaces(bp) +char *bp; +{ + register char c, *p, *p2; + boolean was_space = TRUE; + + for (p = p2 = bp; (c = *p) != '\0'; p++) { + if (c == '\t') c = ' '; + if (c != ' ' || !was_space) *p2++ = c; + was_space = (c == ' '); + } + if (was_space && p2 > bp) p2--; + *p2 = '\0'; + return bp; +} + +#endif /* OVLB */ + +#ifdef OVL0 +char * +eos(s) /* return the end of a string (pointing at '\0') */ + register char *s; +{ + while (*s) s++; /* s += strlen(s); */ + return s; +} + +char * +s_suffix(s) /* return a name converted to possessive */ + const char *s; +{ + Static char buf[BUFSZ]; + + Strcpy(buf, s); + if(!strcmpi(buf, "it")) + Strcat(buf, "s"); + else if(*(eos(buf)-1) == 's') + Strcat(buf, "'"); + else + Strcat(buf, "'s"); + return buf; +} + +char * +xcrypt(str, buf) /* trivial text encryption routine (see makedefs) */ +const char *str; +char *buf; +{ + register const char *p; + register char *q; + register int bitmask; + + for (bitmask = 1, p = str, q = buf; *p; q++) { + *q = *p++; + if (*q & (32|64)) *q ^= bitmask; + if ((bitmask <<= 1) >= 32) bitmask = 1; + } + *q = '\0'; + return buf; +} +#endif /* OVL0 */ + +#ifdef OVL2 +boolean +onlyspace(s) /* is a string entirely whitespace? */ + const char *s; +{ + for (; *s; s++) + if (*s != ' ' && *s != '\t') return FALSE; + return TRUE; +} +#endif /* OVL2 */ + +#ifdef OVLB +char * +tabexpand(sbuf) /* expand tabs into proper number of spaces */ + char *sbuf; +{ + char buf[BUFSZ]; + register char *bp, *s = sbuf; + register int idx; + + if (!*s) return sbuf; + + /* warning: no bounds checking performed */ + for (bp = buf, idx = 0; *s; s++) + if (*s == '\t') { + do *bp++ = ' '; while (++idx % 8); + } else { + *bp++ = *s; + idx++; + } + *bp = 0; + return strcpy(sbuf, buf); +} + +char * +visctrl(c) /* make a displayable string from a character */ + char c; +{ + Static char ccc[3]; + + c &= 0177; + + ccc[2] = '\0'; + if (c < 040) { + ccc[0] = '^'; + ccc[1] = c | 0100; /* letter */ + } else if (c == 0177) { + ccc[0] = '^'; + ccc[1] = c & ~0100; /* '?' */ + } else { + ccc[0] = c; /* printable character */ + ccc[1] = '\0'; + } + return ccc; +} +#endif /* OVLB */ + +#ifdef OVL2 +const char * +ordin(n) /* return the ordinal suffix of a number */ + int n; /* note: should be non-negative */ +{ + register int dd = n % 10; + + return (dd == 0 || dd > 3 || (n % 100) / 10 == 1) ? "th" : + (dd == 1) ? "st" : (dd == 2) ? "nd" : "rd"; +} +#endif /* OVL2 */ + +#ifdef OVL1 +char * +sitoa(n) /* make a signed digit string from a number */ + int n; +{ + Static char buf[13]; + + Sprintf(buf, (n < 0) ? "%d" : "+%d", n); + return buf; +} + +int +sgn(n) /* return the sign of a number: -1, 0, or 1 */ + int n; +{ + return (n < 0) ? -1 : (n != 0); +} +#endif /* OVL1 */ + +#ifdef OVLB +int +rounddiv(x, y) /* calculate x/y, rounding as appropriate */ + long x; + int y; +{ + int r, m; + int divsgn = 1; + + if (y == 0) + panic("division by zero in rounddiv"); + else if (y < 0) { + divsgn = -divsgn; y = -y; + } + if (x < 0) { + divsgn = -divsgn; x = -x; + } + r = x / y; + m = x % y; + if (2*m >= y) r++; + + return divsgn * r; +} +#endif /* OVLB */ + +#ifdef OVL0 +int +distmin(x0, y0, x1, y1) /* distance between two points, in moves */ + int x0, y0, x1, y1; +{ + register int dx = x0 - x1, dy = y0 - y1; + if (dx < 0) dx = -dx; + if (dy < 0) dy = -dy; + /* The minimum number of moves to get from (x0,y0) to (x1,y1) is the + : larger of the [absolute value of the] two deltas. + */ + return (dx < dy) ? dy : dx; +} + +int +dist2(x0, y0, x1, y1) /* square of euclidean distance between pair of pts */ + int x0, y0, x1, y1; +{ + register int dx = x0 - x1, dy = y0 - y1; + return dx * dx + dy * dy; +} + +boolean +online2(x0, y0, x1, y1) /* are two points lined up (on a straight line)? */ + int x0, y0, x1, y1; +{ + int dx = x0 - x1, dy = y0 - y1; + /* If either delta is zero then they're on an orthogonal line, + * else if the deltas are equal (signs ignored) they're on a diagonal. + */ + return((boolean)(!dy || !dx || (dy == dx) || (dy + dx == 0))); /* (dy == -dx) */ +} + +#endif /* OVL0 */ +#ifdef OVLB + +boolean +pmatch(patrn, strng) /* match a string against a pattern */ + const char *patrn, *strng; +{ + char s, p; + /* + : Simple pattern matcher: '*' matches 0 or more characters, '?' matches + : any single character. Returns TRUE if 'strng' matches 'patrn'. + */ +pmatch_top: + s = *strng++; p = *patrn++; /* get next chars and pre-advance */ + if (!p) /* end of pattern */ + return((boolean)(s == '\0')); /* matches iff end of string too */ + else if (p == '*') /* wildcard reached */ + return((boolean)((!*patrn || pmatch(patrn, strng-1)) ? TRUE : + s ? pmatch(patrn-1, strng) : FALSE)); + else if (p != s && (p != '?' || !s)) /* check single character */ + return FALSE; /* doesn't match */ + else /* return pmatch(patrn, strng); */ + goto pmatch_top; /* optimize tail recursion */ +} +#endif /* OVLB */ + +#ifdef OVL2 +#ifndef STRNCMPI +int +strncmpi(s1, s2, n) /* case insensitive counted string comparison */ + register const char *s1, *s2; + register int n; /*(should probably be size_t, which is usually unsigned)*/ +{ /*{ aka strncasecmp }*/ + register char t1, t2; + + while (n--) { + if (!*s2) return (*s1 != 0); /* s1 >= s2 */ + else if (!*s1) return -1; /* s1 < s2 */ + t1 = lowc(*s1++); + t2 = lowc(*s2++); + if (t1 != t2) return (t1 > t2) ? 1 : -1; + } + return 0; /* s1 == s2 */ +} +#endif /* STRNCMPI */ +#endif /* OVL2 */ + +#ifdef OVLB +#ifndef STRSTRI + +char * +strstri(str, sub) /* case insensitive substring search */ + const char *str; + const char *sub; +{ + register const char *s1, *s2; + register int i, k; +# define TABSIZ 0x20 /* 0x40 would be case-sensitive */ + char tstr[TABSIZ], tsub[TABSIZ]; /* nibble count tables */ +# if 0 + assert( (TABSIZ & ~(TABSIZ-1)) == TABSIZ ); /* must be exact power of 2 */ + assert( &lowc != 0 ); /* can't be unsafe macro */ +# endif + + /* special case: empty substring */ + if (!*sub) return (char *) str; + + /* do some useful work while determining relative lengths */ + for (i = 0; i < TABSIZ; i++) tstr[i] = tsub[i] = 0; /* init */ + for (k = 0, s1 = str; *s1; k++) tstr[*s1++ & (TABSIZ-1)]++; + for ( s2 = sub; *s2; --k) tsub[*s2++ & (TABSIZ-1)]++; + + /* evaluate the info we've collected */ + if (k < 0) return (char *) 0; /* sub longer than str, so can't match */ + for (i = 0; i < TABSIZ; i++) /* does sub have more 'x's than str? */ + if (tsub[i] > tstr[i]) return (char *) 0; /* match not possible */ + + /* now actually compare the substring repeatedly to parts of the string */ + for (i = 0; i <= k; i++) { + s1 = &str[i]; + s2 = sub; + while (lowc(*s1++) == lowc(*s2++)) + if (!*s2) return (char *) &str[i]; /* full match */ + } + return (char *) 0; /* not found */ +} +#endif /* STRSTRI */ + +/* compare two strings for equality, ignoring the presence of specified + characters (typically whitespace) and possibly ignoring case */ +boolean +fuzzymatch(s1, s2, ignore_chars, caseblind) + const char *s1, *s2; + const char *ignore_chars; + boolean caseblind; +{ + register char c1, c2; + + do { + while ((c1 = *s1++) != '\0' && index(ignore_chars, c1) != 0) continue; + while ((c2 = *s2++) != '\0' && index(ignore_chars, c2) != 0) continue; + if (!c1 || !c2) break; /* stop when end of either string is reached */ + + if (caseblind) { + c1 = lowc(c1); + c2 = lowc(c2); + } + } while (c1 == c2); + + /* match occurs only when the end of both strings has been reached */ + return (boolean)(!c1 && !c2); +} + +#endif /* OVLB */ +#ifdef OVL2 + +/* + * Time routines + * + * The time is used for: + * - seed for rand() + * - year on tombstone and yyyymmdd in record file + * - phase of the moon (various monsters react to NEW_MOON or FULL_MOON) + * - night and midnight (the undead are dangerous at midnight) + * - determination of what files are "very old" + */ + +#if defined(AMIGA) && !defined(AZTEC_C) && !defined(__SASC_60) && !defined(_DCC) && !defined(__GNUC__) +extern struct tm *FDECL(localtime,(time_t *)); +#endif +static struct tm *NDECL(getlt); + +void +setrandom() +{ + /* the types are different enough here that sweeping the different + * routine names into one via #defines is even more confusing + */ +#ifdef RANDOM /* srandom() from sys/share/random.c */ + srandom((unsigned int) time((time_t *)0)); +#else +# if defined(BSD) || defined(ULTRIX) || defined(CYGWIN32) /* system srandom() */ +# ifdef BSD +# if defined(SUNOS4) + (void) +# endif + srandom((int) time((long *)0)); +# else + srandom((int) time((time_t *)0)); +# endif +# else +# ifdef UNIX /* system srand48() */ + srand48((long) time((time_t *)0)); +# else /* poor quality system routine */ + srand((int) time((time_t *)0)); +# endif +# endif +#endif +} + +static struct tm * +getlt() +{ + time_t date; + +#ifdef BSD + (void) time((long *)(&date)); +#else + (void) time(&date); +#endif +#if (defined(ULTRIX) && !(defined(ULTRIX_PROTO) || defined(NHSTDC))) || defined(BSD) + return(localtime((long *)(&date))); +#else + return(localtime(&date)); +#endif +} + +int +getyear() +{ + return(1900 + getlt()->tm_year); +} + +#if 0 +/* This routine is no longer used since in 2000 it will yield "100mmdd". */ +char * +yymmdd(date) +time_t date; +{ + Static char datestr[10]; + struct tm *lt; + + if (date == 0) + lt = getlt(); + else +#if (defined(ULTRIX) && !(defined(ULTRIX_PROTO) || defined(NHSTDC))) || defined(BSD) + lt = localtime((long *)(&date)); +#else + lt = localtime(&date); +#endif + + Sprintf(datestr, "%02d%02d%02d", + lt->tm_year, lt->tm_mon + 1, lt->tm_mday); + return(datestr); +} +#endif + +long +yyyymmdd(date) +time_t date; +{ + long datenum; + struct tm *lt; + + if (date == 0) + lt = getlt(); + else +#if (defined(ULTRIX) && !(defined(ULTRIX_PROTO) || defined(NHSTDC))) || defined(BSD) + lt = localtime((long *)(&date)); +#else + lt = localtime(&date); +#endif + + /* just in case somebody's localtime supplies (year % 100) + rather than the expected (year - 1900) */ + if (lt->tm_year < 70) + datenum = (long)lt->tm_year + 2000L; + else + datenum = (long)lt->tm_year + 1900L; + /* yyyy --> yyyymm */ + datenum = datenum * 100L + (long)(lt->tm_mon + 1); + /* yyyymm --> yyyymmdd */ + datenum = datenum * 100L + (long)lt->tm_mday; + return datenum; +} + +/* + * moon period = 29.53058 days ~= 30, year = 365.2422 days + * days moon phase advances on first day of year compared to preceding year + * = 365.2422 - 12*29.53058 ~= 11 + * years in Metonic cycle (time until same phases fall on the same days of + * the month) = 18.6 ~= 19 + * moon phase on first day of year (epact) ~= (11*(year%19) + 29) % 30 + * (29 as initial condition) + * current phase in days = first day phase + days elapsed in year + * 6 moons ~= 177 days + * 177 ~= 8 reported phases * 22 + * + 11/22 for rounding + */ +int +phase_of_the_moon() /* 0-7, with 0: new, 4: full */ +{ + register struct tm *lt = getlt(); + register int epact, diy, goldn; + + diy = lt->tm_yday; + goldn = (lt->tm_year % 19) + 1; + epact = (11 * goldn + 18) % 30; + if ((epact == 25 && goldn > 11) || epact == 24) + epact++; + + return( (((((diy + epact) * 6) + 11) % 177) / 22) & 7 ); +} + +boolean +friday_13th() +{ + register struct tm *lt = getlt(); + + return((boolean)(lt->tm_wday == 5 /* friday */ && lt->tm_mday == 13)); +} + +int +night() +{ + register int hour = getlt()->tm_hour; + + return(hour < 6 || hour > 21); +} + +int +midnight() +{ + return(getlt()->tm_hour == 0); +} +#endif /* OVL2 */ + +/*hacklib.c*/