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