tc.str.c revision 167465
1167465Smp/* $Header: /p/tcsh/cvsroot/tcsh/tc.str.c,v 3.26 2006/03/02 18:46:45 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 36145479Smp#include <limits.h> 3759243Sobrien 38167465SmpRCSID("$tcsh: tc.str.c,v 3.26 2006/03/02 18:46:45 christos Exp $") 39145479Smp 4059243Sobrien#define MALLOC_INCR 128 41145479Smp#ifdef WIDE_STRINGS 42145479Smp#define MALLOC_SURPLUS MB_LEN_MAX /* Space for one multibyte character */ 43145479Smp#else 44145479Smp#define MALLOC_SURPLUS 0 45145479Smp#endif 4659243Sobrien 47145479Smp#ifdef WIDE_STRINGS 48145479Smpsize_t 49145479Smpone_mbtowc(wchar_t *pwc, const char *s, size_t n) 50145479Smp{ 51145479Smp int len; 52145479Smp 53145479Smp len = rt_mbtowc(pwc, s, n); 54145479Smp if (len == -1) { 55145479Smp mbtowc(NULL, NULL, 0); 56145479Smp *pwc = (unsigned char)*s | INVALID_BYTE; 57145479Smp } 58145479Smp if (len <= 0) 59145479Smp len = 1; 60145479Smp return len; 61145479Smp} 62145479Smp 63145479Smpsize_t 64145479Smpone_wctomb(char *s, wchar_t wchar) 65145479Smp{ 66145479Smp int len; 67145479Smp 68145479Smp if (wchar & INVALID_BYTE) { 69145479Smp s[0] = wchar & 0xFF; 70145479Smp len = 1; 71145479Smp } else { 72145479Smp len = wctomb(s, wchar); 73145479Smp if (len == -1) 74145479Smp s[0] = wchar; 75145479Smp if (len <= 0) 76145479Smp len = 1; 77145479Smp } 78145479Smp return len; 79145479Smp} 80167465Smp 81145479Smpint 82145479Smprt_mbtowc(wchar_t *pwc, const char *s, size_t n) 83145479Smp{ 84145479Smp int ret; 85145479Smp char back[MB_LEN_MAX]; 86145479Smp 87145479Smp ret = mbtowc(pwc, s, n); 88145479Smp if (ret > 0 && (wctomb(back, *pwc) != ret || memcmp(s, back, ret) != 0)) 89145479Smp ret = -1; 90145479Smp return ret; 91145479Smp} 92167465Smp#endif 93145479Smp 94167465Smp#ifdef SHORT_STRINGS 9559243SobrienChar ** 96167465Smpblk2short(char **src) 9759243Sobrien{ 9859243Sobrien size_t n; 99145479Smp Char **sdst, **dst; 10059243Sobrien 10159243Sobrien /* 10259243Sobrien * Count 10359243Sobrien */ 10459243Sobrien for (n = 0; src[n] != NULL; n++) 10559243Sobrien continue; 106167465Smp sdst = dst = xmalloc((n + 1) * sizeof(Char *)); 10759243Sobrien 10859243Sobrien for (; *src != NULL; src++) 10959243Sobrien *dst++ = SAVE(*src); 11059243Sobrien *dst = NULL; 11159243Sobrien return (sdst); 11259243Sobrien} 11359243Sobrien 11459243Sobrienchar ** 115167465Smpshort2blk(Char **src) 11659243Sobrien{ 11759243Sobrien size_t n; 118145479Smp char **sdst, **dst; 11959243Sobrien 12059243Sobrien /* 12159243Sobrien * Count 12259243Sobrien */ 12359243Sobrien for (n = 0; src[n] != NULL; n++) 12459243Sobrien continue; 125167465Smp sdst = dst = xmalloc((n + 1) * sizeof(char *)); 12659243Sobrien 12759243Sobrien for (; *src != NULL; src++) 12859243Sobrien *dst++ = strsave(short2str(*src)); 12959243Sobrien *dst = NULL; 13059243Sobrien return (sdst); 13159243Sobrien} 13259243Sobrien 13359243SobrienChar * 134167465Smpstr2short(const char *src) 13559243Sobrien{ 136167465Smp static struct Strbuf buf; /* = Strbuf_INIT; */ 13759243Sobrien 13859243Sobrien if (src == NULL) 13959243Sobrien return (NULL); 14059243Sobrien 141167465Smp buf.len = 0; 142167465Smp while (*src) { 143167465Smp Char wc; 14459243Sobrien 145167465Smp src += one_mbtowc(&wc, src, MB_LEN_MAX); 146167465Smp Strbuf_append1(&buf, wc); 14759243Sobrien } 148167465Smp Strbuf_terminate(&buf); 149167465Smp return buf.s; 15059243Sobrien} 15159243Sobrien 15259243Sobrienchar * 153167465Smpshort2str(const Char *src) 15459243Sobrien{ 15559243Sobrien static char *sdst = NULL; 15659243Sobrien static size_t dstsize = 0; 157145479Smp char *dst, *edst; 15859243Sobrien 15959243Sobrien if (src == NULL) 16059243Sobrien return (NULL); 16159243Sobrien 16259243Sobrien if (sdst == NULL) { 16359243Sobrien dstsize = MALLOC_INCR; 164167465Smp sdst = xmalloc((dstsize + MALLOC_SURPLUS) * sizeof(char)); 16559243Sobrien } 16659243Sobrien dst = sdst; 16759243Sobrien edst = &dst[dstsize]; 16859243Sobrien while (*src) { 169145479Smp dst += one_wctomb(dst, *src & CHAR); 170145479Smp src++; 171145479Smp if (dst >= edst) { 17259243Sobrien dstsize += MALLOC_INCR; 173167465Smp sdst = xrealloc(sdst, (dstsize + MALLOC_SURPLUS) * sizeof(char)); 17459243Sobrien edst = &sdst[dstsize]; 17559243Sobrien dst = &edst[-MALLOC_INCR]; 17659243Sobrien } 17759243Sobrien } 17859243Sobrien *dst = 0; 17959243Sobrien return (sdst); 18059243Sobrien} 18159243Sobrien 182145479Smp#ifndef WIDE_STRINGS 18359243SobrienChar * 184167465Smps_strcpy(Char *dst, const Char *src) 18559243Sobrien{ 186145479Smp Char *sdst; 18759243Sobrien 18859243Sobrien sdst = dst; 18959243Sobrien while ((*dst++ = *src++) != '\0') 19059243Sobrien continue; 19159243Sobrien return (sdst); 19259243Sobrien} 19359243Sobrien 19459243SobrienChar * 195167465Smps_strncpy(Char *dst, const Char *src, size_t n) 19659243Sobrien{ 197145479Smp Char *sdst; 19859243Sobrien 19959243Sobrien if (n == 0) 20059243Sobrien return(dst); 20159243Sobrien 20259243Sobrien sdst = dst; 20359243Sobrien do 20459243Sobrien if ((*dst++ = *src++) == '\0') { 20559243Sobrien while (--n != 0) 20659243Sobrien *dst++ = '\0'; 20759243Sobrien return(sdst); 20859243Sobrien } 20959243Sobrien while (--n != 0); 21059243Sobrien return (sdst); 21159243Sobrien} 21259243Sobrien 21359243SobrienChar * 214167465Smps_strcat(Char *dst, const Char *src) 21559243Sobrien{ 216167465Smp Strcpy(Strend(dst), src); 217167465Smp return dst; 21859243Sobrien} 21959243Sobrien 22059243Sobrien#ifdef NOTUSED 22159243SobrienChar * 222167465Smps_strncat(Char *dst, const Char *src, size_t n) 22359243Sobrien{ 224145479Smp Char *sdst; 22559243Sobrien 22659243Sobrien if (n == 0) 22759243Sobrien return (dst); 22859243Sobrien 22959243Sobrien sdst = dst; 23059243Sobrien 231167465Smp while (*dst) 232167465Smp dst++; 23359243Sobrien 23459243Sobrien do 23559243Sobrien if ((*dst++ = *src++) == '\0') 23659243Sobrien return(sdst); 23759243Sobrien while (--n != 0) 23859243Sobrien continue; 23959243Sobrien 24059243Sobrien *dst = '\0'; 24159243Sobrien return (sdst); 24259243Sobrien} 24359243Sobrien 24459243Sobrien#endif 24559243Sobrien 24659243SobrienChar * 247167465Smps_strchr(const Char *str, int ch) 24859243Sobrien{ 24959243Sobrien do 25059243Sobrien if (*str == ch) 251145479Smp return ((Char *)(intptr_t)str); 25259243Sobrien while (*str++); 25359243Sobrien return (NULL); 25459243Sobrien} 25559243Sobrien 25659243SobrienChar * 257167465Smps_strrchr(const Char *str, int ch) 25859243Sobrien{ 259145479Smp const Char *rstr; 26059243Sobrien 26159243Sobrien rstr = NULL; 26259243Sobrien do 26359243Sobrien if (*str == ch) 26459243Sobrien rstr = str; 26559243Sobrien while (*str++); 266145479Smp return ((Char *)(intptr_t)rstr); 26759243Sobrien} 26859243Sobrien 26959243Sobriensize_t 270167465Smps_strlen(const Char *str) 27159243Sobrien{ 272145479Smp size_t n; 27359243Sobrien 27459243Sobrien for (n = 0; *str++; n++) 27559243Sobrien continue; 27659243Sobrien return (n); 27759243Sobrien} 27859243Sobrien 27959243Sobrienint 280167465Smps_strcmp(const Char *str1, const Char *str2) 28159243Sobrien{ 28259243Sobrien for (; *str1 && *str1 == *str2; str1++, str2++) 28359243Sobrien continue; 28459243Sobrien /* 28559243Sobrien * The following case analysis is necessary so that characters which look 28659243Sobrien * negative collate low against normal characters but high against the 28759243Sobrien * end-of-string NUL. 28859243Sobrien */ 28959243Sobrien if (*str1 == '\0' && *str2 == '\0') 29059243Sobrien return (0); 29159243Sobrien else if (*str1 == '\0') 29259243Sobrien return (-1); 29359243Sobrien else if (*str2 == '\0') 29459243Sobrien return (1); 29559243Sobrien else 29659243Sobrien return (*str1 - *str2); 29759243Sobrien} 29859243Sobrien 29959243Sobrienint 300167465Smps_strncmp(const Char *str1, const Char *str2, size_t n) 30159243Sobrien{ 30259243Sobrien if (n == 0) 30359243Sobrien return (0); 30459243Sobrien do { 30559243Sobrien if (*str1 != *str2) { 30659243Sobrien /* 30759243Sobrien * The following case analysis is necessary so that characters 30859243Sobrien * which look negative collate low against normal characters 30959243Sobrien * but high against the end-of-string NUL. 31059243Sobrien */ 31159243Sobrien if (*str1 == '\0') 31259243Sobrien return (-1); 31359243Sobrien else if (*str2 == '\0') 31459243Sobrien return (1); 31559243Sobrien else 31659243Sobrien return (*str1 - *str2); 31759243Sobrien } 31859243Sobrien if (*str1 == '\0') 31959243Sobrien return(0); 32059243Sobrien str1++, str2++; 32159243Sobrien } while (--n != 0); 32259243Sobrien return(0); 32359243Sobrien} 324145479Smp#endif /* not WIDE_STRINGS */ 32559243Sobrien 326131962Smpint 327167465Smps_strcasecmp(const Char *str1, const Char *str2) 328131962Smp{ 329145479Smp#ifdef WIDE_STRINGS 330145479Smp wchar_t l1 = 0, l2 = 0; 331145479Smp for (; *str1 && ((*str1 == *str2 && (l1 = l2 = 0) == 0) || 332145479Smp (l1 = towlower(*str1)) == (l2 = towlower(*str2))); str1++, str2++) 333145479Smp continue; 334145479Smp 335145479Smp#else 336131962Smp unsigned char c1, c2, l1 = 0, l2 = 0; 337131962Smp for (; *str1 && ((*str1 == *str2 && (l1 = l2 = 0) == 0) || 338131962Smp ((c1 = (unsigned char)*str1) == *str1 && 339131962Smp (c2 = (unsigned char)*str2) == *str2 && 340131962Smp (l1 = tolower(c1)) == (l2 = tolower(c2)))); str1++, str2++) 341131962Smp continue; 342145479Smp#endif 343131962Smp /* 344131962Smp * The following case analysis is necessary so that characters which look 345131962Smp * negative collate low against normal characters but high against the 346131962Smp * end-of-string NUL. 347131962Smp */ 348131962Smp if (*str1 == '\0' && *str2 == '\0') 349131962Smp return (0); 350131962Smp else if (*str1 == '\0') 351131962Smp return (-1); 352131962Smp else if (*str2 == '\0') 353131962Smp return (1); 354131962Smp else if (l1 == l2) /* They are zero when they are equal */ 355131962Smp return (*str1 - *str2); 356131962Smp else 357131962Smp return (l1 - l2); 358131962Smp} 359131962Smp 36059243SobrienChar * 361167465Smps_strnsave(const Char *s, size_t len) 36259243Sobrien{ 363167465Smp Char *n; 364167465Smp 365167465Smp n = xmalloc((len + 1) * sizeof (*n)); 366167465Smp memcpy(n, s, len * sizeof (*n)); 367167465Smp n[len] = '\0'; 368167465Smp return n; 369167465Smp} 370167465Smp 371167465SmpChar * 372167465Smps_strsave(const Char *s) 373167465Smp{ 37459243Sobrien Char *n; 375167465Smp size_t size; 37659243Sobrien 377167465Smp if (s == NULL) 37859243Sobrien s = STRNULL; 379167465Smp size = (Strlen(s) + 1) * sizeof(*n); 380167465Smp n = xmalloc(size); 381167465Smp memcpy(n, s, size); 38259243Sobrien return (n); 38359243Sobrien} 38459243Sobrien 38559243SobrienChar * 386167465Smps_strspl(const Char *cp, const Char *dp) 38759243Sobrien{ 388167465Smp Char *res, *ep; 389167465Smp const Char *p, *q; 39059243Sobrien 39159243Sobrien if (!cp) 39259243Sobrien cp = STRNULL; 39359243Sobrien if (!dp) 39459243Sobrien dp = STRNULL; 395167465Smp for (p = cp; *p++;) 39659243Sobrien continue; 397167465Smp for (q = dp; *q++;) 39859243Sobrien continue; 399167465Smp res = xmalloc(((p - cp) + (q - dp) - 1) * sizeof(Char)); 400167465Smp for (ep = res, q = cp; (*ep++ = *q++) != '\0';) 40159243Sobrien continue; 402167465Smp for (ep--, q = dp; (*ep++ = *q++) != '\0';) 40359243Sobrien continue; 404167465Smp return (res); 40559243Sobrien} 40659243Sobrien 40759243SobrienChar * 408167465Smps_strend(const Char *cp) 40959243Sobrien{ 41059243Sobrien if (!cp) 411145479Smp return ((Char *)(intptr_t) cp); 41259243Sobrien while (*cp) 41359243Sobrien cp++; 414145479Smp return ((Char *)(intptr_t) cp); 41559243Sobrien} 41659243Sobrien 41759243SobrienChar * 418167465Smps_strstr(const Char *s, const Char *t) 41959243Sobrien{ 42059243Sobrien do { 421145479Smp const Char *ss = s; 422145479Smp const Char *tt = t; 42359243Sobrien 42459243Sobrien do 42559243Sobrien if (*tt == '\0') 426145479Smp return ((Char *)(intptr_t) s); 42759243Sobrien while (*ss++ == *tt++); 42859243Sobrien } while (*s++ != '\0'); 42959243Sobrien return (NULL); 43059243Sobrien} 43159243Sobrien 432167465Smp#else /* !SHORT_STRINGS */ 433167465Smpchar * 434167465Smpcaching_strip(const char *s) 435167465Smp{ 436167465Smp static char *buf = NULL; 437167465Smp static size_t buf_size = 0; 438167465Smp size_t size; 43959243Sobrien 440167465Smp if (s == NULL) 441167465Smp return NULL; 442167465Smp size = strlen(s) + 1; 443167465Smp if (buf_size < size) { 444167465Smp buf = xrealloc(buf, size); 445167465Smp buf_size = size; 446167465Smp } 447167465Smp memcpy(buf, s, size); 448167465Smp strip(buf); 449167465Smp return buf; 450167465Smp} 451167465Smp#endif 452167465Smp 45359243Sobrienchar * 454167465Smpshort2qstr(const Char *src) 45559243Sobrien{ 45659243Sobrien static char *sdst = NULL; 45759243Sobrien static size_t dstsize = 0; 458145479Smp char *dst, *edst; 45959243Sobrien 46059243Sobrien if (src == NULL) 46159243Sobrien return (NULL); 46259243Sobrien 46359243Sobrien if (sdst == NULL) { 46459243Sobrien dstsize = MALLOC_INCR; 465167465Smp sdst = xmalloc((dstsize + MALLOC_SURPLUS) * sizeof(char)); 46659243Sobrien } 46759243Sobrien dst = sdst; 46859243Sobrien edst = &dst[dstsize]; 46959243Sobrien while (*src) { 47059243Sobrien if (*src & QUOTE) { 47159243Sobrien *dst++ = '\\'; 47259243Sobrien if (dst == edst) { 47359243Sobrien dstsize += MALLOC_INCR; 474167465Smp sdst = xrealloc(sdst, 475167465Smp (dstsize + MALLOC_SURPLUS) * sizeof(char)); 47659243Sobrien edst = &sdst[dstsize]; 47759243Sobrien dst = &edst[-MALLOC_INCR]; 47859243Sobrien } 47959243Sobrien } 480145479Smp dst += one_wctomb(dst, *src & CHAR); 481145479Smp src++; 482145479Smp if (dst >= edst) { 48359243Sobrien dstsize += MALLOC_INCR; 484167465Smp sdst = xrealloc(sdst, (dstsize + MALLOC_SURPLUS) * sizeof(char)); 48559243Sobrien edst = &sdst[dstsize]; 48659243Sobrien dst = &edst[-MALLOC_INCR]; 48759243Sobrien } 48859243Sobrien } 48959243Sobrien *dst = 0; 49059243Sobrien return (sdst); 49159243Sobrien} 492167465Smp 493167465Smpstatic void 494167465Smpbb_store(struct blk_buf *bb, Char *str) 495167465Smp{ 496167465Smp if (bb->len == bb->size) { /* Keep space for terminating NULL */ 497167465Smp if (bb->size == 0) 498167465Smp bb->size = 16; /* Arbitrary */ 499167465Smp else 500167465Smp bb->size *= 2; 501167465Smp bb->vec = xrealloc(bb->vec, bb->size * sizeof (*bb->vec)); 502167465Smp } 503167465Smp bb->vec[bb->len] = str; 504167465Smp} 505167465Smp 506167465Smpvoid 507167465Smpbb_append(struct blk_buf *bb, Char *str) 508167465Smp{ 509167465Smp bb_store(bb, str); 510167465Smp bb->len++; 511167465Smp} 512167465Smp 513167465Smpvoid 514167465Smpbb_cleanup(void *xbb) 515167465Smp{ 516167465Smp struct blk_buf *bb; 517167465Smp size_t i; 518167465Smp 519167465Smp bb = xbb; 520167465Smp for (i = 0; i < bb->len; i++) 521167465Smp xfree(bb->vec[i]); 522167465Smp xfree(bb->vec); 523167465Smp} 524167465Smp 525167465SmpChar ** 526167465Smpbb_finish(struct blk_buf *bb) 527167465Smp{ 528167465Smp bb_store(bb, NULL); 529167465Smp return xrealloc(bb->vec, (bb->len + 1) * sizeof (*bb->vec)); 530167465Smp} 531167465Smp 532167465Smp#define DO_STRBUF(STRBUF, CHAR, STRLEN) \ 533167465Smpstatic void \ 534167465SmpSTRBUF##_store1(struct STRBUF *buf, CHAR c) \ 535167465Smp{ \ 536167465Smp if (buf->size == buf->len) { \ 537167465Smp if (buf->size == 0) \ 538167465Smp buf->size = 64; /* Arbitrary */ \ 539167465Smp else \ 540167465Smp buf->size *= 2; \ 541167465Smp buf->s = xrealloc(buf->s, buf->size * sizeof(*buf->s)); \ 542167465Smp } \ 543167465Smp buf->s[buf->len] = c; \ 544167465Smp} \ 545167465Smp \ 546167465Smp/* Like strbuf_append1(buf, '\0'), but don't advance len */ \ 547167465Smpvoid \ 548167465SmpSTRBUF##_terminate(struct STRBUF *buf) \ 549167465Smp{ \ 550167465Smp STRBUF##_store1(buf, '\0'); \ 551167465Smp} \ 552167465Smp \ 553167465Smpvoid \ 554167465SmpSTRBUF##_append1(struct STRBUF *buf, CHAR c) \ 555167465Smp{ \ 556167465Smp STRBUF##_store1(buf, c); \ 557167465Smp buf->len++; \ 558167465Smp} \ 559167465Smp \ 560167465Smpvoid \ 561167465SmpSTRBUF##_appendn(struct STRBUF *buf, const CHAR *s, size_t len) \ 562167465Smp{ \ 563167465Smp if (buf->size < buf->len + len) { \ 564167465Smp if (buf->size == 0) \ 565167465Smp buf->size = 64; /* Arbitrary */ \ 566167465Smp while (buf->size < buf->len + len) \ 567167465Smp buf->size *= 2; \ 568167465Smp buf->s = xrealloc(buf->s, buf->size * sizeof(*buf->s)); \ 569167465Smp } \ 570167465Smp memcpy(buf->s + buf->len, s, len * sizeof(*buf->s)); \ 571167465Smp buf->len += len; \ 572167465Smp} \ 573167465Smp \ 574167465Smpvoid \ 575167465SmpSTRBUF##_append(struct STRBUF *buf, const CHAR *s) \ 576167465Smp{ \ 577167465Smp STRBUF##_appendn(buf, s, STRLEN(s)); \ 578167465Smp} \ 579167465Smp \ 580167465SmpCHAR * \ 581167465SmpSTRBUF##_finish(struct STRBUF *buf) \ 582167465Smp{ \ 583167465Smp STRBUF##_append1(buf, 0); \ 584167465Smp return xrealloc(buf->s, buf->len * sizeof(*buf->s)); \ 585167465Smp} \ 586167465Smp \ 587167465Smpvoid \ 588167465SmpSTRBUF##_cleanup(void *xbuf) \ 589167465Smp{ \ 590167465Smp struct STRBUF *buf; \ 591167465Smp \ 592167465Smp buf = xbuf; \ 593167465Smp xfree(buf->s); \ 594167465Smp} \ 595167465Smp \ 596167465Smpconst struct STRBUF STRBUF##_init /* = STRBUF##_INIT; */ 597167465Smp 598167465SmpDO_STRBUF(strbuf, char, strlen); 599167465SmpDO_STRBUF(Strbuf, Char, Strlen); 600