tc.str.c revision 145479
1/* $Header: /src/pub/tcsh/tc.str.c,v 3.19 2005/01/06 16:56:26 christos Exp $ */
2/*
3 * tc.str.c: Short string package
4 * 	     This has been a lesson of how to write buggy code!
5 */
6/*-
7 * Copyright (c) 1980, 1991 The Regents of the University of California.
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 *    may be used to endorse or promote products derived from this software
20 *    without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34#include "sh.h"
35
36#include <limits.h>
37
38RCSID("$Id: tc.str.c,v 3.19 2005/01/06 16:56:26 christos Exp $")
39
40#define MALLOC_INCR	128
41#ifdef WIDE_STRINGS
42#define MALLOC_SURPLUS	MB_LEN_MAX /* Space for one multibyte character */
43#else
44#define MALLOC_SURPLUS	0
45#endif
46
47#ifdef WIDE_STRINGS
48size_t
49one_mbtowc(wchar_t *pwc, const char *s, size_t n)
50{
51    int len;
52
53    len = rt_mbtowc(pwc, s, n);
54    if (len == -1) {
55        mbtowc(NULL, NULL, 0);
56	*pwc = (unsigned char)*s | INVALID_BYTE;
57    }
58    if (len <= 0)
59	len = 1;
60    return len;
61}
62
63size_t
64one_wctomb(char *s, wchar_t wchar)
65{
66    int len;
67
68    if (wchar & INVALID_BYTE) {
69	s[0] = wchar & 0xFF;
70	len = 1;
71    } else {
72	len = wctomb(s, wchar);
73	if (len == -1)
74	    s[0] = wchar;
75	if (len <= 0)
76	    len = 1;
77    }
78    return len;
79}
80#endif
81
82#ifdef SHORT_STRINGS
83int
84rt_mbtowc(wchar_t *pwc, const char *s, size_t n)
85{
86    int ret;
87    char back[MB_LEN_MAX];
88
89    ret = mbtowc(pwc, s, n);
90    if (ret > 0 && (wctomb(back, *pwc) != ret || memcmp(s, back, ret) != 0))
91	ret = -1;
92    return ret;
93}
94
95Char  **
96blk2short(src)
97    char **src;
98{
99    size_t     n;
100    Char **sdst, **dst;
101
102    /*
103     * Count
104     */
105    for (n = 0; src[n] != NULL; n++)
106	continue;
107    sdst = dst = (Char **) xmalloc((size_t) ((n + 1) * sizeof(Char *)));
108
109    for (; *src != NULL; src++)
110	*dst++ = SAVE(*src);
111    *dst = NULL;
112    return (sdst);
113}
114
115char  **
116short2blk(src)
117    Char **src;
118{
119    size_t     n;
120    char **sdst, **dst;
121
122    /*
123     * Count
124     */
125    for (n = 0; src[n] != NULL; n++)
126	continue;
127    sdst = dst = (char **) xmalloc((size_t) ((n + 1) * sizeof(char *)));
128
129    for (; *src != NULL; src++)
130	*dst++ = strsave(short2str(*src));
131    *dst = NULL;
132    return (sdst);
133}
134
135Char   *
136str2short(src)
137    const char *src;
138{
139    static Char *sdst;
140    static size_t dstsize = 0;
141    Char *dst, *edst;
142
143    if (src == NULL)
144	return (NULL);
145
146    if (sdst == (NULL)) {
147	dstsize = MALLOC_INCR;
148	sdst = (Char *) xmalloc((size_t) (dstsize * sizeof(Char)));
149    }
150
151    dst = sdst;
152    edst = &dst[dstsize];
153    while ((unsigned char) *src) {
154	src += one_mbtowc(dst, src, MB_LEN_MAX);
155	dst++;
156	if (dst == edst) {
157	    dstsize += MALLOC_INCR;
158	    sdst = (Char *) xrealloc((ptr_t) sdst,
159				     (size_t) (dstsize * sizeof(Char)));
160	    edst = &sdst[dstsize];
161	    dst = &edst[-MALLOC_INCR];
162	}
163    }
164    *dst = 0;
165    return (sdst);
166}
167
168char   *
169short2str(src)
170    const Char *src;
171{
172    static char *sdst = NULL;
173    static size_t dstsize = 0;
174    char *dst, *edst;
175
176    if (src == NULL)
177	return (NULL);
178
179    if (sdst == NULL) {
180	dstsize = MALLOC_INCR;
181	sdst = (char *) xmalloc((size_t) ((dstsize + MALLOC_SURPLUS)
182					  * sizeof(char)));
183    }
184    dst = sdst;
185    edst = &dst[dstsize];
186    while (*src) {
187	dst += one_wctomb(dst, *src & CHAR);
188	src++;
189	if (dst >= edst) {
190	    dstsize += MALLOC_INCR;
191	    sdst = (char *) xrealloc((ptr_t) sdst,
192				     (size_t) ((dstsize + MALLOC_SURPLUS)
193					       * sizeof(char)));
194	    edst = &sdst[dstsize];
195	    dst = &edst[-MALLOC_INCR];
196	}
197    }
198    *dst = 0;
199    return (sdst);
200}
201
202#ifndef WIDE_STRINGS
203Char   *
204s_strcpy(dst, src)
205    Char *dst;
206    const Char *src;
207{
208    Char *sdst;
209
210    sdst = dst;
211    while ((*dst++ = *src++) != '\0')
212	continue;
213    return (sdst);
214}
215
216Char   *
217s_strncpy(dst, src, n)
218    Char *dst;
219    const Char *src;
220    size_t n;
221{
222    Char *sdst;
223
224    if (n == 0)
225	return(dst);
226
227    sdst = dst;
228    do
229	if ((*dst++ = *src++) == '\0') {
230	    while (--n != 0)
231		*dst++ = '\0';
232	    return(sdst);
233	}
234    while (--n != 0);
235    return (sdst);
236}
237
238Char   *
239s_strcat(dst, src)
240    Char *dst;
241    const Char *src;
242{
243    Char *sdst;
244
245    sdst = dst;
246    while (*dst++)
247	continue;
248    --dst;
249    while ((*dst++ = *src++) != '\0')
250	continue;
251    return (sdst);
252}
253
254#ifdef NOTUSED
255Char   *
256s_strncat(dst, src, n)
257    Char *dst;
258    const Char *src;
259    size_t n;
260{
261    Char *sdst;
262
263    if (n == 0)
264	return (dst);
265
266    sdst = dst;
267
268    while (*dst++)
269	continue;
270    --dst;
271
272    do
273	if ((*dst++ = *src++) == '\0')
274	    return(sdst);
275    while (--n != 0)
276	continue;
277
278    *dst = '\0';
279    return (sdst);
280}
281
282#endif
283
284Char   *
285s_strchr(str, ch)
286    const Char *str;
287    int ch;
288{
289    do
290	if (*str == ch)
291	    return ((Char *)(intptr_t)str);
292    while (*str++);
293    return (NULL);
294}
295
296Char   *
297s_strrchr(str, ch)
298    const Char *str;
299    int ch;
300{
301    const Char *rstr;
302
303    rstr = NULL;
304    do
305	if (*str == ch)
306	    rstr = str;
307    while (*str++);
308    return ((Char *)(intptr_t)rstr);
309}
310
311size_t
312s_strlen(str)
313    const Char *str;
314{
315    size_t n;
316
317    for (n = 0; *str++; n++)
318	continue;
319    return (n);
320}
321
322int
323s_strcmp(str1, str2)
324    const Char *str1, *str2;
325{
326    for (; *str1 && *str1 == *str2; str1++, str2++)
327	continue;
328    /*
329     * The following case analysis is necessary so that characters which look
330     * negative collate low against normal characters but high against the
331     * end-of-string NUL.
332     */
333    if (*str1 == '\0' && *str2 == '\0')
334	return (0);
335    else if (*str1 == '\0')
336	return (-1);
337    else if (*str2 == '\0')
338	return (1);
339    else
340	return (*str1 - *str2);
341}
342
343int
344s_strncmp(str1, str2, n)
345    const Char *str1, *str2;
346    size_t n;
347{
348    if (n == 0)
349	return (0);
350    do {
351	if (*str1 != *str2) {
352	    /*
353	     * The following case analysis is necessary so that characters
354	     * which look negative collate low against normal characters
355	     * but high against the end-of-string NUL.
356	     */
357	    if (*str1 == '\0')
358		return (-1);
359	    else if (*str2 == '\0')
360		return (1);
361	    else
362		return (*str1 - *str2);
363	}
364        if (*str1 == '\0')
365	    return(0);
366	str1++, str2++;
367    } while (--n != 0);
368    return(0);
369}
370#endif /* not WIDE_STRINGS */
371
372int
373s_strcasecmp(str1, str2)
374    const Char *str1, *str2;
375{
376#ifdef WIDE_STRINGS
377    wchar_t l1 = 0, l2 = 0;
378    for (; *str1 && ((*str1 == *str2 && (l1 = l2 = 0) == 0) ||
379	(l1 = towlower(*str1)) == (l2 = towlower(*str2))); str1++, str2++)
380	continue;
381
382#else
383    unsigned char c1, c2, l1 = 0, l2 = 0;
384    for (; *str1 && ((*str1 == *str2 && (l1 = l2 = 0) == 0) ||
385	((c1 = (unsigned char)*str1) == *str1 &&
386	 (c2 = (unsigned char)*str2) == *str2 &&
387	(l1 = tolower(c1)) == (l2 = tolower(c2)))); str1++, str2++)
388	continue;
389#endif
390    /*
391     * The following case analysis is necessary so that characters which look
392     * negative collate low against normal characters but high against the
393     * end-of-string NUL.
394     */
395    if (*str1 == '\0' && *str2 == '\0')
396	return (0);
397    else if (*str1 == '\0')
398	return (-1);
399    else if (*str2 == '\0')
400	return (1);
401    else if (l1 == l2)	/* They are zero when they are equal */
402	return (*str1 - *str2);
403    else
404	return (l1 - l2);
405}
406
407Char   *
408s_strsave(s)
409    const Char *s;
410{
411    Char   *n;
412    Char *p;
413
414    if (s == 0)
415	s = STRNULL;
416    for (p = (Char *)(intptr_t)s; *p++;)
417	continue;
418    n = p = (Char *) xmalloc((size_t)
419			     ((((const Char *) p) - s) * sizeof(Char)));
420    while ((*p++ = *s++) != '\0')
421	continue;
422    return (n);
423}
424
425Char   *
426s_strspl(cp, dp)
427    const Char   *cp, *dp;
428{
429    Char   *ep;
430    Char *p, *q;
431
432    if (!cp)
433	cp = STRNULL;
434    if (!dp)
435	dp = STRNULL;
436    for (p = (Char *)(intptr_t) cp; *p++;)
437	continue;
438    for (q = (Char *)(intptr_t) dp; *q++;)
439	continue;
440    ep = (Char *) xmalloc((size_t)
441			  (((((const Char *) p) - cp) +
442			    (((const Char *) q) - dp) - 1) * sizeof(Char)));
443    for (p = ep, q = (Char*)(intptr_t) cp; (*p++ = *q++) != '\0';)
444	continue;
445    for (p--, q = (Char *)(intptr_t) dp; (*p++ = *q++) != '\0';)
446	continue;
447    return (ep);
448}
449
450Char   *
451s_strend(cp)
452    const Char *cp;
453{
454    if (!cp)
455	return ((Char *)(intptr_t) cp);
456    while (*cp)
457	cp++;
458    return ((Char *)(intptr_t) cp);
459}
460
461Char   *
462s_strstr(s, t)
463    const Char *s, *t;
464{
465    do {
466	const Char *ss = s;
467	const Char *tt = t;
468
469	do
470	    if (*tt == '\0')
471		return ((Char *)(intptr_t) s);
472	while (*ss++ == *tt++);
473    } while (*s++ != '\0');
474    return (NULL);
475}
476
477#endif				/* SHORT_STRINGS */
478
479char   *
480short2qstr(src)
481    const Char *src;
482{
483    static char *sdst = NULL;
484    static size_t dstsize = 0;
485    char *dst, *edst;
486
487    if (src == NULL)
488	return (NULL);
489
490    if (sdst == NULL) {
491	dstsize = MALLOC_INCR;
492	sdst = (char *) xmalloc((size_t) ((dstsize + MALLOC_SURPLUS)
493					  * sizeof(char)));
494    }
495    dst = sdst;
496    edst = &dst[dstsize];
497    while (*src) {
498	if (*src & QUOTE) {
499	    *dst++ = '\\';
500	    if (dst == edst) {
501		dstsize += MALLOC_INCR;
502		sdst = (char *) xrealloc((ptr_t) sdst,
503					 (size_t) ((dstsize + MALLOC_SURPLUS)
504						   * sizeof(char)));
505		edst = &sdst[dstsize];
506		dst = &edst[-MALLOC_INCR];
507	    }
508	}
509	dst += one_wctomb(dst, *src & CHAR);
510	src++;
511	if (dst >= edst) {
512	    dstsize += MALLOC_INCR;
513	    sdst = (char *) xrealloc((ptr_t) sdst,
514				     (size_t) ((dstsize + MALLOC_SURPLUS)
515					       * sizeof(char)));
516	    edst = &sdst[dstsize];
517	    dst = &edst[-MALLOC_INCR];
518	}
519    }
520    *dst = 0;
521    return (sdst);
522}
523