159243Sobrien/* 259243Sobrien * tc.str.c: Short string package 359243Sobrien * This has been a lesson of how to write buggy code! 459243Sobrien */ 559243Sobrien/*- 659243Sobrien * Copyright (c) 1980, 1991 The Regents of the University of California. 759243Sobrien * All rights reserved. 859243Sobrien * 959243Sobrien * Redistribution and use in source and binary forms, with or without 1059243Sobrien * modification, are permitted provided that the following conditions 1159243Sobrien * are met: 1259243Sobrien * 1. Redistributions of source code must retain the above copyright 1359243Sobrien * notice, this list of conditions and the following disclaimer. 1459243Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1559243Sobrien * notice, this list of conditions and the following disclaimer in the 1659243Sobrien * documentation and/or other materials provided with the distribution. 17100616Smp * 3. Neither the name of the University nor the names of its contributors 1859243Sobrien * may be used to endorse or promote products derived from this software 1959243Sobrien * without specific prior written permission. 2059243Sobrien * 2159243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2259243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2359243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2459243Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2559243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2659243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2759243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2859243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2959243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3059243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3159243Sobrien * SUCH DAMAGE. 3259243Sobrien */ 3359243Sobrien#include "sh.h" 3459243Sobrien 35231990Smp#include <assert.h> 36145479Smp#include <limits.h> 3759243Sobrien 3859243Sobrien#define MALLOC_INCR 128 39145479Smp#ifdef WIDE_STRINGS 40145479Smp#define MALLOC_SURPLUS MB_LEN_MAX /* Space for one multibyte character */ 41145479Smp#else 42145479Smp#define MALLOC_SURPLUS 0 43145479Smp#endif 4459243Sobrien 45145479Smp#ifdef WIDE_STRINGS 46145479Smpsize_t 47231990Smpone_mbtowc(Char *pwc, const char *s, size_t n) 48145479Smp{ 49145479Smp int len; 50145479Smp 51145479Smp len = rt_mbtowc(pwc, s, n); 52145479Smp if (len == -1) { 53195609Smp reset_mbtowc(); 54145479Smp *pwc = (unsigned char)*s | INVALID_BYTE; 55145479Smp } 56145479Smp if (len <= 0) 57145479Smp len = 1; 58145479Smp return len; 59145479Smp} 60145479Smp 61145479Smpsize_t 62231990Smpone_wctomb(char *s, Char wchar) 63145479Smp{ 64145479Smp int len; 65145479Smp 66316957Sdchagin#if INVALID_BYTE != 0 67316957Sdchagin if ((wchar & INVALID_BYTE) == INVALID_BYTE) { /* wchar >= INVALID_BYTE */ 68316957Sdchagin /* invalid char 69316957Sdchagin * exmaple) 70316957Sdchagin * if wchar = f0000090(=90|INVALID_BYTE), then *s = ffffff90 */ 71316957Sdchagin *s = (char)wchar; 72145479Smp len = 1; 73316957Sdchagin#else 74316957Sdchagin if (wchar & (CHAR & INVALID_BYTE)) { 75316957Sdchagin s[0] = wchar & (CHAR & 0xFF); 76316957Sdchagin len = 1; 77316957Sdchagin#endif 78145479Smp } else { 79316957Sdchagin#if INVALID_BYTE != 0 80316957Sdchagin wchar &= MAX_UTF32; 81316957Sdchagin#else 82316957Sdchagin wchar &= CHAR; 83316957Sdchagin#endif 84231990Smp#ifdef UTF16_STRINGS 85231990Smp if (wchar >= 0x10000) { 86231990Smp /* UTF-16 systems can't handle these values directly in calls to 87231990Smp wctomb. Convert value to UTF-16 surrogate and call wcstombs to 88231990Smp convert the "string" to the correct multibyte representation, 89231990Smp if any. */ 90231990Smp wchar_t ws[3]; 91231990Smp wchar -= 0x10000; 92231990Smp ws[0] = 0xd800 | (wchar >> 10); 93231990Smp ws[1] = 0xdc00 | (wchar & 0x3ff); 94231990Smp ws[2] = 0; 95231990Smp /* The return value of wcstombs excludes the trailing 0, so len is 96231990Smp the correct number of multibytes for the Unicode char. */ 97231990Smp len = wcstombs (s, ws, MB_CUR_MAX + 1); 98231990Smp } else 99231990Smp#endif 100231990Smp len = wctomb(s, (wchar_t) wchar); 101145479Smp if (len == -1) 102145479Smp s[0] = wchar; 103145479Smp if (len <= 0) 104145479Smp len = 1; 105145479Smp } 106145479Smp return len; 107145479Smp} 108167465Smp 109145479Smpint 110231990Smprt_mbtowc(Char *pwc, const char *s, size_t n) 111145479Smp{ 112145479Smp int ret; 113145479Smp char back[MB_LEN_MAX]; 114231990Smp wchar_t tmp; 115231990Smp#if defined(UTF16_STRINGS) && defined(HAVE_MBRTOWC) 116231990Smp# if defined(AUTOSET_KANJI) 117231990Smp static mbstate_t mb_zero, mb; 118231990Smp /* 119231990Smp * Workaround the Shift-JIS endcoding that translates unshifted 7 bit ASCII! 120231990Smp */ 121231990Smp if (!adrof(STRnokanji) && n && pwc && s && (*s == '\\' || *s == '~') && 122231990Smp !memcmp(&mb, &mb_zero, sizeof(mb))) 123231990Smp { 124231990Smp *pwc = *s; 125231990Smp return 1; 126231990Smp } 127231990Smp# else 128231990Smp mbstate_t mb; 129231990Smp# endif 130145479Smp 131231990Smp memset (&mb, 0, sizeof mb); 132231990Smp ret = mbrtowc(&tmp, s, n, &mb); 133231990Smp#else 134231990Smp ret = mbtowc(&tmp, s, n); 135231990Smp#endif 136231990Smp if (ret > 0) { 137231990Smp *pwc = tmp; 138231990Smp#if defined(UTF16_STRINGS) && defined(HAVE_MBRTOWC) 139231990Smp if (tmp >= 0xd800 && tmp <= 0xdbff) { 140231990Smp /* UTF-16 surrogate pair. Fetch second half and compute 141231990Smp UTF-32 value. Dispense with the inverse test in this case. */ 142231990Smp size_t n2 = mbrtowc(&tmp, s + ret, n - ret, &mb); 143231990Smp if (n2 == 0 || n2 == (size_t)-1 || n2 == (size_t)-2) 144231990Smp ret = -1; 145231990Smp else { 146231990Smp *pwc = (((*pwc & 0x3ff) << 10) | (tmp & 0x3ff)) + 0x10000; 147231990Smp ret += n2; 148231990Smp } 149231990Smp } else 150231990Smp#endif 151231990Smp if (wctomb(back, *pwc) != ret || memcmp(s, back, ret) != 0) 152231990Smp ret = -1; 153231990Smp 154231990Smp } else if (ret == -2) 155145479Smp ret = -1; 156231990Smp else if (ret == 0) 157231990Smp *pwc = '\0'; 158231990Smp 159145479Smp return ret; 160145479Smp} 161167465Smp#endif 162145479Smp 163167465Smp#ifdef SHORT_STRINGS 16459243SobrienChar ** 165167465Smpblk2short(char **src) 16659243Sobrien{ 16759243Sobrien size_t n; 168145479Smp Char **sdst, **dst; 16959243Sobrien 17059243Sobrien /* 17159243Sobrien * Count 17259243Sobrien */ 17359243Sobrien for (n = 0; src[n] != NULL; n++) 17459243Sobrien continue; 175167465Smp sdst = dst = xmalloc((n + 1) * sizeof(Char *)); 17659243Sobrien 17759243Sobrien for (; *src != NULL; src++) 17859243Sobrien *dst++ = SAVE(*src); 17959243Sobrien *dst = NULL; 18059243Sobrien return (sdst); 18159243Sobrien} 18259243Sobrien 18359243Sobrienchar ** 184167465Smpshort2blk(Char **src) 18559243Sobrien{ 18659243Sobrien size_t n; 187145479Smp char **sdst, **dst; 18859243Sobrien 18959243Sobrien /* 19059243Sobrien * Count 19159243Sobrien */ 19259243Sobrien for (n = 0; src[n] != NULL; n++) 19359243Sobrien continue; 194167465Smp sdst = dst = xmalloc((n + 1) * sizeof(char *)); 19559243Sobrien 19659243Sobrien for (; *src != NULL; src++) 19759243Sobrien *dst++ = strsave(short2str(*src)); 19859243Sobrien *dst = NULL; 19959243Sobrien return (sdst); 20059243Sobrien} 20159243Sobrien 20259243SobrienChar * 203167465Smpstr2short(const char *src) 20459243Sobrien{ 205167465Smp static struct Strbuf buf; /* = Strbuf_INIT; */ 20659243Sobrien 20759243Sobrien if (src == NULL) 20859243Sobrien return (NULL); 20959243Sobrien 210167465Smp buf.len = 0; 211167465Smp while (*src) { 212167465Smp Char wc; 21359243Sobrien 214167465Smp src += one_mbtowc(&wc, src, MB_LEN_MAX); 215167465Smp Strbuf_append1(&buf, wc); 21659243Sobrien } 217167465Smp Strbuf_terminate(&buf); 218167465Smp return buf.s; 21959243Sobrien} 22059243Sobrien 22159243Sobrienchar * 222167465Smpshort2str(const Char *src) 22359243Sobrien{ 22459243Sobrien static char *sdst = NULL; 22559243Sobrien static size_t dstsize = 0; 226145479Smp char *dst, *edst; 22759243Sobrien 22859243Sobrien if (src == NULL) 22959243Sobrien return (NULL); 23059243Sobrien 23159243Sobrien if (sdst == NULL) { 23259243Sobrien dstsize = MALLOC_INCR; 233167465Smp sdst = xmalloc((dstsize + MALLOC_SURPLUS) * sizeof(char)); 23459243Sobrien } 23559243Sobrien dst = sdst; 23659243Sobrien edst = &dst[dstsize]; 23759243Sobrien while (*src) { 238316957Sdchagin dst += one_wctomb(dst, *src); 239145479Smp src++; 240145479Smp if (dst >= edst) { 241195609Smp char *wdst = dst; 242195609Smp char *wedst = edst; 243195609Smp 24459243Sobrien dstsize += MALLOC_INCR; 245167465Smp sdst = xrealloc(sdst, (dstsize + MALLOC_SURPLUS) * sizeof(char)); 24659243Sobrien edst = &sdst[dstsize]; 24759243Sobrien dst = &edst[-MALLOC_INCR]; 248195609Smp while (wdst > wedst) { 249195609Smp dst++; 250195609Smp wdst--; 251195609Smp } 25259243Sobrien } 25359243Sobrien } 25459243Sobrien *dst = 0; 25559243Sobrien return (sdst); 25659243Sobrien} 25759243Sobrien 258231990Smp#if !defined (WIDE_STRINGS) || defined (UTF16_STRINGS) 25959243SobrienChar * 260167465Smps_strcpy(Char *dst, const Char *src) 26159243Sobrien{ 262145479Smp Char *sdst; 26359243Sobrien 26459243Sobrien sdst = dst; 26559243Sobrien while ((*dst++ = *src++) != '\0') 26659243Sobrien continue; 26759243Sobrien return (sdst); 26859243Sobrien} 26959243Sobrien 27059243SobrienChar * 271167465Smps_strncpy(Char *dst, const Char *src, size_t n) 27259243Sobrien{ 273145479Smp Char *sdst; 27459243Sobrien 27559243Sobrien if (n == 0) 27659243Sobrien return(dst); 27759243Sobrien 27859243Sobrien sdst = dst; 27959243Sobrien do 28059243Sobrien if ((*dst++ = *src++) == '\0') { 28159243Sobrien while (--n != 0) 28259243Sobrien *dst++ = '\0'; 28359243Sobrien return(sdst); 28459243Sobrien } 28559243Sobrien while (--n != 0); 28659243Sobrien return (sdst); 28759243Sobrien} 28859243Sobrien 28959243SobrienChar * 290167465Smps_strcat(Char *dst, const Char *src) 29159243Sobrien{ 292167465Smp Strcpy(Strend(dst), src); 293167465Smp return dst; 29459243Sobrien} 29559243Sobrien 29659243Sobrien#ifdef NOTUSED 29759243SobrienChar * 298167465Smps_strncat(Char *dst, const Char *src, size_t n) 29959243Sobrien{ 300145479Smp Char *sdst; 30159243Sobrien 30259243Sobrien if (n == 0) 30359243Sobrien return (dst); 30459243Sobrien 30559243Sobrien sdst = dst; 30659243Sobrien 307167465Smp while (*dst) 308167465Smp dst++; 30959243Sobrien 31059243Sobrien do 31159243Sobrien if ((*dst++ = *src++) == '\0') 31259243Sobrien return(sdst); 31359243Sobrien while (--n != 0) 31459243Sobrien continue; 31559243Sobrien 31659243Sobrien *dst = '\0'; 31759243Sobrien return (sdst); 31859243Sobrien} 31959243Sobrien 32059243Sobrien#endif 32159243Sobrien 32259243SobrienChar * 323167465Smps_strchr(const Char *str, int ch) 32459243Sobrien{ 32559243Sobrien do 32659243Sobrien if (*str == ch) 327145479Smp return ((Char *)(intptr_t)str); 32859243Sobrien while (*str++); 32959243Sobrien return (NULL); 33059243Sobrien} 33159243Sobrien 33259243SobrienChar * 333167465Smps_strrchr(const Char *str, int ch) 33459243Sobrien{ 335145479Smp const Char *rstr; 33659243Sobrien 33759243Sobrien rstr = NULL; 33859243Sobrien do 33959243Sobrien if (*str == ch) 34059243Sobrien rstr = str; 34159243Sobrien while (*str++); 342145479Smp return ((Char *)(intptr_t)rstr); 34359243Sobrien} 34459243Sobrien 34559243Sobriensize_t 346167465Smps_strlen(const Char *str) 34759243Sobrien{ 348145479Smp size_t n; 34959243Sobrien 35059243Sobrien for (n = 0; *str++; n++) 35159243Sobrien continue; 35259243Sobrien return (n); 35359243Sobrien} 35459243Sobrien 35559243Sobrienint 356167465Smps_strcmp(const Char *str1, const Char *str2) 35759243Sobrien{ 35859243Sobrien for (; *str1 && *str1 == *str2; str1++, str2++) 35959243Sobrien continue; 36059243Sobrien /* 36159243Sobrien * The following case analysis is necessary so that characters which look 36259243Sobrien * negative collate low against normal characters but high against the 36359243Sobrien * end-of-string NUL. 36459243Sobrien */ 36559243Sobrien if (*str1 == '\0' && *str2 == '\0') 36659243Sobrien return (0); 36759243Sobrien else if (*str1 == '\0') 36859243Sobrien return (-1); 36959243Sobrien else if (*str2 == '\0') 37059243Sobrien return (1); 37159243Sobrien else 37259243Sobrien return (*str1 - *str2); 37359243Sobrien} 37459243Sobrien 37559243Sobrienint 376167465Smps_strncmp(const Char *str1, const Char *str2, size_t n) 37759243Sobrien{ 37859243Sobrien if (n == 0) 37959243Sobrien return (0); 38059243Sobrien do { 38159243Sobrien if (*str1 != *str2) { 38259243Sobrien /* 38359243Sobrien * The following case analysis is necessary so that characters 38459243Sobrien * which look negative collate low against normal characters 38559243Sobrien * but high against the end-of-string NUL. 38659243Sobrien */ 38759243Sobrien if (*str1 == '\0') 38859243Sobrien return (-1); 38959243Sobrien else if (*str2 == '\0') 39059243Sobrien return (1); 39159243Sobrien else 39259243Sobrien return (*str1 - *str2); 39359243Sobrien } 39459243Sobrien if (*str1 == '\0') 39559243Sobrien return(0); 39659243Sobrien str1++, str2++; 39759243Sobrien } while (--n != 0); 39859243Sobrien return(0); 39959243Sobrien} 400145479Smp#endif /* not WIDE_STRINGS */ 40159243Sobrien 402131962Smpint 403167465Smps_strcasecmp(const Char *str1, const Char *str2) 404131962Smp{ 405145479Smp#ifdef WIDE_STRINGS 406231990Smp wint_t l1 = 0, l2 = 0; 407231990Smp for (; *str1; str1++, str2++) 408231990Smp if (*str1 == *str2) 409231990Smp l1 = l2 = 0; 410231990Smp else if ((l1 = towlower(*str1)) != (l2 = towlower(*str2))) 411231990Smp break; 412145479Smp#else 413231990Smp unsigned char l1 = 0, l2 = 0; 414231990Smp for (; *str1; str1++, str2++) 415231990Smp if (*str1 == *str2) 416231990Smp l1 = l2 = 0; 417231990Smp else if ((l1 = tolower((unsigned char)*str1)) != 418231990Smp (l2 = tolower((unsigned char)*str2))) 419231990Smp break; 420145479Smp#endif 421131962Smp /* 422131962Smp * The following case analysis is necessary so that characters which look 423131962Smp * negative collate low against normal characters but high against the 424131962Smp * end-of-string NUL. 425131962Smp */ 426131962Smp if (*str1 == '\0' && *str2 == '\0') 427131962Smp return (0); 428131962Smp else if (*str1 == '\0') 429131962Smp return (-1); 430131962Smp else if (*str2 == '\0') 431131962Smp return (1); 432131962Smp else if (l1 == l2) /* They are zero when they are equal */ 433131962Smp return (*str1 - *str2); 434131962Smp else 435131962Smp return (l1 - l2); 436131962Smp} 437131962Smp 43859243SobrienChar * 439167465Smps_strnsave(const Char *s, size_t len) 44059243Sobrien{ 441167465Smp Char *n; 442167465Smp 443167465Smp n = xmalloc((len + 1) * sizeof (*n)); 444167465Smp memcpy(n, s, len * sizeof (*n)); 445167465Smp n[len] = '\0'; 446167465Smp return n; 447167465Smp} 448167465Smp 449167465SmpChar * 450167465Smps_strsave(const Char *s) 451167465Smp{ 45259243Sobrien Char *n; 453167465Smp size_t size; 45459243Sobrien 455167465Smp if (s == NULL) 45659243Sobrien s = STRNULL; 457167465Smp size = (Strlen(s) + 1) * sizeof(*n); 458167465Smp n = xmalloc(size); 459167465Smp memcpy(n, s, size); 46059243Sobrien return (n); 46159243Sobrien} 46259243Sobrien 46359243SobrienChar * 464167465Smps_strspl(const Char *cp, const Char *dp) 46559243Sobrien{ 466167465Smp Char *res, *ep; 467167465Smp const Char *p, *q; 46859243Sobrien 46959243Sobrien if (!cp) 47059243Sobrien cp = STRNULL; 47159243Sobrien if (!dp) 47259243Sobrien dp = STRNULL; 473167465Smp for (p = cp; *p++;) 47459243Sobrien continue; 475167465Smp for (q = dp; *q++;) 47659243Sobrien continue; 477167465Smp res = xmalloc(((p - cp) + (q - dp) - 1) * sizeof(Char)); 478167465Smp for (ep = res, q = cp; (*ep++ = *q++) != '\0';) 47959243Sobrien continue; 480167465Smp for (ep--, q = dp; (*ep++ = *q++) != '\0';) 48159243Sobrien continue; 482167465Smp return (res); 48359243Sobrien} 48459243Sobrien 48559243SobrienChar * 486167465Smps_strend(const Char *cp) 48759243Sobrien{ 48859243Sobrien if (!cp) 489145479Smp return ((Char *)(intptr_t) cp); 49059243Sobrien while (*cp) 49159243Sobrien cp++; 492145479Smp return ((Char *)(intptr_t) cp); 49359243Sobrien} 49459243Sobrien 49559243SobrienChar * 496167465Smps_strstr(const Char *s, const Char *t) 49759243Sobrien{ 49859243Sobrien do { 499145479Smp const Char *ss = s; 500145479Smp const Char *tt = t; 50159243Sobrien 50259243Sobrien do 50359243Sobrien if (*tt == '\0') 504145479Smp return ((Char *)(intptr_t) s); 50559243Sobrien while (*ss++ == *tt++); 50659243Sobrien } while (*s++ != '\0'); 50759243Sobrien return (NULL); 50859243Sobrien} 50959243Sobrien 510167465Smp#else /* !SHORT_STRINGS */ 511167465Smpchar * 512167465Smpcaching_strip(const char *s) 513167465Smp{ 514167465Smp static char *buf = NULL; 515167465Smp static size_t buf_size = 0; 516167465Smp size_t size; 51759243Sobrien 518167465Smp if (s == NULL) 519167465Smp return NULL; 520167465Smp size = strlen(s) + 1; 521167465Smp if (buf_size < size) { 522167465Smp buf = xrealloc(buf, size); 523167465Smp buf_size = size; 524167465Smp } 525167465Smp memcpy(buf, s, size); 526167465Smp strip(buf); 527167465Smp return buf; 528167465Smp} 529167465Smp#endif 530167465Smp 53159243Sobrienchar * 532167465Smpshort2qstr(const Char *src) 53359243Sobrien{ 53459243Sobrien static char *sdst = NULL; 53559243Sobrien static size_t dstsize = 0; 536145479Smp char *dst, *edst; 53759243Sobrien 53859243Sobrien if (src == NULL) 53959243Sobrien return (NULL); 54059243Sobrien 54159243Sobrien if (sdst == NULL) { 54259243Sobrien dstsize = MALLOC_INCR; 543167465Smp sdst = xmalloc((dstsize + MALLOC_SURPLUS) * sizeof(char)); 54459243Sobrien } 54559243Sobrien dst = sdst; 54659243Sobrien edst = &dst[dstsize]; 54759243Sobrien while (*src) { 54859243Sobrien if (*src & QUOTE) { 54959243Sobrien *dst++ = '\\'; 55059243Sobrien if (dst == edst) { 55159243Sobrien dstsize += MALLOC_INCR; 552167465Smp sdst = xrealloc(sdst, 553167465Smp (dstsize + MALLOC_SURPLUS) * sizeof(char)); 55459243Sobrien edst = &sdst[dstsize]; 55559243Sobrien dst = &edst[-MALLOC_INCR]; 55659243Sobrien } 55759243Sobrien } 558316957Sdchagin dst += one_wctomb(dst, *src); 559145479Smp src++; 560145479Smp if (dst >= edst) { 561195609Smp ptrdiff_t i = dst - edst; 56259243Sobrien dstsize += MALLOC_INCR; 563167465Smp sdst = xrealloc(sdst, (dstsize + MALLOC_SURPLUS) * sizeof(char)); 56459243Sobrien edst = &sdst[dstsize]; 565195609Smp dst = &edst[-MALLOC_INCR + i]; 56659243Sobrien } 56759243Sobrien } 56859243Sobrien *dst = 0; 56959243Sobrien return (sdst); 57059243Sobrien} 571167465Smp 572195609Smpstruct blk_buf * 573316957Sdchaginbb_alloc(void) 574195609Smp{ 575195609Smp return xcalloc(1, sizeof(struct blk_buf)); 576195609Smp} 577195609Smp 578167465Smpstatic void 579167465Smpbb_store(struct blk_buf *bb, Char *str) 580167465Smp{ 581167465Smp if (bb->len == bb->size) { /* Keep space for terminating NULL */ 582167465Smp if (bb->size == 0) 583167465Smp bb->size = 16; /* Arbitrary */ 584167465Smp else 585167465Smp bb->size *= 2; 586167465Smp bb->vec = xrealloc(bb->vec, bb->size * sizeof (*bb->vec)); 587167465Smp } 588167465Smp bb->vec[bb->len] = str; 589167465Smp} 590167465Smp 591167465Smpvoid 592167465Smpbb_append(struct blk_buf *bb, Char *str) 593167465Smp{ 594167465Smp bb_store(bb, str); 595167465Smp bb->len++; 596167465Smp} 597167465Smp 598167465Smpvoid 599167465Smpbb_cleanup(void *xbb) 600167465Smp{ 601167465Smp struct blk_buf *bb; 602167465Smp size_t i; 603167465Smp 604316957Sdchagin bb = (struct blk_buf *)xbb; 605316957Sdchagin if (bb->vec) { 606316957Sdchagin for (i = 0; i < bb->len; i++) 607316957Sdchagin xfree(bb->vec[i]); 608316957Sdchagin xfree(bb->vec); 609316957Sdchagin } 610316957Sdchagin bb->vec = NULL; 611316957Sdchagin bb->len = 0; 612167465Smp} 613167465Smp 614195609Smpvoid 615195609Smpbb_free(void *bb) 616195609Smp{ 617195609Smp bb_cleanup(bb); 618195609Smp xfree(bb); 619195609Smp} 620195609Smp 621167465SmpChar ** 622167465Smpbb_finish(struct blk_buf *bb) 623167465Smp{ 624167465Smp bb_store(bb, NULL); 625167465Smp return xrealloc(bb->vec, (bb->len + 1) * sizeof (*bb->vec)); 626167465Smp} 627167465Smp 628167465Smp#define DO_STRBUF(STRBUF, CHAR, STRLEN) \ 629195609Smp \ 630195609Smpstruct STRBUF * \ 631195609SmpSTRBUF##_alloc(void) \ 632195609Smp{ \ 633195609Smp return xcalloc(1, sizeof(struct STRBUF)); \ 634195609Smp} \ 635195609Smp \ 636167465Smpstatic void \ 637167465SmpSTRBUF##_store1(struct STRBUF *buf, CHAR c) \ 638167465Smp{ \ 639167465Smp if (buf->size == buf->len) { \ 640167465Smp if (buf->size == 0) \ 641167465Smp buf->size = 64; /* Arbitrary */ \ 642167465Smp else \ 643167465Smp buf->size *= 2; \ 644167465Smp buf->s = xrealloc(buf->s, buf->size * sizeof(*buf->s)); \ 645167465Smp } \ 646231990Smp assert(buf->s); \ 647167465Smp buf->s[buf->len] = c; \ 648167465Smp} \ 649167465Smp \ 650167465Smp/* Like strbuf_append1(buf, '\0'), but don't advance len */ \ 651167465Smpvoid \ 652167465SmpSTRBUF##_terminate(struct STRBUF *buf) \ 653167465Smp{ \ 654167465Smp STRBUF##_store1(buf, '\0'); \ 655167465Smp} \ 656167465Smp \ 657167465Smpvoid \ 658167465SmpSTRBUF##_append1(struct STRBUF *buf, CHAR c) \ 659167465Smp{ \ 660167465Smp STRBUF##_store1(buf, c); \ 661167465Smp buf->len++; \ 662167465Smp} \ 663167465Smp \ 664167465Smpvoid \ 665167465SmpSTRBUF##_appendn(struct STRBUF *buf, const CHAR *s, size_t len) \ 666167465Smp{ \ 667167465Smp if (buf->size < buf->len + len) { \ 668167465Smp if (buf->size == 0) \ 669167465Smp buf->size = 64; /* Arbitrary */ \ 670167465Smp while (buf->size < buf->len + len) \ 671167465Smp buf->size *= 2; \ 672167465Smp buf->s = xrealloc(buf->s, buf->size * sizeof(*buf->s)); \ 673167465Smp } \ 674167465Smp memcpy(buf->s + buf->len, s, len * sizeof(*buf->s)); \ 675167465Smp buf->len += len; \ 676167465Smp} \ 677167465Smp \ 678167465Smpvoid \ 679167465SmpSTRBUF##_append(struct STRBUF *buf, const CHAR *s) \ 680167465Smp{ \ 681167465Smp STRBUF##_appendn(buf, s, STRLEN(s)); \ 682167465Smp} \ 683167465Smp \ 684167465SmpCHAR * \ 685167465SmpSTRBUF##_finish(struct STRBUF *buf) \ 686167465Smp{ \ 687167465Smp STRBUF##_append1(buf, 0); \ 688167465Smp return xrealloc(buf->s, buf->len * sizeof(*buf->s)); \ 689167465Smp} \ 690167465Smp \ 691167465Smpvoid \ 692167465SmpSTRBUF##_cleanup(void *xbuf) \ 693167465Smp{ \ 694167465Smp struct STRBUF *buf; \ 695167465Smp \ 696167465Smp buf = xbuf; \ 697167465Smp xfree(buf->s); \ 698167465Smp} \ 699167465Smp \ 700195609Smpvoid \ 701195609SmpSTRBUF##_free(void *xbuf) \ 702195609Smp{ \ 703195609Smp STRBUF##_cleanup(xbuf); \ 704195609Smp xfree(xbuf); \ 705195609Smp} \ 706195609Smp \ 707167465Smpconst struct STRBUF STRBUF##_init /* = STRBUF##_INIT; */ 708167465Smp 709167465SmpDO_STRBUF(strbuf, char, strlen); 710167465SmpDO_STRBUF(Strbuf, Char, Strlen); 711