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 char * reversestring (char *)
38 boolean fuzzymatch (const char *,const char *,const char *,boolean)
41 char * yymmdd (time_t)
42 long yyyymmdd (time_t)
43 int phase_of_the_moon (void)
44 boolean friday_13th (void)
49 # define Static /* pacify lint */
51 # define Static static
56 digit(c
) /* is 'c' a digit? */
59 return((boolean
)('0' <= c
&& c
<= '9'));
63 letter(c
) /* is 'c' a letter? note: '@' classed as letter */
66 return((boolean
)(('@' <= c
&& c
<= 'Z') || ('a' <= c
&& c
<= 'z')));
72 highc(c
) /* force 'c' into uppercase */
75 return((char)(('a' <= c
&& c
<= 'z') ? (c
& ~040) : c
));
79 lowc(c
) /* force 'c' into lowercase */
82 return((char)(('A' <= c
&& c
<= 'Z') ? (c
| 040) : c
));
88 lcase(s
) /* convert a string into all lowercase */
94 if ('A' <= *p
&& *p
<= 'Z') *p
|= 040;
99 upstart(s
) /* convert first character of a string to uppercase */
102 if (s
) *s
= highc(*s
);
106 /* remove excess whitespace from a string buffer (in place) */
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
--;
128 eos(s
) /* return the end of a string (pointing at '\0') */
131 while (*s
) s
++; /* s += strlen(s); */
135 /* strcat(s, {c,'\0'}); */
137 strkitten(s
, c
) /* append a character to a string (in place) */
149 reversestring(char *str
)
155 for (p1
= str
, p2
= str
+ strlen(str
) - 1; p2
> p1
; ++p1
, --p2
)
165 s_suffix(s
) /* return a name converted to possessive */
168 Static
char buf
[BUFSZ
];
171 if(!strcmpi(buf
, "it"))
173 else if(*(eos(buf
)-1) == 's')
181 xcrypt(str
, buf
) /* trivial text encryption routine (see makedefs) */
185 register const char *p
;
187 register int bitmask
;
189 for (bitmask
= 1, p
= str
, q
= buf
; *p
; q
++) {
191 if (*q
& (32|64)) *q
^= bitmask
;
192 if ((bitmask
<<= 1) >= 32) bitmask
= 1;
201 onlyspace(s
) /* is a string entirely whitespace? */
205 if (*s
!= ' ' && *s
!= '\t') return FALSE
;
212 tabexpand(sbuf
) /* expand tabs into proper number of spaces */
216 register char *bp
, *s
= sbuf
;
219 if (!*s
) return sbuf
;
221 /* warning: no bounds checking performed */
222 for (bp
= buf
, idx
= 0; *s
; s
++)
224 do *bp
++ = ' '; while (++idx
% 8);
230 return strcpy(sbuf
, buf
);
234 visctrl(c
) /* make a displayable string from a character */
244 ccc
[1] = c
| 0100; /* letter */
245 } else if (c
== 0177) {
247 ccc
[1] = c
& ~0100; /* '?' */
249 ccc
[0] = c
; /* printable character */
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";
270 sitoa(n
) /* make a signed digit string from a number */
275 sprintf(buf
, (n
< 0) ? "%d" : "+%d", n
);
280 sgn(n
) /* return the sign of a number: -1, 0, or 1 */
283 return (n
< 0) ? -1 : (n
!= 0);
289 rounddiv(x
, y
) /* calculate x/y, rounding as appropriate */
297 panic("division by zero in rounddiv");
299 divsgn
= -divsgn
; y
= -y
;
302 divsgn
= -divsgn
; x
= -x
;
314 distmin(x0
, y0
, x1
, y1
) /* distance between two points, in moves */
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 */
330 register int dx
= x0
- x1
, dy
= y0
- y1
;
331 return dx
* dx
+ dy
* dy
;
335 online2(x0
, y0
, x1
, y1
) /* are two points lined up (on a straight line)? */
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) */
349 pmatch(patrn
, strng
) /* match a string against a pattern */
350 const char *patrn
, *strng
;
354 : Simple pattern matcher: '*' matches 0 or more characters, '?' matches
355 : any single character. Returns TRUE if 'strng' matches 'patrn'.
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 */
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
;
381 if (!*s2
) return (*s1
!= 0); /* s1 >= s2 */
382 else if (!*s1
) return -1; /* s1 < s2 */
385 if (t1
!= t2
) return (t1
> t2
) ? 1 : -1;
387 return 0; /* s1 == s2 */
389 #endif /* STRNCMPI */
396 strstri(str
, sub
) /* case insensitive substring search */
400 register const char *s1
, *s2
;
402 # define TABSIZ 0x20 /* 0x40 would be case-sensitive */
403 char tstr
[TABSIZ
], tsub
[TABSIZ
]; /* nibble count tables */
405 assert( (TABSIZ
& ~(TABSIZ
-1)) == TABSIZ
); /* must be exact power of 2 */
406 assert( &lowc
!= 0 ); /* can't be unsafe macro */
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
++) {
426 while (lowc(*s1
++) == lowc(*s2
++))
427 if (!*s2
) return (char *) &str
[i
]; /* full match */
429 return (char *) 0; /* not found */
433 /* compare two strings for equality, ignoring the presence of specified
434 characters (typically whitespace) and possibly ignoring case */
436 fuzzymatch(s1
, s2
, ignore_chars
, caseblind
)
438 const char *ignore_chars
;
441 register char c1
, c2
;
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 */
454 /* match occurs only when the end of both strings has been reached */
455 return (boolean
)(!c1
&& !c2
);
464 * The time is used for:
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 *);
475 struct tm
*getlt(void);
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));
486 # if defined(BSD) || defined(LINUX) || defined(ULTRIX) || defined(CYGWIN32) /* system srandom() */
487 # if defined(BSD) && !defined(POSIX_TYPES)
491 srandom((int) time((long *)0));
493 srandom((int) time((time_t *)0));
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));
510 #if defined(BSD) && !defined(POSIX_TYPES)
511 (void) time((long *)(&date
));
515 #if (defined(ULTRIX) && !(defined(ULTRIX_PROTO) || defined(NHSTDC))) || (defined(BSD) && !defined(POSIX_TYPES))
516 return(localtime((long *)(&date
)));
518 return(localtime(&date
));
525 return(1900 + getlt()->tm_year
);
528 /* KMH -- Used by gypsies */
532 return (getlt()->tm_mon
);
536 /* This routine is no longer used since in 2000 it will yield "100mmdd". */
541 Static
char datestr
[10];
547 #if (defined(ULTRIX) && !(defined(ULTRIX_PROTO) || defined(NHSTDC))) || defined(BSD)
548 lt
= localtime((long *)(&date
));
550 lt
= localtime(&date
);
553 sprintf(datestr
, "%02d%02d%02d",
554 lt
->tm_year
, lt
->tm_mon
+ 1, lt
->tm_mday
);
569 #if (defined(ULTRIX) && !(defined(ULTRIX_PROTO) || defined(NHSTDC))) || (defined(BSD) && !defined(POSIX_TYPES))
570 lt
= localtime((long *)(&date
));
572 lt
= localtime(&date
);
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;
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
;
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
;
608 goldn
= (lt
->tm_year
% 19) + 1;
609 epact
= (11 * goldn
+ 18) % 30;
610 if ((epact
== 25 && goldn
> 11) || epact
== 24)
613 return( (((((diy
+ epact
) * 6) + 11) % 177) / 22) & 7 );
619 register struct tm
*lt
= getlt();
621 return((boolean
)(lt
->tm_wday
== 5 /* friday */ && lt
->tm_mday
== 13));
627 register struct tm
*lt
= getlt();
629 /* KMH -- Groundhog Day is February 2 */
630 return((boolean
)(lt
->tm_mon
== 1 && lt
->tm_mday
== 2));
636 register int hour
= getlt()->tm_hour
;
638 return(hour
< 6 || hour
> 21);
644 return(getlt()->tm_hour
== 0);