1232633Smp/* $Header: /p/tcsh/cvsroot/tcsh/tc.str.c,v 3.42 2012/01/10 21:34:31 christos Exp $ */ 259243Sobrien/* 359243Sobrien * tc.str.c: Short string package 459243Sobrien * This has been a lesson of how to write buggy code! 559243Sobrien */ 659243Sobrien/*- 759243Sobrien * Copyright (c) 1980, 1991 The Regents of the University of California. 859243Sobrien * All rights reserved. 959243Sobrien * 1059243Sobrien * Redistribution and use in source and binary forms, with or without 1159243Sobrien * modification, are permitted provided that the following conditions 1259243Sobrien * are met: 1359243Sobrien * 1. Redistributions of source code must retain the above copyright 1459243Sobrien * notice, this list of conditions and the following disclaimer. 1559243Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1659243Sobrien * notice, this list of conditions and the following disclaimer in the 1759243Sobrien * documentation and/or other materials provided with the distribution. 18100616Smp * 3. Neither the name of the University nor the names of its contributors 1959243Sobrien * may be used to endorse or promote products derived from this software 2059243Sobrien * without specific prior written permission. 2159243Sobrien * 2259243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2359243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2459243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2559243Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2659243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2759243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2859243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2959243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3059243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3159243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3259243Sobrien * SUCH DAMAGE. 3359243Sobrien */ 3459243Sobrien#include "sh.h" 3559243Sobrien 36232633Smp#include <assert.h> 37145479Smp#include <limits.h> 3859243Sobrien 39232633SmpRCSID("$tcsh: tc.str.c,v 3.42 2012/01/10 21:34:31 christos Exp $") 40145479Smp 4159243Sobrien#define MALLOC_INCR 128 42145479Smp#ifdef WIDE_STRINGS 43145479Smp#define MALLOC_SURPLUS MB_LEN_MAX /* Space for one multibyte character */ 44145479Smp#else 45145479Smp#define MALLOC_SURPLUS 0 46145479Smp#endif 4759243Sobrien 48145479Smp#ifdef WIDE_STRINGS 49145479Smpsize_t 50232633Smpone_mbtowc(Char *pwc, const char *s, size_t n) 51145479Smp{ 52145479Smp int len; 53145479Smp 54145479Smp len = rt_mbtowc(pwc, s, n); 55145479Smp if (len == -1) { 56195609Smp reset_mbtowc(); 57145479Smp *pwc = (unsigned char)*s | INVALID_BYTE; 58145479Smp } 59145479Smp if (len <= 0) 60145479Smp len = 1; 61145479Smp return len; 62145479Smp} 63145479Smp 64145479Smpsize_t 65232633Smpone_wctomb(char *s, Char wchar) 66145479Smp{ 67145479Smp int len; 68145479Smp 69145479Smp if (wchar & INVALID_BYTE) { 70145479Smp s[0] = wchar & 0xFF; 71145479Smp len = 1; 72145479Smp } else { 73232633Smp#ifdef UTF16_STRINGS 74232633Smp if (wchar >= 0x10000) { 75232633Smp /* UTF-16 systems can't handle these values directly in calls to 76232633Smp wctomb. Convert value to UTF-16 surrogate and call wcstombs to 77232633Smp convert the "string" to the correct multibyte representation, 78232633Smp if any. */ 79232633Smp wchar_t ws[3]; 80232633Smp wchar -= 0x10000; 81232633Smp ws[0] = 0xd800 | (wchar >> 10); 82232633Smp ws[1] = 0xdc00 | (wchar & 0x3ff); 83232633Smp ws[2] = 0; 84232633Smp /* The return value of wcstombs excludes the trailing 0, so len is 85232633Smp the correct number of multibytes for the Unicode char. */ 86232633Smp len = wcstombs (s, ws, MB_CUR_MAX + 1); 87232633Smp } else 88232633Smp#endif 89232633Smp len = wctomb(s, (wchar_t) wchar); 90145479Smp if (len == -1) 91145479Smp s[0] = wchar; 92145479Smp if (len <= 0) 93145479Smp len = 1; 94145479Smp } 95145479Smp return len; 96145479Smp} 97167465Smp 98145479Smpint 99232633Smprt_mbtowc(Char *pwc, const char *s, size_t n) 100145479Smp{ 101145479Smp int ret; 102145479Smp char back[MB_LEN_MAX]; 103232633Smp wchar_t tmp; 104232633Smp#if defined(UTF16_STRINGS) && defined(HAVE_MBRTOWC) 105232633Smp# if defined(AUTOSET_KANJI) 106232633Smp static mbstate_t mb_zero, mb; 107232633Smp /* 108232633Smp * Workaround the Shift-JIS endcoding that translates unshifted 7 bit ASCII! 109232633Smp */ 110232633Smp if (!adrof(STRnokanji) && n && pwc && s && (*s == '\\' || *s == '~') && 111232633Smp !memcmp(&mb, &mb_zero, sizeof(mb))) 112232633Smp { 113232633Smp *pwc = *s; 114232633Smp return 1; 115232633Smp } 116232633Smp# else 117232633Smp mbstate_t mb; 118232633Smp# endif 119145479Smp 120232633Smp memset (&mb, 0, sizeof mb); 121232633Smp ret = mbrtowc(&tmp, s, n, &mb); 122232633Smp#else 123232633Smp ret = mbtowc(&tmp, s, n); 124232633Smp#endif 125232633Smp if (ret > 0) { 126232633Smp *pwc = tmp; 127232633Smp#if defined(UTF16_STRINGS) && defined(HAVE_MBRTOWC) 128232633Smp if (tmp >= 0xd800 && tmp <= 0xdbff) { 129232633Smp /* UTF-16 surrogate pair. Fetch second half and compute 130232633Smp UTF-32 value. Dispense with the inverse test in this case. */ 131232633Smp size_t n2 = mbrtowc(&tmp, s + ret, n - ret, &mb); 132232633Smp if (n2 == 0 || n2 == (size_t)-1 || n2 == (size_t)-2) 133232633Smp ret = -1; 134232633Smp else { 135232633Smp *pwc = (((*pwc & 0x3ff) << 10) | (tmp & 0x3ff)) + 0x10000; 136232633Smp ret += n2; 137232633Smp } 138232633Smp } else 139232633Smp#endif 140232633Smp if (wctomb(back, *pwc) != ret || memcmp(s, back, ret) != 0) 141232633Smp ret = -1; 142232633Smp 143232633Smp } else if (ret == -2) 144145479Smp ret = -1; 145232633Smp else if (ret == 0) 146232633Smp *pwc = '\0'; 147232633Smp 148145479Smp return ret; 149145479Smp} 150167465Smp#endif 151145479Smp 152167465Smp#ifdef SHORT_STRINGS 15359243SobrienChar ** 154167465Smpblk2short(char **src) 15559243Sobrien{ 15659243Sobrien size_t n; 157145479Smp Char **sdst, **dst; 15859243Sobrien 15959243Sobrien /* 16059243Sobrien * Count 16159243Sobrien */ 16259243Sobrien for (n = 0; src[n] != NULL; n++) 16359243Sobrien continue; 164167465Smp sdst = dst = xmalloc((n + 1) * sizeof(Char *)); 16559243Sobrien 16659243Sobrien for (; *src != NULL; src++) 16759243Sobrien *dst++ = SAVE(*src); 16859243Sobrien *dst = NULL; 16959243Sobrien return (sdst); 17059243Sobrien} 17159243Sobrien 17259243Sobrienchar ** 173167465Smpshort2blk(Char **src) 17459243Sobrien{ 17559243Sobrien size_t n; 176145479Smp char **sdst, **dst; 17759243Sobrien 17859243Sobrien /* 17959243Sobrien * Count 18059243Sobrien */ 18159243Sobrien for (n = 0; src[n] != NULL; n++) 18259243Sobrien continue; 183167465Smp sdst = dst = xmalloc((n + 1) * sizeof(char *)); 18459243Sobrien 18559243Sobrien for (; *src != NULL; src++) 18659243Sobrien *dst++ = strsave(short2str(*src)); 18759243Sobrien *dst = NULL; 18859243Sobrien return (sdst); 18959243Sobrien} 19059243Sobrien 19159243SobrienChar * 192167465Smpstr2short(const char *src) 19359243Sobrien{ 194167465Smp static struct Strbuf buf; /* = Strbuf_INIT; */ 19559243Sobrien 19659243Sobrien if (src == NULL) 19759243Sobrien return (NULL); 19859243Sobrien 199167465Smp buf.len = 0; 200167465Smp while (*src) { 201167465Smp Char wc; 20259243Sobrien 203167465Smp src += one_mbtowc(&wc, src, MB_LEN_MAX); 204167465Smp Strbuf_append1(&buf, wc); 20559243Sobrien } 206167465Smp Strbuf_terminate(&buf); 207167465Smp return buf.s; 20859243Sobrien} 20959243Sobrien 21059243Sobrienchar * 211167465Smpshort2str(const Char *src) 21259243Sobrien{ 21359243Sobrien static char *sdst = NULL; 21459243Sobrien static size_t dstsize = 0; 215145479Smp char *dst, *edst; 21659243Sobrien 21759243Sobrien if (src == NULL) 21859243Sobrien return (NULL); 21959243Sobrien 22059243Sobrien if (sdst == NULL) { 22159243Sobrien dstsize = MALLOC_INCR; 222167465Smp sdst = xmalloc((dstsize + MALLOC_SURPLUS) * sizeof(char)); 22359243Sobrien } 22459243Sobrien dst = sdst; 22559243Sobrien edst = &dst[dstsize]; 22659243Sobrien while (*src) { 227145479Smp dst += one_wctomb(dst, *src & CHAR); 228145479Smp src++; 229145479Smp if (dst >= edst) { 230195609Smp char *wdst = dst; 231195609Smp char *wedst = edst; 232195609Smp 23359243Sobrien dstsize += MALLOC_INCR; 234167465Smp sdst = xrealloc(sdst, (dstsize + MALLOC_SURPLUS) * sizeof(char)); 23559243Sobrien edst = &sdst[dstsize]; 23659243Sobrien dst = &edst[-MALLOC_INCR]; 237195609Smp while (wdst > wedst) { 238195609Smp dst++; 239195609Smp wdst--; 240195609Smp } 24159243Sobrien } 24259243Sobrien } 24359243Sobrien *dst = 0; 24459243Sobrien return (sdst); 24559243Sobrien} 24659243Sobrien 247232633Smp#if !defined (WIDE_STRINGS) || defined (UTF16_STRINGS) 24859243SobrienChar * 249167465Smps_strcpy(Char *dst, const Char *src) 25059243Sobrien{ 251145479Smp Char *sdst; 25259243Sobrien 25359243Sobrien sdst = dst; 25459243Sobrien while ((*dst++ = *src++) != '\0') 25559243Sobrien continue; 25659243Sobrien return (sdst); 25759243Sobrien} 25859243Sobrien 25959243SobrienChar * 260167465Smps_strncpy(Char *dst, const Char *src, size_t n) 26159243Sobrien{ 262145479Smp Char *sdst; 26359243Sobrien 26459243Sobrien if (n == 0) 26559243Sobrien return(dst); 26659243Sobrien 26759243Sobrien sdst = dst; 26859243Sobrien do 26959243Sobrien if ((*dst++ = *src++) == '\0') { 27059243Sobrien while (--n != 0) 27159243Sobrien *dst++ = '\0'; 27259243Sobrien return(sdst); 27359243Sobrien } 27459243Sobrien while (--n != 0); 27559243Sobrien return (sdst); 27659243Sobrien} 27759243Sobrien 27859243SobrienChar * 279167465Smps_strcat(Char *dst, const Char *src) 28059243Sobrien{ 281167465Smp Strcpy(Strend(dst), src); 282167465Smp return dst; 28359243Sobrien} 28459243Sobrien 28559243Sobrien#ifdef NOTUSED 28659243SobrienChar * 287167465Smps_strncat(Char *dst, const Char *src, size_t n) 28859243Sobrien{ 289145479Smp Char *sdst; 29059243Sobrien 29159243Sobrien if (n == 0) 29259243Sobrien return (dst); 29359243Sobrien 29459243Sobrien sdst = dst; 29559243Sobrien 296167465Smp while (*dst) 297167465Smp dst++; 29859243Sobrien 29959243Sobrien do 30059243Sobrien if ((*dst++ = *src++) == '\0') 30159243Sobrien return(sdst); 30259243Sobrien while (--n != 0) 30359243Sobrien continue; 30459243Sobrien 30559243Sobrien *dst = '\0'; 30659243Sobrien return (sdst); 30759243Sobrien} 30859243Sobrien 30959243Sobrien#endif 31059243Sobrien 31159243SobrienChar * 312167465Smps_strchr(const Char *str, int ch) 31359243Sobrien{ 31459243Sobrien do 31559243Sobrien if (*str == ch) 316145479Smp return ((Char *)(intptr_t)str); 31759243Sobrien while (*str++); 31859243Sobrien return (NULL); 31959243Sobrien} 32059243Sobrien 32159243SobrienChar * 322167465Smps_strrchr(const Char *str, int ch) 32359243Sobrien{ 324145479Smp const Char *rstr; 32559243Sobrien 32659243Sobrien rstr = NULL; 32759243Sobrien do 32859243Sobrien if (*str == ch) 32959243Sobrien rstr = str; 33059243Sobrien while (*str++); 331145479Smp return ((Char *)(intptr_t)rstr); 33259243Sobrien} 33359243Sobrien 33459243Sobriensize_t 335167465Smps_strlen(const Char *str) 33659243Sobrien{ 337145479Smp size_t n; 33859243Sobrien 33959243Sobrien for (n = 0; *str++; n++) 34059243Sobrien continue; 34159243Sobrien return (n); 34259243Sobrien} 34359243Sobrien 34459243Sobrienint 345167465Smps_strcmp(const Char *str1, const Char *str2) 34659243Sobrien{ 34759243Sobrien for (; *str1 && *str1 == *str2; str1++, str2++) 34859243Sobrien continue; 34959243Sobrien /* 35059243Sobrien * The following case analysis is necessary so that characters which look 35159243Sobrien * negative collate low against normal characters but high against the 35259243Sobrien * end-of-string NUL. 35359243Sobrien */ 35459243Sobrien if (*str1 == '\0' && *str2 == '\0') 35559243Sobrien return (0); 35659243Sobrien else if (*str1 == '\0') 35759243Sobrien return (-1); 35859243Sobrien else if (*str2 == '\0') 35959243Sobrien return (1); 36059243Sobrien else 36159243Sobrien return (*str1 - *str2); 36259243Sobrien} 36359243Sobrien 36459243Sobrienint 365167465Smps_strncmp(const Char *str1, const Char *str2, size_t n) 36659243Sobrien{ 36759243Sobrien if (n == 0) 36859243Sobrien return (0); 36959243Sobrien do { 37059243Sobrien if (*str1 != *str2) { 37159243Sobrien /* 37259243Sobrien * The following case analysis is necessary so that characters 37359243Sobrien * which look negative collate low against normal characters 37459243Sobrien * but high against the end-of-string NUL. 37559243Sobrien */ 37659243Sobrien if (*str1 == '\0') 37759243Sobrien return (-1); 37859243Sobrien else if (*str2 == '\0') 37959243Sobrien return (1); 38059243Sobrien else 38159243Sobrien return (*str1 - *str2); 38259243Sobrien } 38359243Sobrien if (*str1 == '\0') 38459243Sobrien return(0); 38559243Sobrien str1++, str2++; 38659243Sobrien } while (--n != 0); 38759243Sobrien return(0); 38859243Sobrien} 389145479Smp#endif /* not WIDE_STRINGS */ 39059243Sobrien 391131962Smpint 392167465Smps_strcasecmp(const Char *str1, const Char *str2) 393131962Smp{ 394145479Smp#ifdef WIDE_STRINGS 395232633Smp wint_t l1 = 0, l2 = 0; 396232633Smp for (; *str1; str1++, str2++) 397232633Smp if (*str1 == *str2) 398232633Smp l1 = l2 = 0; 399232633Smp else if ((l1 = towlower(*str1)) != (l2 = towlower(*str2))) 400232633Smp break; 401145479Smp#else 402232633Smp unsigned char l1 = 0, l2 = 0; 403232633Smp for (; *str1; str1++, str2++) 404232633Smp if (*str1 == *str2) 405232633Smp l1 = l2 = 0; 406232633Smp else if ((l1 = tolower((unsigned char)*str1)) != 407232633Smp (l2 = tolower((unsigned char)*str2))) 408232633Smp break; 409145479Smp#endif 410131962Smp /* 411131962Smp * The following case analysis is necessary so that characters which look 412131962Smp * negative collate low against normal characters but high against the 413131962Smp * end-of-string NUL. 414131962Smp */ 415131962Smp if (*str1 == '\0' && *str2 == '\0') 416131962Smp return (0); 417131962Smp else if (*str1 == '\0') 418131962Smp return (-1); 419131962Smp else if (*str2 == '\0') 420131962Smp return (1); 421131962Smp else if (l1 == l2) /* They are zero when they are equal */ 422131962Smp return (*str1 - *str2); 423131962Smp else 424131962Smp return (l1 - l2); 425131962Smp} 426131962Smp 42759243SobrienChar * 428167465Smps_strnsave(const Char *s, size_t len) 42959243Sobrien{ 430167465Smp Char *n; 431167465Smp 432167465Smp n = xmalloc((len + 1) * sizeof (*n)); 433167465Smp memcpy(n, s, len * sizeof (*n)); 434167465Smp n[len] = '\0'; 435167465Smp return n; 436167465Smp} 437167465Smp 438167465SmpChar * 439167465Smps_strsave(const Char *s) 440167465Smp{ 44159243Sobrien Char *n; 442167465Smp size_t size; 44359243Sobrien 444167465Smp if (s == NULL) 44559243Sobrien s = STRNULL; 446167465Smp size = (Strlen(s) + 1) * sizeof(*n); 447167465Smp n = xmalloc(size); 448167465Smp memcpy(n, s, size); 44959243Sobrien return (n); 45059243Sobrien} 45159243Sobrien 45259243SobrienChar * 453167465Smps_strspl(const Char *cp, const Char *dp) 45459243Sobrien{ 455167465Smp Char *res, *ep; 456167465Smp const Char *p, *q; 45759243Sobrien 45859243Sobrien if (!cp) 45959243Sobrien cp = STRNULL; 46059243Sobrien if (!dp) 46159243Sobrien dp = STRNULL; 462167465Smp for (p = cp; *p++;) 46359243Sobrien continue; 464167465Smp for (q = dp; *q++;) 46559243Sobrien continue; 466167465Smp res = xmalloc(((p - cp) + (q - dp) - 1) * sizeof(Char)); 467167465Smp for (ep = res, q = cp; (*ep++ = *q++) != '\0';) 46859243Sobrien continue; 469167465Smp for (ep--, q = dp; (*ep++ = *q++) != '\0';) 47059243Sobrien continue; 471167465Smp return (res); 47259243Sobrien} 47359243Sobrien 47459243SobrienChar * 475167465Smps_strend(const Char *cp) 47659243Sobrien{ 47759243Sobrien if (!cp) 478145479Smp return ((Char *)(intptr_t) cp); 47959243Sobrien while (*cp) 48059243Sobrien cp++; 481145479Smp return ((Char *)(intptr_t) cp); 48259243Sobrien} 48359243Sobrien 48459243SobrienChar * 485167465Smps_strstr(const Char *s, const Char *t) 48659243Sobrien{ 48759243Sobrien do { 488145479Smp const Char *ss = s; 489145479Smp const Char *tt = t; 49059243Sobrien 49159243Sobrien do 49259243Sobrien if (*tt == '\0') 493145479Smp return ((Char *)(intptr_t) s); 49459243Sobrien while (*ss++ == *tt++); 49559243Sobrien } while (*s++ != '\0'); 49659243Sobrien return (NULL); 49759243Sobrien} 49859243Sobrien 499167465Smp#else /* !SHORT_STRINGS */ 500167465Smpchar * 501167465Smpcaching_strip(const char *s) 502167465Smp{ 503167465Smp static char *buf = NULL; 504167465Smp static size_t buf_size = 0; 505167465Smp size_t size; 50659243Sobrien 507167465Smp if (s == NULL) 508167465Smp return NULL; 509167465Smp size = strlen(s) + 1; 510167465Smp if (buf_size < size) { 511167465Smp buf = xrealloc(buf, size); 512167465Smp buf_size = size; 513167465Smp } 514167465Smp memcpy(buf, s, size); 515167465Smp strip(buf); 516167465Smp return buf; 517167465Smp} 518167465Smp#endif 519167465Smp 52059243Sobrienchar * 521167465Smpshort2qstr(const Char *src) 52259243Sobrien{ 52359243Sobrien static char *sdst = NULL; 52459243Sobrien static size_t dstsize = 0; 525145479Smp char *dst, *edst; 52659243Sobrien 52759243Sobrien if (src == NULL) 52859243Sobrien return (NULL); 52959243Sobrien 53059243Sobrien if (sdst == NULL) { 53159243Sobrien dstsize = MALLOC_INCR; 532167465Smp sdst = xmalloc((dstsize + MALLOC_SURPLUS) * sizeof(char)); 53359243Sobrien } 53459243Sobrien dst = sdst; 53559243Sobrien edst = &dst[dstsize]; 53659243Sobrien while (*src) { 53759243Sobrien if (*src & QUOTE) { 53859243Sobrien *dst++ = '\\'; 53959243Sobrien if (dst == edst) { 54059243Sobrien dstsize += MALLOC_INCR; 541167465Smp sdst = xrealloc(sdst, 542167465Smp (dstsize + MALLOC_SURPLUS) * sizeof(char)); 54359243Sobrien edst = &sdst[dstsize]; 54459243Sobrien dst = &edst[-MALLOC_INCR]; 54559243Sobrien } 54659243Sobrien } 547145479Smp dst += one_wctomb(dst, *src & CHAR); 548145479Smp src++; 549145479Smp if (dst >= edst) { 550195609Smp ptrdiff_t i = dst - edst; 55159243Sobrien dstsize += MALLOC_INCR; 552167465Smp sdst = xrealloc(sdst, (dstsize + MALLOC_SURPLUS) * sizeof(char)); 55359243Sobrien edst = &sdst[dstsize]; 554195609Smp dst = &edst[-MALLOC_INCR + i]; 55559243Sobrien } 55659243Sobrien } 55759243Sobrien *dst = 0; 55859243Sobrien return (sdst); 55959243Sobrien} 560167465Smp 561195609Smpstruct blk_buf * 562195609Smpbb_alloc() 563195609Smp{ 564195609Smp return xcalloc(1, sizeof(struct blk_buf)); 565195609Smp} 566195609Smp 567167465Smpstatic void 568167465Smpbb_store(struct blk_buf *bb, Char *str) 569167465Smp{ 570167465Smp if (bb->len == bb->size) { /* Keep space for terminating NULL */ 571167465Smp if (bb->size == 0) 572167465Smp bb->size = 16; /* Arbitrary */ 573167465Smp else 574167465Smp bb->size *= 2; 575167465Smp bb->vec = xrealloc(bb->vec, bb->size * sizeof (*bb->vec)); 576167465Smp } 577167465Smp bb->vec[bb->len] = str; 578167465Smp} 579167465Smp 580167465Smpvoid 581167465Smpbb_append(struct blk_buf *bb, Char *str) 582167465Smp{ 583167465Smp bb_store(bb, str); 584167465Smp bb->len++; 585167465Smp} 586167465Smp 587167465Smpvoid 588167465Smpbb_cleanup(void *xbb) 589167465Smp{ 590167465Smp struct blk_buf *bb; 591167465Smp size_t i; 592167465Smp 593167465Smp bb = xbb; 594167465Smp for (i = 0; i < bb->len; i++) 595167465Smp xfree(bb->vec[i]); 596167465Smp xfree(bb->vec); 597167465Smp} 598167465Smp 599195609Smpvoid 600195609Smpbb_free(void *bb) 601195609Smp{ 602195609Smp bb_cleanup(bb); 603195609Smp xfree(bb); 604195609Smp} 605195609Smp 606167465SmpChar ** 607167465Smpbb_finish(struct blk_buf *bb) 608167465Smp{ 609167465Smp bb_store(bb, NULL); 610167465Smp return xrealloc(bb->vec, (bb->len + 1) * sizeof (*bb->vec)); 611167465Smp} 612167465Smp 613167465Smp#define DO_STRBUF(STRBUF, CHAR, STRLEN) \ 614195609Smp \ 615195609Smpstruct STRBUF * \ 616195609SmpSTRBUF##_alloc(void) \ 617195609Smp{ \ 618195609Smp return xcalloc(1, sizeof(struct STRBUF)); \ 619195609Smp} \ 620195609Smp \ 621167465Smpstatic void \ 622167465SmpSTRBUF##_store1(struct STRBUF *buf, CHAR c) \ 623167465Smp{ \ 624167465Smp if (buf->size == buf->len) { \ 625167465Smp if (buf->size == 0) \ 626167465Smp buf->size = 64; /* Arbitrary */ \ 627167465Smp else \ 628167465Smp buf->size *= 2; \ 629167465Smp buf->s = xrealloc(buf->s, buf->size * sizeof(*buf->s)); \ 630167465Smp } \ 631232633Smp assert(buf->s); \ 632167465Smp buf->s[buf->len] = c; \ 633167465Smp} \ 634167465Smp \ 635167465Smp/* Like strbuf_append1(buf, '\0'), but don't advance len */ \ 636167465Smpvoid \ 637167465SmpSTRBUF##_terminate(struct STRBUF *buf) \ 638167465Smp{ \ 639167465Smp STRBUF##_store1(buf, '\0'); \ 640167465Smp} \ 641167465Smp \ 642167465Smpvoid \ 643167465SmpSTRBUF##_append1(struct STRBUF *buf, CHAR c) \ 644167465Smp{ \ 645167465Smp STRBUF##_store1(buf, c); \ 646167465Smp buf->len++; \ 647167465Smp} \ 648167465Smp \ 649167465Smpvoid \ 650167465SmpSTRBUF##_appendn(struct STRBUF *buf, const CHAR *s, size_t len) \ 651167465Smp{ \ 652167465Smp if (buf->size < buf->len + len) { \ 653167465Smp if (buf->size == 0) \ 654167465Smp buf->size = 64; /* Arbitrary */ \ 655167465Smp while (buf->size < buf->len + len) \ 656167465Smp buf->size *= 2; \ 657167465Smp buf->s = xrealloc(buf->s, buf->size * sizeof(*buf->s)); \ 658167465Smp } \ 659167465Smp memcpy(buf->s + buf->len, s, len * sizeof(*buf->s)); \ 660167465Smp buf->len += len; \ 661167465Smp} \ 662167465Smp \ 663167465Smpvoid \ 664167465SmpSTRBUF##_append(struct STRBUF *buf, const CHAR *s) \ 665167465Smp{ \ 666167465Smp STRBUF##_appendn(buf, s, STRLEN(s)); \ 667167465Smp} \ 668167465Smp \ 669167465SmpCHAR * \ 670167465SmpSTRBUF##_finish(struct STRBUF *buf) \ 671167465Smp{ \ 672167465Smp STRBUF##_append1(buf, 0); \ 673167465Smp return xrealloc(buf->s, buf->len * sizeof(*buf->s)); \ 674167465Smp} \ 675167465Smp \ 676167465Smpvoid \ 677167465SmpSTRBUF##_cleanup(void *xbuf) \ 678167465Smp{ \ 679167465Smp struct STRBUF *buf; \ 680167465Smp \ 681167465Smp buf = xbuf; \ 682167465Smp xfree(buf->s); \ 683167465Smp} \ 684167465Smp \ 685195609Smpvoid \ 686195609SmpSTRBUF##_free(void *xbuf) \ 687195609Smp{ \ 688195609Smp STRBUF##_cleanup(xbuf); \ 689195609Smp xfree(xbuf); \ 690195609Smp} \ 691195609Smp \ 692167465Smpconst struct STRBUF STRBUF##_init /* = STRBUF##_INIT; */ 693167465Smp 694167465SmpDO_STRBUF(strbuf, char, strlen); 695167465SmpDO_STRBUF(Strbuf, Char, Strlen); 696