]> git.ipfire.org Git - thirdparty/bash.git/blame - stringlib.c
Imported from ../bash-2.03.tar.gz.
[thirdparty/bash.git] / stringlib.c
CommitLineData
ccc6cda3
JA
1/* stringlib.c - Miscellaneous string functions. */
2
3/* Copyright (C) 1996
4 Free Software Foundation, Inc.
5
6 This file is part of GNU Bash, the Bourne Again SHell.
7
8 Bash is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 2, or (at your option) any later
11 version.
12
13 Bash is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 for more details.
17
18 You should have received a copy of the GNU General Public License along
19 with Bash; see the file COPYING. If not, write to the Free Software
20 Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
21
22#include "config.h"
23
24#include "bashtypes.h"
25
26#if defined (HAVE_UNISTD_H)
27# include <unistd.h>
28#endif
29
30#include "bashansi.h"
31#include <stdio.h>
32#include <ctype.h>
33
34#include "shell.h"
35
36#ifndef to_upper
37# define to_upper(c) (islower(c) ? toupper(c) : (c))
38# define to_lower(c) (isupper(c) ? tolower(c) : (c))
39#endif
40
cce855bc
JA
41#define ISOCTAL(c) ((c) >= '0' && (c) <= '7')
42#define OCTVALUE(c) ((c) - '0')
43
44#ifndef isxdigit
45# define isxdigit(c) (isdigit((c)) || ((c) >= 'a' && (c) <= 'f') || ((c) >= 'A' && (c) <= 'F'))
46#endif
47
48#define HEXVALUE(c) \
49 ((c) >= 'a' && (c) <= 'f' ? (c)-'a'+10 : (c) >= 'A' && (c) <= 'F' ? (c)-'A'+10 : (c)-'0')
50
ccc6cda3
JA
51/* Convert STRING by expanding the escape sequences specified by the
52 ANSI C standard. If SAWC is non-null, recognize `\c' and use that
53 as a string terminator. If we see \c, set *SAWC to 1 before
54 returning. LEN is the length of STRING. */
55char *
d166f048 56ansicstr (string, len, sawc, rlen)
ccc6cda3 57 char *string;
d166f048 58 int len, *sawc, *rlen;
ccc6cda3 59{
cce855bc 60 int c, temp;
ccc6cda3
JA
61 char *ret, *r, *s;
62
63 if (string == 0 || *string == '\0')
64 return ((char *)NULL);
65
66 ret = xmalloc (len + 1);
67 for (r = ret, s = string; s && *s; )
68 {
69 c = *s++;
70 if (c != '\\' || *s == '\0')
71 *r++ = c;
72 else
73 {
74 switch (c = *s++)
75 {
76#if defined (__STDC__)
77 case 'a': c = '\a'; break;
78 case 'v': c = '\v'; break;
79#else
80 case 'a': c = '\007'; break;
81 case 'v': c = (int) 0x0B; break;
82#endif
83 case 'b': c = '\b'; break;
cce855bc
JA
84 case 'e': case 'E': /* ESC -- non-ANSI */
85 c = '\033'; break;
ccc6cda3
JA
86 case 'f': c = '\f'; break;
87 case 'n': c = '\n'; break;
88 case 'r': c = '\r'; break;
89 case 't': c = '\t'; break;
90 case '0': case '1': case '2': case '3':
91 case '4': case '5': case '6': case '7':
cce855bc
JA
92 for (temp = 2, c -= '0'; ISOCTAL (*s) && temp--; s++)
93 c = (c * 8) + OCTVALUE (*s);
94 break;
95 case 'x': /* Hex digit -- non-ANSI */
96 for (temp = 3, c = 0; isxdigit (*s) && temp--; s++)
97 c = (c * 16) + HEXVALUE (*s);
98 /* \x followed by non-hex digits is passed through unchanged */
99 if (temp == 3)
100 {
101 *r++ = '\\';
102 c = 'x';
103 }
ccc6cda3
JA
104 break;
105 case '\\':
106 case '\'':
107 break;
108 case 'c':
109 if (sawc)
110 {
111 *sawc = 1;
112 *r = '\0';
d166f048
JA
113 if (rlen)
114 *rlen = r - ret;
ccc6cda3
JA
115 return ret;
116 }
117 default: *r++ = '\\'; break;
118 }
119 *r++ = c;
120 }
121 }
122 *r = '\0';
d166f048
JA
123 if (rlen)
124 *rlen = r - ret;
ccc6cda3
JA
125 return ret;
126}
127
128/* **************************************************************** */
129/* */
130/* Functions to manage arrays of strings */
131/* */
132/* **************************************************************** */
133
cce855bc 134#ifdef INCLUDE_UNUSED
ccc6cda3
JA
135/* Find NAME in ARRAY. Return the index of NAME, or -1 if not present.
136 ARRAY should be NULL terminated. */
137int
138find_name_in_array (name, array)
139 char *name, **array;
140{
141 int i;
142
143 for (i = 0; array[i]; i++)
144 if (STREQ (name, array[i]))
145 return (i);
146
147 return (-1);
148}
cce855bc 149#endif
ccc6cda3
JA
150
151/* Return the length of ARRAY, a NULL terminated array of char *. */
152int
153array_len (array)
154 char **array;
155{
156 register int i;
157
158 for (i = 0; array[i]; i++);
159 return (i);
160}
161
162/* Free the contents of ARRAY, a NULL terminated array of char *. */
163void
164free_array_members (array)
165 char **array;
166{
167 register int i;
168
169 if (array == 0)
170 return;
171
172 for (i = 0; array[i]; i++)
173 free (array[i]);
174}
175
176void
177free_array (array)
178 char **array;
179{
180 if (array == 0)
181 return;
182
183 free_array_members (array);
184 free (array);
185}
186
187/* Allocate and return a new copy of ARRAY and its contents. */
188char **
189copy_array (array)
190 char **array;
191{
192 register int i;
193 int len;
194 char **new_array;
195
196 len = array_len (array);
197
198 new_array = (char **)xmalloc ((len + 1) * sizeof (char *));
199 for (i = 0; array[i]; i++)
200 new_array[i] = savestring (array[i]);
201 new_array[i] = (char *)NULL;
202
203 return (new_array);
204}
205
206/* Comparison routine for use with qsort() on arrays of strings. Uses
207 strcoll(3) if available, otherwise it uses strcmp(3). */
208int
209qsort_string_compare (s1, s2)
210 register char **s1, **s2;
211{
212#if defined (HAVE_STRCOLL)
213 return (strcoll (*s1, *s2));
214#else /* !HAVE_STRCOLL */
215 int result;
216
217 if ((result = **s1 - **s2) == 0)
218 result = strcmp (*s1, *s2);
219
220 return (result);
221#endif /* !HAVE_STRCOLL */
222}
223
224/* Sort ARRAY, a null terminated array of pointers to strings. */
225void
226sort_char_array (array)
227 char **array;
228{
229 qsort (array, array_len (array), sizeof (char *),
230 (Function *)qsort_string_compare);
231}
232
233/* Cons up a new array of words. The words are taken from LIST,
234 which is a WORD_LIST *. If COPY is true, everything is malloc'ed,
235 so you should free everything in this array when you are done.
236 The array is NULL terminated. If IP is non-null, it gets the
237 number of words in the returned array. STARTING_INDEX says where
238 to start filling in the returned array; it can be used to reserve
239 space at the beginning of the array. */
240char **
241word_list_to_argv (list, copy, starting_index, ip)
242 WORD_LIST *list;
243 int copy, starting_index, *ip;
244{
245 int count;
246 char **array;
247
248 count = list_length (list);
249 array = (char **)xmalloc ((1 + count + starting_index) * sizeof (char *));
250
251 for (count = 0; count < starting_index; count++)
252 array[count] = (char *)NULL;
253 for (count = starting_index; list; count++, list = list->next)
254 array[count] = copy ? savestring (list->word->word) : list->word->word;
255 array[count] = (char *)NULL;
256
257 if (ip)
258 *ip = count;
259 return (array);
260}
261
262/* Convert an array of strings into the form used internally by the shell.
263 COPY means to copy the values in ARRAY into the returned list rather
264 than allocate new storage. STARTING_INDEX says where in ARRAY to begin. */
265WORD_LIST *
266argv_to_word_list (array, copy, starting_index)
267 char **array;
268 int copy, starting_index;
269{
270 WORD_LIST *list;
271 WORD_DESC *w;
272 int i, count;
273
274 if (array == 0 || array[0] == 0)
275 return (WORD_LIST *)NULL;
276
277 for (count = 0; array[count]; count++)
278 ;
279
280 for (i = starting_index, list = (WORD_LIST *)NULL; i < count; i++)
281 {
282 w = make_bare_word (copy ? "" : array[i]);
283 if (copy)
284 {
285 free (w->word);
286 w->word = array[i];
287 }
288 list = make_word_list (w, list);
289 }
290 return (REVERSE_LIST(list, WORD_LIST *));
291}
292
293/* **************************************************************** */
294/* */
295/* String Management Functions */
296/* */
297/* **************************************************************** */
298
299/* Replace occurrences of PAT with REP in STRING. If GLOBAL is non-zero,
300 replace all occurrences, otherwise replace only the first.
301 This returns a new string; the caller should free it. */
302char *
303strsub (string, pat, rep, global)
304 char *string, *pat, *rep;
305 int global;
306{
cce855bc 307 int patlen, replen, templen, tempsize, repl, i;
ccc6cda3
JA
308 char *temp, *r;
309
310 patlen = strlen (pat);
cce855bc 311 replen = strlen (rep);
ccc6cda3
JA
312 for (temp = (char *)NULL, i = templen = tempsize = 0, repl = 1; string[i]; )
313 {
314 if (repl && STREQN (string + i, pat, patlen))
315 {
cce855bc 316 RESIZE_MALLOCED_BUFFER (temp, templen, replen, tempsize, (replen * 2));
ccc6cda3
JA
317
318 for (r = rep; *r; )
319 temp[templen++] = *r++;
320
321 i += patlen;
322 repl = global != 0;
323 }
324 else
325 {
326 RESIZE_MALLOCED_BUFFER (temp, templen, 1, tempsize, 16);
327 temp[templen++] = string[i++];
328 }
329 }
330 temp[templen] = 0;
331 return (temp);
332}
333
d166f048 334#ifdef INCLUDE_UNUSED
ccc6cda3
JA
335/* Remove all leading whitespace from STRING. This includes
336 newlines. STRING should be terminated with a zero. */
337void
338strip_leading (string)
339 char *string;
340{
341 char *start = string;
342
343 while (*string && (whitespace (*string) || *string == '\n'))
344 string++;
345
346 if (string != start)
347 {
348 int len = strlen (string);
349 FASTCOPY (string, start, len);
350 start[len] = '\0';
351 }
352}
d166f048 353#endif
ccc6cda3
JA
354
355/* Remove all trailing whitespace from STRING. This includes
356 newlines. If NEWLINES_ONLY is non-zero, only trailing newlines
357 are removed. STRING should be terminated with a zero. */
358void
d166f048 359strip_trailing (string, len, newlines_only)
ccc6cda3 360 char *string;
d166f048 361 int len;
ccc6cda3
JA
362 int newlines_only;
363{
ccc6cda3
JA
364 while (len >= 0)
365 {
366 if ((newlines_only && string[len] == '\n') ||
367 (!newlines_only && whitespace (string[len])))
368 len--;
369 else
370 break;
371 }
372 string[len + 1] = '\0';
373}
374
375/* Determine if s2 occurs in s1. If so, return a pointer to the
376 match in s1. The compare is case insensitive. This is a
377 case-insensitive strstr(3). */
378char *
379strindex (s1, s2)
380 char *s1, *s2;
381{
382 register int i, l, len, c;
383
384 c = to_upper (s2[0]);
385 for (i = 0, len = strlen (s1), l = strlen (s2); (len - i) >= l; i++)
386 if ((to_upper (s1[i]) == c) && (strncasecmp (s1 + i, s2, l) == 0))
387 return (s1 + i);
388 return ((char *)NULL);
389}
390
391/* A wrapper for bcopy that can be prototyped in general.h */
392void
393xbcopy (s, d, n)
394 char *s, *d;
395 int n;
396{
397 FASTCOPY (s, d, n);
398}