OSDN Git Service

shrink mine
[nethackexpress/trunk.git] / src / hacklib.c
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. */
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 *          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         boolean         fuzzymatch      (const char *,const char *,const char *,boolean)
38         void            setrandom       (void)
39         int             getyear         (void)
40         char *          yymmdd          (time_t)
41         long            yyyymmdd        (time_t)
42         int             phase_of_the_moon       (void)
43         boolean         friday_13th     (void)
44         int             night           (void)
45         int             midnight        (void)
46 =*/
47 #ifdef LINT
48 # define Static         /* pacify lint */
49 #else
50 # define Static static
51 #endif
52
53 #ifdef OVLB
54 boolean
55 digit(c)                /* is 'c' a digit? */
56     char c;
57 {
58     return((boolean)('0' <= c && c <= '9'));
59 }
60
61 boolean
62 letter(c)               /* is 'c' a letter?  note: '@' classed as letter */
63     char c;
64 {
65     return((boolean)(('@' <= c && c <= 'Z') || ('a' <= c && c <= 'z')));
66 }
67 #endif /* OVLB */
68
69 #ifdef OVL1
70 char
71 highc(c)                        /* force 'c' into uppercase */
72     char c;
73 {
74     return((char)(('a' <= c && c <= 'z') ? (c & ~040) : c));
75 }
76
77 char
78 lowc(c)                 /* force 'c' into lowercase */
79     char c;
80 {
81     return((char)(('A' <= c && c <= 'Z') ? (c | 040) : c));
82 }
83 #endif /* OVL1 */
84
85 #ifdef OVLB
86 char *
87 lcase(s)                /* convert a string into all lowercase */
88     char *s;
89 {
90     register char *p;
91
92     for (p = s; *p; p++)
93         if ('A' <= *p && *p <= 'Z') *p |= 040;
94     return s;
95 }
96
97 char *
98 upstart(s)              /* convert first character of a string to uppercase */
99     char *s;
100 {
101     if (s) *s = highc(*s);
102     return s;
103 }
104
105 /* remove excess whitespace from a string buffer (in place) */
106 char *
107 mungspaces(bp)
108 char *bp;
109 {
110     register char c, *p, *p2;
111     boolean was_space = TRUE;
112
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 == ' ');
117     }
118     if (was_space && p2 > bp) p2--;
119     *p2 = '\0';
120     return bp;
121 }
122
123 #endif /* OVLB */
124
125 #ifdef OVL0
126 char *
127 eos(s)                  /* return the end of a string (pointing at '\0') */
128     register char *s;
129 {
130     while (*s) s++;     /* s += strlen(s); */
131     return s;
132 }
133
134 /* strcat(s, {c,'\0'}); */
135 char *
136 strkitten(s, c)         /* append a character to a string (in place) */
137     char *s;
138     char c;
139 {
140     char *p = eos(s);
141
142     *p++ = c;
143     *p = '\0';
144     return s;
145 }
146
147 char *
148 s_suffix(s)             /* return a name converted to possessive */
149     const char *s;
150 {
151     Static char buf[BUFSZ];
152
153     Strcpy(buf, s);
154     if(!strcmpi(buf, "it"))
155         Strcat(buf, "s");
156     else if(*(eos(buf)-1) == 's')
157         Strcat(buf, "'");
158     else
159         Strcat(buf, "'s");
160     return buf;
161 }
162
163 char *
164 xcrypt(str, buf)        /* trivial text encryption routine (see makedefs) */
165 const char *str;
166 char *buf;
167 {
168     register const char *p;
169     register char *q;
170     register int bitmask;
171
172     for (bitmask = 1, p = str, q = buf; *p; q++) {
173         *q = *p++;
174         if (*q & (32|64)) *q ^= bitmask;
175         if ((bitmask <<= 1) >= 32) bitmask = 1;
176     }
177     *q = '\0';
178     return buf;
179 }
180 #endif /* OVL0 */
181
182 #ifdef OVL2
183 boolean
184 onlyspace(s)            /* is a string entirely whitespace? */
185     const char *s;
186 {
187     for (; *s; s++)
188         if (*s != ' ' && *s != '\t') return FALSE;
189     return TRUE;
190 }
191 #endif /* OVL2 */
192
193 #ifdef OVLB
194 char *
195 tabexpand(sbuf)         /* expand tabs into proper number of spaces */
196     char *sbuf;
197 {
198     char buf[BUFSZ];
199     register char *bp, *s = sbuf;
200     register int idx;
201
202     if (!*s) return sbuf;
203
204     /* warning: no bounds checking performed */
205     for (bp = buf, idx = 0; *s; s++)
206         if (*s == '\t') {
207             do *bp++ = ' '; while (++idx % 8);
208         } else {
209             *bp++ = *s;
210             idx++;
211         }
212     *bp = 0;
213     return strcpy(sbuf, buf);
214 }
215
216 char *
217 visctrl(c)              /* make a displayable string from a character */
218     char c;
219 {
220     Static char ccc[3];
221
222     c &= 0177;
223
224     ccc[2] = '\0';
225     if (c < 040) {
226         ccc[0] = '^';
227         ccc[1] = c | 0100;      /* letter */
228     } else if (c == 0177) {
229         ccc[0] = '^';
230         ccc[1] = c & ~0100;     /* '?' */
231     } else {
232         ccc[0] = c;             /* printable character */
233         ccc[1] = '\0';
234     }
235     return ccc;
236 }
237 #endif /* OVLB */
238
239 #ifdef OVL2
240 const char *
241 ordin(n)                /* return the ordinal suffix of a number */
242     int n;                      /* note: should be non-negative */
243 {
244     register int dd = n % 10;
245
246     return (dd == 0 || dd > 3 || (n % 100) / 10 == 1) ? "th" :
247             (dd == 1) ? "st" : (dd == 2) ? "nd" : "rd";
248 }
249 #endif /* OVL2 */
250
251 #ifdef OVL1
252 char *
253 sitoa(n)                /* make a signed digit string from a number */
254     int n;
255 {
256     Static char buf[13];
257
258     Sprintf(buf, (n < 0) ? "%d" : "+%d", n);
259     return buf;
260 }
261
262 int
263 sgn(n)                  /* return the sign of a number: -1, 0, or 1 */
264     int n;
265 {
266     return (n < 0) ? -1 : (n != 0);
267 }
268 #endif /* OVL1 */
269
270 #ifdef OVLB
271 int
272 rounddiv(x, y)          /* calculate x/y, rounding as appropriate */
273     long x;
274     int  y;
275 {
276     int r, m;
277     int divsgn = 1;
278
279     if (y == 0)
280         panic("division by zero in rounddiv");
281     else if (y < 0) {
282         divsgn = -divsgn;  y = -y;
283     }
284     if (x < 0) {
285         divsgn = -divsgn;  x = -x;
286     }
287     r = x / y;
288     m = x % y;
289     if (2*m >= y) r++;
290
291     return divsgn * r;
292 }
293 #endif /* OVLB */
294
295 #ifdef OVL0
296 int
297 distmin(x0, y0, x1, y1) /* distance between two points, in moves */
298     int x0, y0, x1, y1;
299 {
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.
305    */
306     return (dx < dy) ? dy : dx;
307 }
308
309 int
310 dist2(x0, y0, x1, y1)   /* square of euclidean distance between pair of pts */
311     int x0, y0, x1, y1;
312 {
313     register int dx = x0 - x1, dy = y0 - y1;
314     return dx * dx + dy * dy;
315 }
316
317 boolean
318 online2(x0, y0, x1, y1) /* are two points lined up (on a straight line)? */
319     int x0, y0, x1, y1;
320 {
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.
324      */
325     return((boolean)(!dy || !dx || (dy == dx) || (dy + dx == 0)));      /* (dy == -dx) */
326 }
327
328 #endif /* OVL0 */
329 #ifdef OVLB
330
331 boolean
332 pmatch(patrn, strng)    /* match a string against a pattern */
333     const char *patrn, *strng;
334 {
335     char s, p;
336   /*
337    :  Simple pattern matcher:  '*' matches 0 or more characters, '?' matches
338    :  any single character.  Returns TRUE if 'strng' matches 'patrn'.
339    */
340 pmatch_top:
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 */
351 }
352 #endif /* OVLB */
353
354 #ifdef OVL2
355 #ifndef STRNCMPI
356 int
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;
362
363     while (n--) {
364         if (!*s2) return (*s1 != 0);    /* s1 >= s2 */
365         else if (!*s1) return -1;       /* s1  < s2 */
366         t1 = lowc(*s1++);
367         t2 = lowc(*s2++);
368         if (t1 != t2) return (t1 > t2) ? 1 : -1;
369     }
370     return 0;                           /* s1 == s2 */
371 }
372 #endif  /* STRNCMPI */
373 #endif /* OVL2 */
374
375 #ifdef OVLB
376 #ifndef STRSTRI
377
378 char *
379 strstri(str, sub)       /* case insensitive substring search */
380     const char *str;
381     const char *sub;
382 {
383     register const char *s1, *s2;
384     register int i, k;
385 # define TABSIZ 0x20    /* 0x40 would be case-sensitive */
386     char tstr[TABSIZ], tsub[TABSIZ];    /* nibble count tables */
387 # if 0
388     assert( (TABSIZ & ~(TABSIZ-1)) == TABSIZ ); /* must be exact power of 2 */
389     assert( &lowc != 0 );                       /* can't be unsafe macro */
390 # endif
391
392     /* special case: empty substring */
393     if (!*sub)  return (char *) str;
394
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)]++;
399
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 */
404
405     /* now actually compare the substring repeatedly to parts of the string */
406     for (i = 0; i <= k; i++) {
407         s1 = &str[i];
408         s2 = sub;
409         while (lowc(*s1++) == lowc(*s2++))
410             if (!*s2)  return (char *) &str[i];         /* full match */
411     }
412     return (char *) 0;  /* not found */
413 }
414 #endif  /* STRSTRI */
415
416 /* compare two strings for equality, ignoring the presence of specified
417    characters (typically whitespace) and possibly ignoring case */
418 boolean
419 fuzzymatch(s1, s2, ignore_chars, caseblind)
420     const char *s1, *s2;
421     const char *ignore_chars;
422     boolean caseblind;
423 {
424     register char c1, c2;
425
426     do {
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 */
430
431         if (caseblind) {
432             c1 = lowc(c1);
433             c2 = lowc(c2);
434         }
435     } while (c1 == c2);
436
437     /* match occurs only when the end of both strings has been reached */
438     return (boolean)(!c1 && !c2);
439 }
440
441 #endif /* OVLB */
442 #ifdef OVL2
443
444 /*
445  * Time routines
446  *
447  * The time is used for:
448  *      - seed for rand()
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"
453  */
454
455 #if defined(AMIGA) && !defined(AZTEC_C) && !defined(__SASC_60) && !defined(_DCC) && !defined(__GNUC__)
456 extern struct tm *FDECL(localtime,(time_t *));
457 #endif
458 static struct tm *NDECL(getlt);
459
460 void
461 setrandom()
462 {
463         /* the types are different enough here that sweeping the different
464          * routine names into one via #defines is even more confusing
465          */
466 #ifdef RANDOM   /* srandom() from sys/share/random.c */
467         srandom((unsigned int) time((time_t *)0));
468 #else
469 # if defined(__APPLE__) || defined(BSD) || defined(LINUX) || defined(ULTRIX) || defined(CYGWIN32) /* system srandom() */
470 #  if defined(BSD) && !defined(POSIX_TYPES)
471 #   if defined(SUNOS4)
472         (void)
473 #   endif
474                 srandom((int) time((long *)0));
475 #  else
476                 srandom((int) time((time_t *)0));
477 #  endif
478 # else
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));
483 #  endif
484 # endif
485 #endif
486 }
487
488 static struct tm *
489 getlt()
490 {
491         time_t date;
492
493 #if defined(BSD) && !defined(POSIX_TYPES)
494         (void) time((long *)(&date));
495 #else
496         (void) time(&date);
497 #endif
498 #if (defined(ULTRIX) && !(defined(ULTRIX_PROTO) || defined(NHSTDC))) || (defined(BSD) && !defined(POSIX_TYPES))
499         return(localtime((long *)(&date)));
500 #else
501         return(localtime(&date));
502 #endif
503 }
504
505 int
506 getyear()
507 {
508         return(1900 + getlt()->tm_year);
509 }
510
511 #if 0
512 /* This routine is no longer used since in 2000 it will yield "100mmdd". */
513 char *
514 yymmdd(date)
515 time_t date;
516 {
517         Static char datestr[10];
518         struct tm *lt;
519
520         if (date == 0)
521                 lt = getlt();
522         else
523 #if (defined(ULTRIX) && !(defined(ULTRIX_PROTO) || defined(NHSTDC))) || defined(BSD)
524                 lt = localtime((long *)(&date));
525 #else
526                 lt = localtime(&date);
527 #endif
528
529         Sprintf(datestr, "%02d%02d%02d",
530                 lt->tm_year, lt->tm_mon + 1, lt->tm_mday);
531         return(datestr);
532 }
533 #endif
534
535 long
536 yyyymmdd(date)
537 time_t date;
538 {
539         long datenum;
540         struct tm *lt;
541
542         if (date == 0)
543                 lt = getlt();
544         else
545 #if (defined(ULTRIX) && !(defined(ULTRIX_PROTO) || defined(NHSTDC))) || (defined(BSD) && !defined(POSIX_TYPES))
546                 lt = localtime((long *)(&date));
547 #else
548                 lt = localtime(&date);
549 #endif
550
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;
555         else
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;
561         return datenum;
562 }
563
564 /*
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
576  */
577 int
578 phase_of_the_moon()             /* 0-7, with 0: new, 4: full */
579 {
580         register struct tm *lt = getlt();
581         register int epact, diy, goldn;
582
583         diy = lt->tm_yday;
584         goldn = (lt->tm_year % 19) + 1;
585         epact = (11 * goldn + 18) % 30;
586         if ((epact == 25 && goldn > 11) || epact == 24)
587                 epact++;
588
589         return( (((((diy + epact) * 6) + 11) % 177) / 22) & 7 );
590 }
591
592 boolean
593 friday_13th()
594 {
595         register struct tm *lt = getlt();
596
597         return((boolean)(lt->tm_wday == 5 /* friday */ && lt->tm_mday == 13));
598 }
599
600 int
601 night()
602 {
603         register int hour = getlt()->tm_hour;
604
605         return(hour < 6 || hour > 21);
606 }
607
608 int
609 midnight()
610 {
611         return(getlt()->tm_hour == 0);
612 }
613 #endif /* OVL2 */
614
615 /*hacklib.c*/