xref: /freebsd-src/contrib/tcsh/tc.str.c (revision 6560ac57ce879857203bc456cdc3849808dc0700)
1c80476e4SDavid E. O'Brien /*
2c80476e4SDavid E. O'Brien  * tc.str.c: Short string package
3c80476e4SDavid E. O'Brien  * 	     This has been a lesson of how to write buggy code!
4c80476e4SDavid E. O'Brien  */
5c80476e4SDavid E. O'Brien /*-
6c80476e4SDavid E. O'Brien  * Copyright (c) 1980, 1991 The Regents of the University of California.
7c80476e4SDavid E. O'Brien  * All rights reserved.
8c80476e4SDavid E. O'Brien  *
9c80476e4SDavid E. O'Brien  * Redistribution and use in source and binary forms, with or without
10c80476e4SDavid E. O'Brien  * modification, are permitted provided that the following conditions
11c80476e4SDavid E. O'Brien  * are met:
12c80476e4SDavid E. O'Brien  * 1. Redistributions of source code must retain the above copyright
13c80476e4SDavid E. O'Brien  *    notice, this list of conditions and the following disclaimer.
14c80476e4SDavid E. O'Brien  * 2. Redistributions in binary form must reproduce the above copyright
15c80476e4SDavid E. O'Brien  *    notice, this list of conditions and the following disclaimer in the
16c80476e4SDavid E. O'Brien  *    documentation and/or other materials provided with the distribution.
1729301572SMark Peek  * 3. Neither the name of the University nor the names of its contributors
18c80476e4SDavid E. O'Brien  *    may be used to endorse or promote products derived from this software
19c80476e4SDavid E. O'Brien  *    without specific prior written permission.
20c80476e4SDavid E. O'Brien  *
21c80476e4SDavid E. O'Brien  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22c80476e4SDavid E. O'Brien  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23c80476e4SDavid E. O'Brien  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24c80476e4SDavid E. O'Brien  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25c80476e4SDavid E. O'Brien  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26c80476e4SDavid E. O'Brien  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27c80476e4SDavid E. O'Brien  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28c80476e4SDavid E. O'Brien  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29c80476e4SDavid E. O'Brien  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30c80476e4SDavid E. O'Brien  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31c80476e4SDavid E. O'Brien  * SUCH DAMAGE.
32c80476e4SDavid E. O'Brien  */
33c80476e4SDavid E. O'Brien #include "sh.h"
34c80476e4SDavid E. O'Brien 
359ccc37e3SMark Peek #include <assert.h>
3623338178SMark Peek #include <limits.h>
3723338178SMark Peek 
38c80476e4SDavid E. O'Brien #define MALLOC_INCR	128
3923338178SMark Peek #ifdef WIDE_STRINGS
4023338178SMark Peek #define MALLOC_SURPLUS	MB_LEN_MAX /* Space for one multibyte character */
4123338178SMark Peek #else
4223338178SMark Peek #define MALLOC_SURPLUS	0
4323338178SMark Peek #endif
4423338178SMark Peek 
4523338178SMark Peek #ifdef WIDE_STRINGS
4623338178SMark Peek size_t
one_mbtowc(Char * pwc,const char * s,size_t n)479ccc37e3SMark Peek one_mbtowc(Char *pwc, const char *s, size_t n)
4823338178SMark Peek {
4923338178SMark Peek     int len;
5023338178SMark Peek 
5123338178SMark Peek     len = rt_mbtowc(pwc, s, n);
5223338178SMark Peek     if (len == -1) {
53a15e6f9aSMark Peek         reset_mbtowc();
5423338178SMark Peek 	*pwc = (unsigned char)*s | INVALID_BYTE;
5523338178SMark Peek     }
5623338178SMark Peek     if (len <= 0)
5723338178SMark Peek 	len = 1;
5823338178SMark Peek     return len;
5923338178SMark Peek }
6023338178SMark Peek 
6123338178SMark Peek size_t
one_wctomb(char * s,Char wchar)629ccc37e3SMark Peek one_wctomb(char *s, Char wchar)
6323338178SMark Peek {
6423338178SMark Peek     int len;
6523338178SMark Peek 
66*19d2e3deSDmitry Chagin #if INVALID_BYTE != 0
67*19d2e3deSDmitry Chagin     if ((wchar & INVALID_BYTE) == INVALID_BYTE) {    /* wchar >= INVALID_BYTE */
68*19d2e3deSDmitry Chagin 	/* invalid char
69*19d2e3deSDmitry Chagin 	 * exmaple)
70*19d2e3deSDmitry Chagin 	 * if wchar = f0000090(=90|INVALID_BYTE), then *s = ffffff90 */
71*19d2e3deSDmitry Chagin 	*s = (char)wchar;
7223338178SMark Peek 	len = 1;
73*19d2e3deSDmitry Chagin #else
74*19d2e3deSDmitry Chagin     if (wchar & (CHAR & INVALID_BYTE)) {
75*19d2e3deSDmitry Chagin 	s[0] = wchar & (CHAR & 0xFF);
76*19d2e3deSDmitry Chagin 	len = 1;
77*19d2e3deSDmitry Chagin #endif
7823338178SMark Peek     } else {
79*19d2e3deSDmitry Chagin #if INVALID_BYTE != 0
80*19d2e3deSDmitry Chagin 	wchar &= MAX_UTF32;
81*19d2e3deSDmitry Chagin #else
82*19d2e3deSDmitry Chagin 	wchar &= CHAR;
83*19d2e3deSDmitry Chagin #endif
849ccc37e3SMark Peek #ifdef UTF16_STRINGS
859ccc37e3SMark Peek 	if (wchar >= 0x10000) {
869ccc37e3SMark Peek 	    /* UTF-16 systems can't handle these values directly in calls to
879ccc37e3SMark Peek 	       wctomb.  Convert value to UTF-16 surrogate and call wcstombs to
889ccc37e3SMark Peek 	       convert the "string" to the correct multibyte representation,
899ccc37e3SMark Peek 	       if any. */
909ccc37e3SMark Peek 	    wchar_t ws[3];
919ccc37e3SMark Peek 	    wchar -= 0x10000;
929ccc37e3SMark Peek 	    ws[0] = 0xd800 | (wchar >> 10);
939ccc37e3SMark Peek 	    ws[1] = 0xdc00 | (wchar & 0x3ff);
949ccc37e3SMark Peek 	    ws[2] = 0;
959ccc37e3SMark Peek 	    /* The return value of wcstombs excludes the trailing 0, so len is
969ccc37e3SMark Peek 	       the correct number of multibytes for the Unicode char. */
979ccc37e3SMark Peek 	    len = wcstombs (s, ws, MB_CUR_MAX + 1);
989ccc37e3SMark Peek 	} else
999ccc37e3SMark Peek #endif
1009ccc37e3SMark Peek 	len = wctomb(s, (wchar_t) wchar);
10123338178SMark Peek 	if (len == -1)
10223338178SMark Peek 	    s[0] = wchar;
10323338178SMark Peek 	if (len <= 0)
10423338178SMark Peek 	    len = 1;
10523338178SMark Peek     }
10623338178SMark Peek     return len;
10723338178SMark Peek }
108c80476e4SDavid E. O'Brien 
10923338178SMark Peek int
1109ccc37e3SMark Peek rt_mbtowc(Char *pwc, const char *s, size_t n)
11123338178SMark Peek {
11223338178SMark Peek     int ret;
11323338178SMark Peek     char back[MB_LEN_MAX];
1149ccc37e3SMark Peek     wchar_t tmp;
1159ccc37e3SMark Peek #if defined(UTF16_STRINGS) && defined(HAVE_MBRTOWC)
1169ccc37e3SMark Peek # if defined(AUTOSET_KANJI)
1179ccc37e3SMark Peek     static mbstate_t mb_zero, mb;
1189ccc37e3SMark Peek     /*
1199ccc37e3SMark Peek      * Workaround the Shift-JIS endcoding that translates unshifted 7 bit ASCII!
1209ccc37e3SMark Peek      */
1219ccc37e3SMark Peek     if (!adrof(STRnokanji) && n && pwc && s && (*s == '\\' || *s == '~') &&
1229ccc37e3SMark Peek 	!memcmp(&mb, &mb_zero, sizeof(mb)))
1239ccc37e3SMark Peek     {
1249ccc37e3SMark Peek 	*pwc = *s;
1259ccc37e3SMark Peek 	return 1;
1269ccc37e3SMark Peek     }
1279ccc37e3SMark Peek # else
1289ccc37e3SMark Peek     mbstate_t mb;
1299ccc37e3SMark Peek # endif
13023338178SMark Peek 
1319ccc37e3SMark Peek     memset (&mb, 0, sizeof mb);
1329ccc37e3SMark Peek     ret = mbrtowc(&tmp, s, n, &mb);
1339ccc37e3SMark Peek #else
1349ccc37e3SMark Peek     ret = mbtowc(&tmp, s, n);
1359ccc37e3SMark Peek #endif
1369ccc37e3SMark Peek     if (ret > 0) {
1379ccc37e3SMark Peek 	*pwc = tmp;
1389ccc37e3SMark Peek #if defined(UTF16_STRINGS) && defined(HAVE_MBRTOWC)
1399ccc37e3SMark Peek 	if (tmp >= 0xd800 && tmp <= 0xdbff) {
1409ccc37e3SMark Peek 	    /* UTF-16 surrogate pair.  Fetch second half and compute
1419ccc37e3SMark Peek 	       UTF-32 value.  Dispense with the inverse test in this case. */
1429ccc37e3SMark Peek 	    size_t n2 = mbrtowc(&tmp, s + ret, n - ret, &mb);
1439ccc37e3SMark Peek 	    if (n2 == 0 || n2 == (size_t)-1 || n2 == (size_t)-2)
14423338178SMark Peek 		ret = -1;
1459ccc37e3SMark Peek 	    else {
1469ccc37e3SMark Peek 		*pwc = (((*pwc & 0x3ff) << 10) | (tmp & 0x3ff)) + 0x10000;
1479ccc37e3SMark Peek 		ret += n2;
1489ccc37e3SMark Peek 	    }
1499ccc37e3SMark Peek 	} else
1509ccc37e3SMark Peek #endif
1519ccc37e3SMark Peek       	if (wctomb(back, *pwc) != ret || memcmp(s, back, ret) != 0)
1529ccc37e3SMark Peek 	    ret = -1;
1539ccc37e3SMark Peek 
1549ccc37e3SMark Peek     } else if (ret == -2)
1559ccc37e3SMark Peek 	ret = -1;
1569ccc37e3SMark Peek     else if (ret == 0)
1579ccc37e3SMark Peek 	*pwc = '\0';
1589ccc37e3SMark Peek 
15923338178SMark Peek     return ret;
16023338178SMark Peek }
16145e5710bSMark Peek #endif
16223338178SMark Peek 
16345e5710bSMark Peek #ifdef SHORT_STRINGS
164c80476e4SDavid E. O'Brien Char  **
16545e5710bSMark Peek blk2short(char **src)
166c80476e4SDavid E. O'Brien {
167c80476e4SDavid E. O'Brien     size_t     n;
16823338178SMark Peek     Char **sdst, **dst;
169c80476e4SDavid E. O'Brien 
170c80476e4SDavid E. O'Brien     /*
171c80476e4SDavid E. O'Brien      * Count
172c80476e4SDavid E. O'Brien      */
173c80476e4SDavid E. O'Brien     for (n = 0; src[n] != NULL; n++)
174c80476e4SDavid E. O'Brien 	continue;
17545e5710bSMark Peek     sdst = dst = xmalloc((n + 1) * sizeof(Char *));
176c80476e4SDavid E. O'Brien 
177c80476e4SDavid E. O'Brien     for (; *src != NULL; src++)
178c80476e4SDavid E. O'Brien 	*dst++ = SAVE(*src);
179c80476e4SDavid E. O'Brien     *dst = NULL;
180c80476e4SDavid E. O'Brien     return (sdst);
181c80476e4SDavid E. O'Brien }
182c80476e4SDavid E. O'Brien 
183c80476e4SDavid E. O'Brien char  **
18445e5710bSMark Peek short2blk(Char **src)
185c80476e4SDavid E. O'Brien {
186c80476e4SDavid E. O'Brien     size_t     n;
18723338178SMark Peek     char **sdst, **dst;
188c80476e4SDavid E. O'Brien 
189c80476e4SDavid E. O'Brien     /*
190c80476e4SDavid E. O'Brien      * Count
191c80476e4SDavid E. O'Brien      */
192c80476e4SDavid E. O'Brien     for (n = 0; src[n] != NULL; n++)
193c80476e4SDavid E. O'Brien 	continue;
19445e5710bSMark Peek     sdst = dst = xmalloc((n + 1) * sizeof(char *));
195c80476e4SDavid E. O'Brien 
196c80476e4SDavid E. O'Brien     for (; *src != NULL; src++)
197c80476e4SDavid E. O'Brien 	*dst++ = strsave(short2str(*src));
198c80476e4SDavid E. O'Brien     *dst = NULL;
199c80476e4SDavid E. O'Brien     return (sdst);
200c80476e4SDavid E. O'Brien }
201c80476e4SDavid E. O'Brien 
202c80476e4SDavid E. O'Brien Char   *
20345e5710bSMark Peek str2short(const char *src)
204c80476e4SDavid E. O'Brien {
20545e5710bSMark Peek     static struct Strbuf buf; /* = Strbuf_INIT; */
206c80476e4SDavid E. O'Brien 
207c80476e4SDavid E. O'Brien     if (src == NULL)
208c80476e4SDavid E. O'Brien 	return (NULL);
209c80476e4SDavid E. O'Brien 
21045e5710bSMark Peek     buf.len = 0;
21145e5710bSMark Peek     while (*src) {
21245e5710bSMark Peek 	Char wc;
213c80476e4SDavid E. O'Brien 
21445e5710bSMark Peek 	src += one_mbtowc(&wc, src, MB_LEN_MAX);
21545e5710bSMark Peek 	Strbuf_append1(&buf, wc);
216c80476e4SDavid E. O'Brien     }
21745e5710bSMark Peek     Strbuf_terminate(&buf);
21845e5710bSMark Peek     return buf.s;
219c80476e4SDavid E. O'Brien }
220c80476e4SDavid E. O'Brien 
221c80476e4SDavid E. O'Brien char   *
22245e5710bSMark Peek short2str(const Char *src)
223c80476e4SDavid E. O'Brien {
224c80476e4SDavid E. O'Brien     static char *sdst = NULL;
225c80476e4SDavid E. O'Brien     static size_t dstsize = 0;
22623338178SMark Peek     char *dst, *edst;
227c80476e4SDavid E. O'Brien 
228c80476e4SDavid E. O'Brien     if (src == NULL)
229c80476e4SDavid E. O'Brien 	return (NULL);
230c80476e4SDavid E. O'Brien 
231c80476e4SDavid E. O'Brien     if (sdst == NULL) {
232c80476e4SDavid E. O'Brien 	dstsize = MALLOC_INCR;
23345e5710bSMark Peek 	sdst = xmalloc((dstsize + MALLOC_SURPLUS) * sizeof(char));
234c80476e4SDavid E. O'Brien     }
235c80476e4SDavid E. O'Brien     dst = sdst;
236c80476e4SDavid E. O'Brien     edst = &dst[dstsize];
237c80476e4SDavid E. O'Brien     while (*src) {
238*19d2e3deSDmitry Chagin 	dst += one_wctomb(dst, *src);
23923338178SMark Peek 	src++;
24023338178SMark Peek 	if (dst >= edst) {
241a15e6f9aSMark Peek 	    char *wdst = dst;
242a15e6f9aSMark Peek 	    char *wedst = edst;
243a15e6f9aSMark Peek 
244c80476e4SDavid E. O'Brien 	    dstsize += MALLOC_INCR;
24545e5710bSMark Peek 	    sdst = xrealloc(sdst, (dstsize + MALLOC_SURPLUS) * sizeof(char));
246c80476e4SDavid E. O'Brien 	    edst = &sdst[dstsize];
247c80476e4SDavid E. O'Brien 	    dst = &edst[-MALLOC_INCR];
248a15e6f9aSMark Peek 	    while (wdst > wedst) {
249a15e6f9aSMark Peek 		dst++;
250a15e6f9aSMark Peek 		wdst--;
251a15e6f9aSMark Peek 	    }
252c80476e4SDavid E. O'Brien 	}
253c80476e4SDavid E. O'Brien     }
254c80476e4SDavid E. O'Brien     *dst = 0;
255c80476e4SDavid E. O'Brien     return (sdst);
256c80476e4SDavid E. O'Brien }
257c80476e4SDavid E. O'Brien 
2589ccc37e3SMark Peek #if !defined (WIDE_STRINGS) || defined (UTF16_STRINGS)
259c80476e4SDavid E. O'Brien Char   *
26045e5710bSMark Peek s_strcpy(Char *dst, const Char *src)
261c80476e4SDavid E. O'Brien {
26223338178SMark Peek     Char *sdst;
263c80476e4SDavid E. O'Brien 
264c80476e4SDavid E. O'Brien     sdst = dst;
265c80476e4SDavid E. O'Brien     while ((*dst++ = *src++) != '\0')
266c80476e4SDavid E. O'Brien 	continue;
267c80476e4SDavid E. O'Brien     return (sdst);
268c80476e4SDavid E. O'Brien }
269c80476e4SDavid E. O'Brien 
270c80476e4SDavid E. O'Brien Char   *
27145e5710bSMark Peek s_strncpy(Char *dst, const Char *src, size_t n)
272c80476e4SDavid E. O'Brien {
27323338178SMark Peek     Char *sdst;
274c80476e4SDavid E. O'Brien 
275c80476e4SDavid E. O'Brien     if (n == 0)
276c80476e4SDavid E. O'Brien 	return(dst);
277c80476e4SDavid E. O'Brien 
278c80476e4SDavid E. O'Brien     sdst = dst;
279c80476e4SDavid E. O'Brien     do
280c80476e4SDavid E. O'Brien 	if ((*dst++ = *src++) == '\0') {
281c80476e4SDavid E. O'Brien 	    while (--n != 0)
282c80476e4SDavid E. O'Brien 		*dst++ = '\0';
283c80476e4SDavid E. O'Brien 	    return(sdst);
284c80476e4SDavid E. O'Brien 	}
285c80476e4SDavid E. O'Brien     while (--n != 0);
286c80476e4SDavid E. O'Brien     return (sdst);
287c80476e4SDavid E. O'Brien }
288c80476e4SDavid E. O'Brien 
289c80476e4SDavid E. O'Brien Char   *
29045e5710bSMark Peek s_strcat(Char *dst, const Char *src)
291c80476e4SDavid E. O'Brien {
29245e5710bSMark Peek     Strcpy(Strend(dst), src);
29345e5710bSMark Peek     return dst;
294c80476e4SDavid E. O'Brien }
295c80476e4SDavid E. O'Brien 
296c80476e4SDavid E. O'Brien #ifdef NOTUSED
297c80476e4SDavid E. O'Brien Char   *
29845e5710bSMark Peek s_strncat(Char *dst, const Char *src, size_t n)
299c80476e4SDavid E. O'Brien {
30023338178SMark Peek     Char *sdst;
301c80476e4SDavid E. O'Brien 
302c80476e4SDavid E. O'Brien     if (n == 0)
303c80476e4SDavid E. O'Brien 	return (dst);
304c80476e4SDavid E. O'Brien 
305c80476e4SDavid E. O'Brien     sdst = dst;
306c80476e4SDavid E. O'Brien 
30745e5710bSMark Peek     while (*dst)
30845e5710bSMark Peek 	dst++;
309c80476e4SDavid E. O'Brien 
310c80476e4SDavid E. O'Brien     do
311c80476e4SDavid E. O'Brien 	if ((*dst++ = *src++) == '\0')
312c80476e4SDavid E. O'Brien 	    return(sdst);
313c80476e4SDavid E. O'Brien     while (--n != 0)
314c80476e4SDavid E. O'Brien 	continue;
315c80476e4SDavid E. O'Brien 
316c80476e4SDavid E. O'Brien     *dst = '\0';
317c80476e4SDavid E. O'Brien     return (sdst);
318c80476e4SDavid E. O'Brien }
319c80476e4SDavid E. O'Brien 
320c80476e4SDavid E. O'Brien #endif
321c80476e4SDavid E. O'Brien 
322c80476e4SDavid E. O'Brien Char   *
32345e5710bSMark Peek s_strchr(const Char *str, int ch)
324c80476e4SDavid E. O'Brien {
325c80476e4SDavid E. O'Brien     do
326c80476e4SDavid E. O'Brien 	if (*str == ch)
32723338178SMark Peek 	    return ((Char *)(intptr_t)str);
328c80476e4SDavid E. O'Brien     while (*str++);
329c80476e4SDavid E. O'Brien     return (NULL);
330c80476e4SDavid E. O'Brien }
331c80476e4SDavid E. O'Brien 
332c80476e4SDavid E. O'Brien Char   *
33345e5710bSMark Peek s_strrchr(const Char *str, int ch)
334c80476e4SDavid E. O'Brien {
33523338178SMark Peek     const Char *rstr;
336c80476e4SDavid E. O'Brien 
337c80476e4SDavid E. O'Brien     rstr = NULL;
338c80476e4SDavid E. O'Brien     do
339c80476e4SDavid E. O'Brien 	if (*str == ch)
340c80476e4SDavid E. O'Brien 	    rstr = str;
341c80476e4SDavid E. O'Brien     while (*str++);
34223338178SMark Peek     return ((Char *)(intptr_t)rstr);
343c80476e4SDavid E. O'Brien }
344c80476e4SDavid E. O'Brien 
345c80476e4SDavid E. O'Brien size_t
34645e5710bSMark Peek s_strlen(const Char *str)
347c80476e4SDavid E. O'Brien {
34823338178SMark Peek     size_t n;
349c80476e4SDavid E. O'Brien 
350c80476e4SDavid E. O'Brien     for (n = 0; *str++; n++)
351c80476e4SDavid E. O'Brien 	continue;
352c80476e4SDavid E. O'Brien     return (n);
353c80476e4SDavid E. O'Brien }
354c80476e4SDavid E. O'Brien 
355c80476e4SDavid E. O'Brien int
35645e5710bSMark Peek s_strcmp(const Char *str1, const Char *str2)
357c80476e4SDavid E. O'Brien {
358c80476e4SDavid E. O'Brien     for (; *str1 && *str1 == *str2; str1++, str2++)
359c80476e4SDavid E. O'Brien 	continue;
360c80476e4SDavid E. O'Brien     /*
361c80476e4SDavid E. O'Brien      * The following case analysis is necessary so that characters which look
362c80476e4SDavid E. O'Brien      * negative collate low against normal characters but high against the
363c80476e4SDavid E. O'Brien      * end-of-string NUL.
364c80476e4SDavid E. O'Brien      */
365c80476e4SDavid E. O'Brien     if (*str1 == '\0' && *str2 == '\0')
366c80476e4SDavid E. O'Brien 	return (0);
367c80476e4SDavid E. O'Brien     else if (*str1 == '\0')
368c80476e4SDavid E. O'Brien 	return (-1);
369c80476e4SDavid E. O'Brien     else if (*str2 == '\0')
370c80476e4SDavid E. O'Brien 	return (1);
371c80476e4SDavid E. O'Brien     else
372c80476e4SDavid E. O'Brien 	return (*str1 - *str2);
373c80476e4SDavid E. O'Brien }
374c80476e4SDavid E. O'Brien 
375c80476e4SDavid E. O'Brien int
37645e5710bSMark Peek s_strncmp(const Char *str1, const Char *str2, size_t n)
377c80476e4SDavid E. O'Brien {
378c80476e4SDavid E. O'Brien     if (n == 0)
379c80476e4SDavid E. O'Brien 	return (0);
380c80476e4SDavid E. O'Brien     do {
381c80476e4SDavid E. O'Brien 	if (*str1 != *str2) {
382c80476e4SDavid E. O'Brien 	    /*
383c80476e4SDavid E. O'Brien 	     * The following case analysis is necessary so that characters
384c80476e4SDavid E. O'Brien 	     * which look negative collate low against normal characters
385c80476e4SDavid E. O'Brien 	     * but high against the end-of-string NUL.
386c80476e4SDavid E. O'Brien 	     */
387c80476e4SDavid E. O'Brien 	    if (*str1 == '\0')
388c80476e4SDavid E. O'Brien 		return (-1);
389c80476e4SDavid E. O'Brien 	    else if (*str2 == '\0')
390c80476e4SDavid E. O'Brien 		return (1);
391c80476e4SDavid E. O'Brien 	    else
392c80476e4SDavid E. O'Brien 		return (*str1 - *str2);
393c80476e4SDavid E. O'Brien 	}
394c80476e4SDavid E. O'Brien         if (*str1 == '\0')
395c80476e4SDavid E. O'Brien 	    return(0);
396c80476e4SDavid E. O'Brien 	str1++, str2++;
397c80476e4SDavid E. O'Brien     } while (--n != 0);
398c80476e4SDavid E. O'Brien     return(0);
399c80476e4SDavid E. O'Brien }
40023338178SMark Peek #endif /* not WIDE_STRINGS */
401c80476e4SDavid E. O'Brien 
402b2d5d167SMark Peek int
40345e5710bSMark Peek s_strcasecmp(const Char *str1, const Char *str2)
404b2d5d167SMark Peek {
40523338178SMark Peek #ifdef WIDE_STRINGS
4069ccc37e3SMark Peek     wint_t l1 = 0, l2 = 0;
4079ccc37e3SMark Peek     for (; *str1; str1++, str2++)
4089ccc37e3SMark Peek 	if (*str1 == *str2)
4099ccc37e3SMark Peek 	    l1 = l2 = 0;
4109ccc37e3SMark Peek 	else if ((l1 = towlower(*str1)) != (l2 = towlower(*str2)))
4119ccc37e3SMark Peek 	    break;
41223338178SMark Peek #else
4139ccc37e3SMark Peek     unsigned char l1 = 0, l2 = 0;
4149ccc37e3SMark Peek     for (; *str1; str1++, str2++)
4159ccc37e3SMark Peek 	if (*str1 == *str2)
4169ccc37e3SMark Peek 		l1 = l2 = 0;
4179ccc37e3SMark Peek 	else if ((l1 = tolower((unsigned char)*str1)) !=
4189ccc37e3SMark Peek 	    (l2 = tolower((unsigned char)*str2)))
4199ccc37e3SMark Peek 	    break;
42023338178SMark Peek #endif
421b2d5d167SMark Peek     /*
422b2d5d167SMark Peek      * The following case analysis is necessary so that characters which look
423b2d5d167SMark Peek      * negative collate low against normal characters but high against the
424b2d5d167SMark Peek      * end-of-string NUL.
425b2d5d167SMark Peek      */
426b2d5d167SMark Peek     if (*str1 == '\0' && *str2 == '\0')
427b2d5d167SMark Peek 	return (0);
428b2d5d167SMark Peek     else if (*str1 == '\0')
429b2d5d167SMark Peek 	return (-1);
430b2d5d167SMark Peek     else if (*str2 == '\0')
431b2d5d167SMark Peek 	return (1);
432b2d5d167SMark Peek     else if (l1 == l2)	/* They are zero when they are equal */
433b2d5d167SMark Peek 	return (*str1 - *str2);
434b2d5d167SMark Peek     else
435b2d5d167SMark Peek 	return (l1 - l2);
436b2d5d167SMark Peek }
437b2d5d167SMark Peek 
438c80476e4SDavid E. O'Brien Char   *
43945e5710bSMark Peek s_strnsave(const Char *s, size_t len)
440c80476e4SDavid E. O'Brien {
441c80476e4SDavid E. O'Brien     Char *n;
442c80476e4SDavid E. O'Brien 
44345e5710bSMark Peek     n = xmalloc((len + 1) * sizeof (*n));
44445e5710bSMark Peek     memcpy(n, s, len * sizeof (*n));
44545e5710bSMark Peek     n[len] = '\0';
44645e5710bSMark Peek     return n;
44745e5710bSMark Peek }
44845e5710bSMark Peek 
44945e5710bSMark Peek Char   *
45045e5710bSMark Peek s_strsave(const Char *s)
45145e5710bSMark Peek {
45245e5710bSMark Peek     Char   *n;
45345e5710bSMark Peek     size_t size;
45445e5710bSMark Peek 
45545e5710bSMark Peek     if (s == NULL)
456c80476e4SDavid E. O'Brien 	s = STRNULL;
45745e5710bSMark Peek     size = (Strlen(s) + 1) * sizeof(*n);
45845e5710bSMark Peek     n = xmalloc(size);
45945e5710bSMark Peek     memcpy(n, s, size);
460c80476e4SDavid E. O'Brien     return (n);
461c80476e4SDavid E. O'Brien }
462c80476e4SDavid E. O'Brien 
463c80476e4SDavid E. O'Brien Char   *
46445e5710bSMark Peek s_strspl(const Char *cp, const Char *dp)
465c80476e4SDavid E. O'Brien {
46645e5710bSMark Peek     Char *res, *ep;
46745e5710bSMark Peek     const Char *p, *q;
468c80476e4SDavid E. O'Brien 
469c80476e4SDavid E. O'Brien     if (!cp)
470c80476e4SDavid E. O'Brien 	cp = STRNULL;
471c80476e4SDavid E. O'Brien     if (!dp)
472c80476e4SDavid E. O'Brien 	dp = STRNULL;
47345e5710bSMark Peek     for (p = cp; *p++;)
474c80476e4SDavid E. O'Brien 	continue;
47545e5710bSMark Peek     for (q = dp; *q++;)
476c80476e4SDavid E. O'Brien 	continue;
47745e5710bSMark Peek     res = xmalloc(((p - cp) + (q - dp) - 1) * sizeof(Char));
47845e5710bSMark Peek     for (ep = res, q = cp; (*ep++ = *q++) != '\0';)
479c80476e4SDavid E. O'Brien 	continue;
48045e5710bSMark Peek     for (ep--, q = dp; (*ep++ = *q++) != '\0';)
481c80476e4SDavid E. O'Brien 	continue;
48245e5710bSMark Peek     return (res);
483c80476e4SDavid E. O'Brien }
484c80476e4SDavid E. O'Brien 
485c80476e4SDavid E. O'Brien Char   *
48645e5710bSMark Peek s_strend(const Char *cp)
487c80476e4SDavid E. O'Brien {
488c80476e4SDavid E. O'Brien     if (!cp)
48923338178SMark Peek 	return ((Char *)(intptr_t) cp);
490c80476e4SDavid E. O'Brien     while (*cp)
491c80476e4SDavid E. O'Brien 	cp++;
49223338178SMark Peek     return ((Char *)(intptr_t) cp);
493c80476e4SDavid E. O'Brien }
494c80476e4SDavid E. O'Brien 
495c80476e4SDavid E. O'Brien Char   *
49645e5710bSMark Peek s_strstr(const Char *s, const Char *t)
497c80476e4SDavid E. O'Brien {
498c80476e4SDavid E. O'Brien     do {
49923338178SMark Peek 	const Char *ss = s;
50023338178SMark Peek 	const Char *tt = t;
501c80476e4SDavid E. O'Brien 
502c80476e4SDavid E. O'Brien 	do
503c80476e4SDavid E. O'Brien 	    if (*tt == '\0')
50423338178SMark Peek 		return ((Char *)(intptr_t) s);
505c80476e4SDavid E. O'Brien 	while (*ss++ == *tt++);
506c80476e4SDavid E. O'Brien     } while (*s++ != '\0');
507c80476e4SDavid E. O'Brien     return (NULL);
508c80476e4SDavid E. O'Brien }
509c80476e4SDavid E. O'Brien 
51045e5710bSMark Peek #else /* !SHORT_STRINGS */
51145e5710bSMark Peek char *
51245e5710bSMark Peek caching_strip(const char *s)
51345e5710bSMark Peek {
51445e5710bSMark Peek     static char *buf = NULL;
51545e5710bSMark Peek     static size_t buf_size = 0;
51645e5710bSMark Peek     size_t size;
51745e5710bSMark Peek 
51845e5710bSMark Peek     if (s == NULL)
51945e5710bSMark Peek       return NULL;
52045e5710bSMark Peek     size = strlen(s) + 1;
52145e5710bSMark Peek     if (buf_size < size) {
52245e5710bSMark Peek 	buf = xrealloc(buf, size);
52345e5710bSMark Peek 	buf_size = size;
52445e5710bSMark Peek     }
52545e5710bSMark Peek     memcpy(buf, s, size);
52645e5710bSMark Peek     strip(buf);
52745e5710bSMark Peek     return buf;
52845e5710bSMark Peek }
52945e5710bSMark Peek #endif
530c80476e4SDavid E. O'Brien 
531c80476e4SDavid E. O'Brien char   *
53245e5710bSMark Peek short2qstr(const Char *src)
533c80476e4SDavid E. O'Brien {
534c80476e4SDavid E. O'Brien     static char *sdst = NULL;
535c80476e4SDavid E. O'Brien     static size_t dstsize = 0;
53623338178SMark Peek     char *dst, *edst;
537c80476e4SDavid E. O'Brien 
538c80476e4SDavid E. O'Brien     if (src == NULL)
539c80476e4SDavid E. O'Brien 	return (NULL);
540c80476e4SDavid E. O'Brien 
541c80476e4SDavid E. O'Brien     if (sdst == NULL) {
542c80476e4SDavid E. O'Brien 	dstsize = MALLOC_INCR;
54345e5710bSMark Peek 	sdst = xmalloc((dstsize + MALLOC_SURPLUS) * sizeof(char));
544c80476e4SDavid E. O'Brien     }
545c80476e4SDavid E. O'Brien     dst = sdst;
546c80476e4SDavid E. O'Brien     edst = &dst[dstsize];
547c80476e4SDavid E. O'Brien     while (*src) {
548c80476e4SDavid E. O'Brien 	if (*src & QUOTE) {
549c80476e4SDavid E. O'Brien 	    *dst++ = '\\';
550c80476e4SDavid E. O'Brien 	    if (dst == edst) {
551c80476e4SDavid E. O'Brien 		dstsize += MALLOC_INCR;
55245e5710bSMark Peek 		sdst = xrealloc(sdst,
55345e5710bSMark Peek 				(dstsize + MALLOC_SURPLUS) * sizeof(char));
554c80476e4SDavid E. O'Brien 		edst = &sdst[dstsize];
555c80476e4SDavid E. O'Brien 		dst = &edst[-MALLOC_INCR];
556c80476e4SDavid E. O'Brien 	    }
557c80476e4SDavid E. O'Brien 	}
558*19d2e3deSDmitry Chagin 	dst += one_wctomb(dst, *src);
55923338178SMark Peek 	src++;
56023338178SMark Peek 	if (dst >= edst) {
561a15e6f9aSMark Peek 	    ptrdiff_t i = dst - edst;
562c80476e4SDavid E. O'Brien 	    dstsize += MALLOC_INCR;
56345e5710bSMark Peek 	    sdst = xrealloc(sdst, (dstsize + MALLOC_SURPLUS) * sizeof(char));
564c80476e4SDavid E. O'Brien 	    edst = &sdst[dstsize];
565a15e6f9aSMark Peek 	    dst = &edst[-MALLOC_INCR + i];
566c80476e4SDavid E. O'Brien 	}
567c80476e4SDavid E. O'Brien     }
568c80476e4SDavid E. O'Brien     *dst = 0;
569c80476e4SDavid E. O'Brien     return (sdst);
570c80476e4SDavid E. O'Brien }
57145e5710bSMark Peek 
572a15e6f9aSMark Peek struct blk_buf *
573*19d2e3deSDmitry Chagin bb_alloc(void)
574a15e6f9aSMark Peek {
575a15e6f9aSMark Peek     return xcalloc(1, sizeof(struct blk_buf));
576a15e6f9aSMark Peek }
577a15e6f9aSMark Peek 
57845e5710bSMark Peek static void
57945e5710bSMark Peek bb_store(struct blk_buf *bb, Char *str)
58045e5710bSMark Peek {
58145e5710bSMark Peek     if (bb->len == bb->size) { /* Keep space for terminating NULL */
58245e5710bSMark Peek 	if (bb->size == 0)
58345e5710bSMark Peek 	    bb->size = 16; /* Arbitrary */
58445e5710bSMark Peek 	else
58545e5710bSMark Peek 	    bb->size *= 2;
58645e5710bSMark Peek 	bb->vec = xrealloc(bb->vec, bb->size * sizeof (*bb->vec));
58745e5710bSMark Peek     }
58845e5710bSMark Peek     bb->vec[bb->len] = str;
58945e5710bSMark Peek }
59045e5710bSMark Peek 
59145e5710bSMark Peek void
59245e5710bSMark Peek bb_append(struct blk_buf *bb, Char *str)
59345e5710bSMark Peek {
59445e5710bSMark Peek     bb_store(bb, str);
59545e5710bSMark Peek     bb->len++;
59645e5710bSMark Peek }
59745e5710bSMark Peek 
59845e5710bSMark Peek void
59945e5710bSMark Peek bb_cleanup(void *xbb)
60045e5710bSMark Peek {
60145e5710bSMark Peek     struct blk_buf *bb;
60245e5710bSMark Peek     size_t i;
60345e5710bSMark Peek 
604*19d2e3deSDmitry Chagin     bb = (struct blk_buf *)xbb;
605*19d2e3deSDmitry Chagin     if (bb->vec) {
60645e5710bSMark Peek 	for (i = 0; i < bb->len; i++)
60745e5710bSMark Peek 	    xfree(bb->vec[i]);
60845e5710bSMark Peek 	xfree(bb->vec);
60945e5710bSMark Peek     }
610*19d2e3deSDmitry Chagin     bb->vec = NULL;
611*19d2e3deSDmitry Chagin     bb->len = 0;
612*19d2e3deSDmitry Chagin }
61345e5710bSMark Peek 
614a15e6f9aSMark Peek void
615a15e6f9aSMark Peek bb_free(void *bb)
616a15e6f9aSMark Peek {
617a15e6f9aSMark Peek     bb_cleanup(bb);
618a15e6f9aSMark Peek     xfree(bb);
619a15e6f9aSMark Peek }
620a15e6f9aSMark Peek 
62145e5710bSMark Peek Char **
62245e5710bSMark Peek bb_finish(struct blk_buf *bb)
62345e5710bSMark Peek {
62445e5710bSMark Peek     bb_store(bb, NULL);
62545e5710bSMark Peek     return xrealloc(bb->vec, (bb->len + 1) * sizeof (*bb->vec));
62645e5710bSMark Peek }
62745e5710bSMark Peek 
62845e5710bSMark Peek #define DO_STRBUF(STRBUF, CHAR, STRLEN)				\
629a15e6f9aSMark Peek 								\
630a15e6f9aSMark Peek struct STRBUF *							\
631a15e6f9aSMark Peek STRBUF##_alloc(void)						\
632a15e6f9aSMark Peek {								\
633a15e6f9aSMark Peek     return xcalloc(1, sizeof(struct STRBUF));			\
634a15e6f9aSMark Peek }								\
635a15e6f9aSMark Peek 								\
63645e5710bSMark Peek static void							\
63745e5710bSMark Peek STRBUF##_store1(struct STRBUF *buf, CHAR c)			\
63845e5710bSMark Peek {								\
63945e5710bSMark Peek     if (buf->size == buf->len) {				\
64045e5710bSMark Peek 	if (buf->size == 0)					\
64145e5710bSMark Peek 	    buf->size = 64; /* Arbitrary */			\
64245e5710bSMark Peek 	else							\
64345e5710bSMark Peek 	    buf->size *= 2;					\
64445e5710bSMark Peek 	buf->s = xrealloc(buf->s, buf->size * sizeof(*buf->s));	\
64545e5710bSMark Peek     }								\
6469ccc37e3SMark Peek     assert(buf->s);						\
64745e5710bSMark Peek     buf->s[buf->len] = c;					\
64845e5710bSMark Peek }								\
64945e5710bSMark Peek 								\
65045e5710bSMark Peek /* Like strbuf_append1(buf, '\0'), but don't advance len */	\
65145e5710bSMark Peek void								\
65245e5710bSMark Peek STRBUF##_terminate(struct STRBUF *buf)				\
65345e5710bSMark Peek {								\
65445e5710bSMark Peek     STRBUF##_store1(buf, '\0');					\
65545e5710bSMark Peek }								\
65645e5710bSMark Peek 								\
65745e5710bSMark Peek void								\
65845e5710bSMark Peek STRBUF##_append1(struct STRBUF *buf, CHAR c)			\
65945e5710bSMark Peek {								\
66045e5710bSMark Peek     STRBUF##_store1(buf, c);					\
66145e5710bSMark Peek     buf->len++;							\
66245e5710bSMark Peek }								\
66345e5710bSMark Peek 								\
66445e5710bSMark Peek void								\
66545e5710bSMark Peek STRBUF##_appendn(struct STRBUF *buf, const CHAR *s, size_t len)	\
66645e5710bSMark Peek {								\
66745e5710bSMark Peek     if (buf->size < buf->len + len) {				\
66845e5710bSMark Peek 	if (buf->size == 0)					\
66945e5710bSMark Peek 	    buf->size = 64; /* Arbitrary */			\
67045e5710bSMark Peek 	while (buf->size < buf->len + len)			\
67145e5710bSMark Peek 	    buf->size *= 2;					\
67245e5710bSMark Peek 	buf->s = xrealloc(buf->s, buf->size * sizeof(*buf->s));	\
67345e5710bSMark Peek     }								\
67445e5710bSMark Peek     memcpy(buf->s + buf->len, s, len * sizeof(*buf->s));	\
67545e5710bSMark Peek     buf->len += len;						\
67645e5710bSMark Peek }								\
67745e5710bSMark Peek 								\
67845e5710bSMark Peek void								\
67945e5710bSMark Peek STRBUF##_append(struct STRBUF *buf, const CHAR *s)		\
68045e5710bSMark Peek {								\
68145e5710bSMark Peek     STRBUF##_appendn(buf, s, STRLEN(s));			\
68245e5710bSMark Peek }								\
68345e5710bSMark Peek 								\
68445e5710bSMark Peek CHAR *								\
68545e5710bSMark Peek STRBUF##_finish(struct STRBUF *buf)				\
68645e5710bSMark Peek {								\
68745e5710bSMark Peek     STRBUF##_append1(buf, 0);					\
68845e5710bSMark Peek     return xrealloc(buf->s, buf->len * sizeof(*buf->s));	\
68945e5710bSMark Peek }								\
69045e5710bSMark Peek 								\
69145e5710bSMark Peek void								\
69245e5710bSMark Peek STRBUF##_cleanup(void *xbuf)					\
69345e5710bSMark Peek {								\
69445e5710bSMark Peek     struct STRBUF *buf;						\
69545e5710bSMark Peek 								\
69645e5710bSMark Peek     buf = xbuf;							\
69745e5710bSMark Peek     xfree(buf->s);						\
69845e5710bSMark Peek }								\
69945e5710bSMark Peek 								\
700a15e6f9aSMark Peek void								\
701a15e6f9aSMark Peek STRBUF##_free(void *xbuf)					\
702a15e6f9aSMark Peek {								\
703a15e6f9aSMark Peek     STRBUF##_cleanup(xbuf);					\
704a15e6f9aSMark Peek     xfree(xbuf);						\
705a15e6f9aSMark Peek }								\
706a15e6f9aSMark Peek 								\
70745e5710bSMark Peek const struct STRBUF STRBUF##_init /* = STRBUF##_INIT; */
70845e5710bSMark Peek 
70945e5710bSMark Peek DO_STRBUF(strbuf, char, strlen);
71045e5710bSMark Peek DO_STRBUF(Strbuf, Char, Strlen);
711