1 /* NetHack 3.6 hacklib.c $NHDT-Date: 1518922474 2018/02/18 02:54:34 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.54 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /*-Copyright (c) Michael Allison, 2007. */
4 /* Copyright (c) Robert Patrick Rankin, 1991 */
5 /* NetHack may be freely redistributed. See license for details. */
7 /* JNetHack Copyright */
8 /* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000 */
9 /* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2019 */
10 /* JNetHack may be freely redistributed. See license for details. */
12 #include "hack.h" /* for config.h+extern.h */
14 Assorted 'small' utility routines. They're virtually independent of
15 NetHack, except that rounddiv may call panic(). setrandom calls one
16 of srandom(), srand48(), or srand() depending upon configuration.
18 return type routine name argument type(s)
25 char * upstart (char *)
26 char * mungspaces (char *)
27 char * trimspaces (char *)
28 char * strip_newline (char *)
29 char * stripchars (char *, const char *, const char *)
31 boolean str_end_is (const char *, const char *)
32 char * strkitten (char *,char)
33 void copynchars (char *,const char *,int)
34 char chrcasecpy (int,int)
35 char * strcasecpy (char *,const char *)
36 char * s_suffix (const char *)
37 char * ing_suffix (const char *)
38 char * xcrypt (const char *, char *)
39 boolean onlyspace (const char *)
40 char * tabexpand (char *)
42 char * strsubst (char *, const char *, const char *)
43 int strNsubst (char *,const char *,const char *,int)
44 const char * ordin (int)
47 int rounddiv (long, int)
48 int distmin (int, int, int, int)
49 int dist2 (int, int, int, int)
50 boolean online2 (int, int)
51 boolean pmatch (const char *, const char *)
52 boolean pmatchi (const char *, const char *)
53 boolean pmatchz (const char *, const char *)
54 int strncmpi (const char *, const char *, int)
55 char * strstri (const char *, const char *)
56 boolean fuzzymatch (const char *, const char *,
57 const char *, boolean)
61 char * yymmdd (time_t)
62 long yyyymmdd (time_t)
64 char * yyyymmddhhmmss (time_t)
65 time_t time_from_yyyymmddhhmmss (char *)
66 int phase_of_the_moon (void)
67 boolean friday_13th (void)
70 void strbuf_init (strbuf *, const char *)
71 void strbuf_append (strbuf *, const char *)
72 void strbuf_reserve (strbuf *, int)
73 void strbuf_empty (strbuf *)
74 void strbuf_nl_to_crlf (strbuf_t *)
77 #define Static /* pacify lint */
82 static boolean FDECL(pmatch_internal, (const char *, const char *,
83 BOOLEAN_P, const char *));
90 return (boolean) ('0' <= c && c <= '9');
93 /* is 'c' a letter? note: '@' classed as letter */
98 return (boolean) ('@' <= c && c <= 'Z') || ('a' <= c && c <= 'z');
101 /* force 'c' into uppercase */
106 return (char) (('a' <= c && c <= 'z') ? (c & ~040) : c);
109 /* force 'c' into lowercase */
114 return (char) (('A' <= c && c <= 'Z') ? (c | 040) : c);
117 /* convert a string into all lowercase */
125 #if 1 /*JP*//*
\8a¿
\8e\9a\82Í
\8f¬
\95¶
\8e\9a\89»
\82µ
\82È
\82¢*/
126 if (is_kanji(*(unsigned char *)p)) p++; else
128 if ('A' <= *p && *p <= 'Z')
133 /* convert a string into all uppercase */
141 #if 1 /*JP*//*
\8a¿
\8e\9a\82Í
\91å
\95¶
\8e\9a\89»
\82µ
\82È
\82¢*/
142 if (is_kanji(*(unsigned char *)p)) p++; else
144 if ('a' <= *p && *p <= 'z')
149 /* convert first character of a string to uppercase */
159 /* remove excess whitespace from a string buffer (in place) */
164 register char c, *p, *p2;
165 boolean was_space = TRUE;
167 for (p = p2 = bp; (c = *p) != '\0'; p++) {
169 break; /* treat newline the same as end-of-string */
172 if (c != ' ' || !was_space)
174 was_space = (c == ' ');
176 if (was_space && p2 > bp)
182 /* remove leading and trailing whitespace, in place */
189 while (*txt == ' ' || *txt == '\t')
192 while (--end >= txt && (*end == ' ' || *end == '\t'))
198 /* remove \n from end of line; remove \r too if one is there */
203 char *p = rindex(str, '\n');
206 if (p > str && *(p - 1) == '\r')
213 /* return the end of a string (pointing at '\0') */
219 s++; /* s += strlen(s); */
223 /* determine whether 'str' ends in 'chkstr' */
225 str_end_is(str, chkstr)
226 const char *str, *chkstr;
228 int clen = (int) strlen(chkstr);
230 if ((int) strlen(str) >= clen)
231 return (boolean) (!strncmp(eos((char *) str) - clen, chkstr, clen));
235 /* append a character to a string (in place): strcat(s, {c,'\0'}); */
248 /* truncating string copy */
250 copynchars(dst, src, n)
255 /* copies at most n characters, stopping sooner if terminator reached;
256 treats newline as input terminator; unlike strncpy, always supplies
257 '\0' terminator so dst must be able to hold at least n+1 characters */
258 while (n > 0 && *src != '\0' && *src != '\n') {
265 /* convert char nc into oc's case; mostly used by strcasecpy */
270 #if 0 /* this will be necessary if we switch to <ctype.h> */
271 oc = (int) (unsigned char) oc;
272 nc = (int) (unsigned char) nc;
274 if ('a' <= oc && oc <= 'z') {
275 /* old char is lower case; if new char is upper case, downcase it */
276 if ('A' <= nc && nc <= 'Z')
277 nc += 'a' - 'A'; /* lowc(nc) */
278 } else if ('A' <= oc && oc <= 'Z') {
279 /* old char is upper case; if new char is lower case, upcase it */
280 if ('a' <= nc && nc <= 'z')
281 nc += 'A' - 'a'; /* highc(nc) */
286 /* overwrite string, preserving old chars' case;
287 for case-insensitive editions of makeplural() and makesingular();
288 src might be shorter, same length, or longer than dst */
295 int ic, oc, dst_exhausted = 0;
297 /* while dst has characters, replace each one with corresponding
298 character from src, converting case in the process if they differ;
299 once dst runs out, propagate the case of its last character to any
300 remaining src; if dst starts empty, it must be a pointer to the
301 tail of some other string because we examine the char at dst[-1] */
302 while ((ic = (int) *src++) != '\0') {
303 if (!dst_exhausted && !*dst)
305 oc = (int) *(dst - dst_exhausted);
306 *dst++ = chrcasecpy(oc, ic);
312 /* return a name converted to possessive */
317 Static char buf[BUFSZ];
321 if (!strcmpi(buf, "it")) /* it -> its */
323 else if (!strcmpi(buf, "you")) /* you -> your */
325 else if (*(eos(buf) - 1) == 's') /* Xs -> Xs' */
329 #else /* X -> X
\82Ì */
335 /* construct a gerund (a verb formed by appending "ing" to a noun) */
340 static const char vowel[] = "aeiouwy";
341 static char buf[BUFSZ];
347 onoff[0] = *p = *(p + 1) = '\0';
348 if ((p >= &buf[3] && !strcmpi(p - 3, " on"))
349 || (p >= &buf[4] && !strcmpi(p - 4, " off"))
350 || (p >= &buf[5] && !strcmpi(p - 5, " with"))) {
351 p = rindex(buf, ' ');
355 if (p >= &buf[3] && !index(vowel, *(p - 1))
356 && index(vowel, *(p - 2)) && !index(vowel, *(p - 3))) {
357 /* tip -> tipp + ing */
360 } else if (p >= &buf[2] && !strcmpi(p - 2, "ie")) { /* vie -> vy + ing */
363 } else if (p >= &buf[1] && *(p - 1) == 'e') /* grease -> greas + ing */
371 /* trivial text encryption routine (see makedefs) */
377 register const char *p;
379 register int bitmask;
381 for (bitmask = 1, p = str, q = buf; *p; q++) {
385 if ((bitmask <<= 1) >= 32)
392 /* is a string entirely whitespace? */
398 if (*s != ' ' && *s != '\t')
403 /* expand tabs into proper number of spaces */
409 register char *bp, *s = sbuf;
414 /* warning: no bounds checking performed */
415 for (bp = buf, idx = 0; *s; s++)
425 return strcpy(sbuf, buf);
428 #define VISCTRL_NBUF 5
429 /* make a displayable string from a character */
434 Static char visctrl_bufs[VISCTRL_NBUF][5];
437 char *ccc = visctrl_bufs[nbuf];
438 nbuf = (nbuf + 1) % VISCTRL_NBUF;
440 if ((uchar) c & 0200) {
447 ccc[i++] = c | 0100; /* letter */
448 } else if (c == 0177) {
450 ccc[i++] = c & ~0100; /* '?' */
452 ccc[i++] = c; /* printable character */
458 /* strip all the chars in stuff_to_strip from orig */
459 /* caller is responsible for ensuring that bp is a
460 valid pointer to a BUFSZ buffer */
462 stripchars(bp, stuff_to_strip, orig)
464 const char *stuff_to_strip, *orig;
470 while (*orig && i < (BUFSZ - 1)) {
471 if (!index(stuff_to_strip, *orig)) {
479 impossible("no output buf in stripchars");
483 /* substitute a word or phrase in a string (in place) */
484 /* caller is responsible for ensuring that bp points to big enough buffer */
486 strsubst(bp, orig, replacement)
488 const char *orig, *replacement;
490 char *found, buf[BUFSZ];
493 /* [this could be replaced by strNsubst(bp, orig, replacement, 1)] */
494 found = strstr(bp, orig);
496 Strcpy(buf, found + strlen(orig));
497 Strcpy(found, replacement);
504 /* substitute the Nth occurrence of a substring within a string (in place);
505 if N is 0, substitute all occurrences; returns the number of subsitutions;
506 maximum output length is BUFSZ (BUFSZ-1 chars + terminating '\0') */
508 strNsubst(inoutbuf, orig, replacement, n)
509 char *inoutbuf; /* current string, and result buffer */
510 const char *orig, /* old substring; if "" then insert in front of Nth char */
511 *replacement; /* new substring; if "" then delete old substring */
512 int n; /* which occurrence to replace; 0 => all */
514 char *bp, *op, workbuf[BUFSZ];
516 unsigned len = (unsigned) strlen(orig);
517 int ocount = 0, /* number of times 'orig' has been matched */
518 rcount = 0; /* number of subsitutions made */
520 for (bp = inoutbuf, op = workbuf; *bp && op < &workbuf[BUFSZ - 1]; ) {
521 if ((!len || !strncmp(bp, orig, len)) && (++ocount == n || n == 0)) {
522 /* Nth match found */
523 for (rp = replacement; *rp && op < &workbuf[BUFSZ - 1]; )
527 bp += len; /* skip 'orig' */
531 /* no match (or len==0) so retain current character */
534 if (!len && n == ocount + 1) {
535 /* special case: orig=="" (!len) and n==strlen(inoutbuf)+1,
536 insert in front of terminator (in other words, append);
537 [when orig=="", ocount will have been incremented once for
539 for (rp = replacement; *rp && op < &workbuf[BUFSZ - 1]; )
545 Strcpy(inoutbuf, workbuf);
550 /* return the ordinal suffix of a number */
553 int n; /* note: should be non-negative */
555 register int dd = n % 10;
557 return (dd == 0 || dd > 3 || (n % 100) / 10 == 1) ? "th"
558 : (dd == 1) ? "st" : (dd == 2) ? "nd" : "rd";
561 /* make a signed digit string from a number */
568 Sprintf(buf, (n < 0) ? "%d" : "+%d", n);
572 /* return the sign of a number: -1, 0, or 1 */
577 return (n < 0) ? -1 : (n != 0);
580 /* calculate x/y, rounding as appropriate */
590 panic("division by zero in rounddiv");
607 /* distance between two points, in moves */
609 distmin(x0, y0, x1, y1)
612 register int dx = x0 - x1, dy = y0 - y1;
618 /* The minimum number of moves to get from (x0,y0) to (x1,y1) is the
619 * larger of the [absolute value of the] two deltas.
621 return (dx < dy) ? dy : dx;
624 /* square of euclidean distance between pair of pts */
626 dist2(x0, y0, x1, y1)
629 register int dx = x0 - x1, dy = y0 - y1;
631 return dx * dx + dy * dy;
634 /* integer square root function without using floating point */
642 * This could be replaced by a faster algorithm, but has not been because:
643 * + the simple algorithm is easy to read;
644 * + this algorithm does not require 64-bit support;
645 * + in current usage, the values passed to isqrt() are not really that
646 * large, so the performance difference is negligible;
647 * + isqrt() is used in only few places, which are not bottle-necks.
657 /* are two points lined up (on a straight line)? */
659 online2(x0, y0, x1, y1)
662 int dx = x0 - x1, dy = y0 - y1;
663 /* If either delta is zero then they're on an orthogonal line,
664 * else if the deltas are equal (signs ignored) they're on a diagonal.
666 return (boolean) (!dy || !dx || dy == dx || dy == -dx);
669 /* guts of pmatch(), pmatchi(), and pmatchz();
670 match a string against a pattern */
672 pmatch_internal(patrn, strng, ci, sk)
673 const char *patrn, *strng;
674 boolean ci; /* True => case-insensitive, False => case-sensitive */
675 const char *sk; /* set of characters to skip */
679 * Simple pattern matcher: '*' matches 0 or more characters, '?' matches
680 * any single character. Returns TRUE if 'strng' matches 'patrn'.
685 p = *patrn++; /* get next chars and pre-advance */
687 /* fuzzy match variant of pmatch; particular characters are ignored */
690 } while (index(sk, s));
693 } while (index(sk, p));
695 if (!p) /* end of pattern */
696 return (boolean) (s == '\0'); /* matches iff end of string too */
697 else if (p == '*') /* wildcard reached */
698 return (boolean) ((!*patrn
699 || pmatch_internal(patrn, strng - 1, ci, sk))
701 : s ? pmatch_internal(patrn - 1, strng, ci, sk)
703 else if ((ci ? lowc(p) != lowc(s) : p != s) /* check single character */
704 && (p != '?' || !s)) /* & single-char wildcard */
705 return FALSE; /* doesn't match */
706 else /* return pmatch_internal(patrn, strng, ci, sk); */
707 goto pmatch_top; /* optimize tail recursion */
710 /* case-sensitive wildcard match */
713 const char *patrn, *strng;
715 return pmatch_internal(patrn, strng, FALSE, (const char *) 0);
718 /* case-insensitive wildcard match */
720 pmatchi(patrn, strng)
721 const char *patrn, *strng;
723 return pmatch_internal(patrn, strng, TRUE, (const char *) 0);
726 /* case-insensitive wildcard fuzzymatch */
728 pmatchz(patrn, strng)
729 const char *patrn, *strng;
731 /* ignore spaces, tabs (just in case), dashes, and underscores */
732 static const char fuzzychars[] = " \t-_";
734 return pmatch_internal(patrn, strng, TRUE, fuzzychars);
738 /* case insensitive counted string comparison */
740 strncmpi(s1, s2, n) /*{ aka strncasecmp }*/
741 register const char *s1, *s2;
742 register int n; /*(should probably be size_t, which is unsigned)*/
744 register char t1, t2;
748 return (*s1 != 0); /* s1 >= s2 */
750 return -1; /* s1 < s2 */
754 return (t1 > t2) ? 1 : -1;
756 return 0; /* s1 == s2 */
758 #endif /* STRNCMPI */
761 /* case insensitive substring search */
767 register const char *s1, *s2;
769 #define TABSIZ 0x20 /* 0x40 would be case-sensitive */
770 char tstr[TABSIZ], tsub[TABSIZ]; /* nibble count tables */
772 assert( (TABSIZ & ~(TABSIZ-1)) == TABSIZ ); /* must be exact power of 2 */
773 assert( &lowc != 0 ); /* can't be unsafe macro */
776 /* special case: empty substring */
780 /* do some useful work while determining relative lengths */
781 for (i = 0; i < TABSIZ; i++)
782 tstr[i] = tsub[i] = 0; /* init */
783 for (k = 0, s1 = str; *s1; k++)
784 tstr[*s1++ & (TABSIZ - 1)]++;
785 for (s2 = sub; *s2; --k)
786 tsub[*s2++ & (TABSIZ - 1)]++;
788 /* evaluate the info we've collected */
790 return (char *) 0; /* sub longer than str, so can't match */
791 for (i = 0; i < TABSIZ; i++) /* does sub have more 'x's than str? */
792 if (tsub[i] > tstr[i])
793 return (char *) 0; /* match not possible */
795 /* now actually compare the substring repeatedly to parts of the string */
796 for (i = 0; i <= k; i++) {
799 while (lowc(*s1++) == lowc(*s2++))
801 return (char *) &str[i]; /* full match */
803 return (char *) 0; /* not found */
807 /* compare two strings for equality, ignoring the presence of specified
808 characters (typically whitespace) and possibly ignoring case */
810 fuzzymatch(s1, s2, ignore_chars, caseblind)
812 const char *ignore_chars;
815 register char c1, c2;
818 while ((c1 = *s1++) != '\0' && index(ignore_chars, c1) != 0)
820 while ((c2 = *s2++) != '\0' && index(ignore_chars, c2) != 0)
823 break; /* stop when end of either string is reached */
831 /* match occurs only when the end of both strings has been reached */
832 return (boolean) (!c1 && !c2);
838 * The time is used for:
840 * - year on tombstone and yyyymmdd in record file
841 * - phase of the moon (various monsters react to NEW_MOON or FULL_MOON)
842 * - night and midnight (the undead are dangerous at midnight)
843 * - determination of what files are "very old"
846 /* TIME_type: type of the argument to time(); we actually use &(time_t) */
847 #if defined(BSD) && !defined(POSIX_TYPES)
848 #define TIME_type long *
850 #define TIME_type time_t *
852 /* LOCALTIME_type: type of the argument to localtime() */
853 #if (defined(ULTRIX) && !(defined(ULTRIX_PROTO) || defined(NHSTDC))) \
854 || (defined(BSD) && !defined(POSIX_TYPES))
855 #define LOCALTIME_type long *
857 #define LOCALTIME_type time_t *
860 #if defined(AMIGA) && !defined(AZTEC_C) && !defined(__SASC_60) \
861 && !defined(_DCC) && !defined(__GNUC__)
862 extern struct tm *FDECL(localtime, (time_t *));
864 STATIC_DCL struct tm *NDECL(getlt);
869 unsigned long seed = (unsigned long) getnow(); /* time((TIME_type) 0) */
871 #if defined(UNIX) || defined(VMS)
873 unsigned long pid = (unsigned long) getpid();
875 /* Quick dirty band-aid to prevent PRNG prediction */
884 /* the types are different enough here that sweeping the different
885 * routine names into one via #defines is even more confusing
887 #ifdef RANDOM /* srandom() from sys/share/random.c */
888 srandom((unsigned int) seed);
890 #if defined(__APPLE__) || defined(BSD) || defined(LINUX) || defined(ULTRIX) \
891 || defined(CYGWIN32) /* system srandom() */
892 #if defined(BSD) && !defined(POSIX_TYPES) && defined(SUNOS4)
897 #ifdef UNIX /* system srand48() */
898 srand48((long) seed);
899 #else /* poor quality system routine */
911 (void) time((TIME_type) &datetime);
915 STATIC_OVL struct tm *
918 time_t date = getnow();
920 return localtime((LOCALTIME_type) &date);
926 return (1900 + getlt()->tm_year);
930 /* This routine is no longer used since in 20YY it yields "1YYmmdd". */
935 Static char datestr[10];
941 lt = localtime((LOCALTIME_type) &date);
943 Sprintf(datestr, "%02d%02d%02d",
944 lt->tm_year, lt->tm_mon + 1, lt->tm_mday);
959 lt = localtime((LOCALTIME_type) &date);
961 /* just in case somebody's localtime supplies (year % 100)
962 rather than the expected (year - 1900) */
963 if (lt->tm_year < 70)
964 datenum = (long) lt->tm_year + 2000L;
966 datenum = (long) lt->tm_year + 1900L;
967 /* yyyy --> yyyymm */
968 datenum = datenum * 100L + (long) (lt->tm_mon + 1);
969 /* yyyymm --> yyyymmdd */
970 datenum = datenum * 100L + (long) lt->tm_mday;
984 lt = localtime((LOCALTIME_type) &date);
986 timenum = lt->tm_hour * 10000L + lt->tm_min * 100L + lt->tm_sec;
995 static char datestr[15];
1001 #if (defined(ULTRIX) && !(defined(ULTRIX_PROTO) || defined(NHSTDC))) \
1003 lt = localtime((long *) (&date));
1005 lt = localtime(&date);
1007 /* just in case somebody's localtime supplies (year % 100)
1008 rather than the expected (year - 1900) */
1009 if (lt->tm_year < 70)
1010 datenum = (long) lt->tm_year + 2000L;
1012 datenum = (long) lt->tm_year + 1900L;
1013 Sprintf(datestr, "%04ld%02d%02d%02d%02d%02d", datenum, lt->tm_mon + 1,
1014 lt->tm_mday, lt->tm_hour, lt->tm_min, lt->tm_sec);
1015 debugpline1("yyyymmddhhmmss() produced date string %s", datestr);
1020 time_from_yyyymmddhhmmss(buf)
1024 time_t timeresult = (time_t) 0;
1026 char *g, *p, y[5], mo[3], md[3], h[3], mi[3], s[3];
1028 if (buf && strlen(buf) == 14) {
1031 for (k = 0; k < 4; ++k)
1035 for (k = 0; k < 2; ++k)
1039 for (k = 0; k < 2; ++k)
1043 for (k = 0; k < 2; ++k)
1046 p = mi; /* minutes */
1047 for (k = 0; k < 2; ++k)
1050 p = s; /* seconds */
1051 for (k = 0; k < 2; ++k)
1057 t.tm_year = atoi(y) - 1900;
1058 t.tm_mon = atoi(mo) - 1;
1059 t.tm_mday = atoi(md);
1060 t.tm_hour = atoi(h);
1061 t.tm_min = atoi(mi);
1063 timeresult = mktime(&t);
1065 if ((int) timeresult == -1)
1066 debugpline1("time_from_yyyymmddhhmmss(%s) would have returned -1",
1075 * moon period = 29.53058 days ~= 30, year = 365.2422 days
1076 * days moon phase advances on first day of year compared to preceding year
1077 * = 365.2422 - 12*29.53058 ~= 11
1078 * years in Metonic cycle (time until same phases fall on the same days of
1079 * the month) = 18.6 ~= 19
1080 * moon phase on first day of year (epact) ~= (11*(year%19) + 29) % 30
1081 * (29 as initial condition)
1082 * current phase in days = first day phase + days elapsed in year
1083 * 6 moons ~= 177 days
1084 * 177 ~= 8 reported phases * 22
1085 * + 11/22 for rounding
1088 phase_of_the_moon() /* 0-7, with 0: new, 4: full */
1090 register struct tm *lt = getlt();
1091 register int epact, diy, goldn;
1094 goldn = (lt->tm_year % 19) + 1;
1095 epact = (11 * goldn + 18) % 30;
1096 if ((epact == 25 && goldn > 11) || epact == 24)
1099 return ((((((diy + epact) * 6) + 11) % 177) / 22) & 7);
1105 register struct tm *lt = getlt();
1107 /* tm_wday (day of week; 0==Sunday) == 5 => Friday */
1108 return (boolean) (lt->tm_wday == 5 && lt->tm_mday == 13);
1114 register int hour = getlt()->tm_hour;
1116 return (hour < 6 || hour > 21);
1122 return (getlt()->tm_hour == 0);
1125 /* strbuf_init() initializes strbuf state for use */
1134 /* strbuf_append() appends given str to strbuf->str */
1136 strbuf_append(strbuf, str)
1140 int len = (int) strlen(str) + 1;
1142 strbuf_reserve(strbuf,
1143 len + (strbuf->str ? (int) strlen(strbuf->str) : 0));
1144 Strcat(strbuf->str, str);
1147 /* strbuf_reserve() ensure strbuf->str has storage for len characters */
1149 strbuf_reserve(strbuf, len)
1153 if (strbuf->str == NULL) {
1154 strbuf->str = strbuf->buf;
1155 strbuf->str[0] = '\0';
1156 strbuf->len = (int) sizeof strbuf->buf;
1159 if (len > strbuf->len) {
1160 char *oldbuf = strbuf->str;
1162 strbuf->len = len + (int) sizeof strbuf->buf;
1163 strbuf->str = (char *) alloc(strbuf->len);
1164 Strcpy(strbuf->str, oldbuf);
1165 if (oldbuf != strbuf->buf)
1166 free((genericptr_t) oldbuf);
1170 /* strbuf_empty() frees allocated memory and set strbuf to initial state */
1172 strbuf_empty(strbuf)
1175 if (strbuf->str != NULL && strbuf->str != strbuf->buf)
1176 free((genericptr_t) strbuf->str);
1177 strbuf_init(strbuf);
1180 /* strbuf_nl_to_crlf() converts all occurences of \n to \r\n */
1182 strbuf_nl_to_crlf(strbuf)
1186 int len = (int) strlen(strbuf->str);
1188 char *cp = strbuf->str;
1194 strbuf_reserve(strbuf, len + count + 1);
1195 for (cp = strbuf->str + len + count; count; --cp)
1196 if ((*cp = cp[-count]) == '\n') {