]> git.ipfire.org Git - thirdparty/bash.git/blob - stringlib.c
Imported from ../bash-2.0.tar.gz.
[thirdparty/bash.git] / stringlib.c
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
41 /* Convert STRING by expanding the escape sequences specified by the
42 ANSI C standard. If SAWC is non-null, recognize `\c' and use that
43 as a string terminator. If we see \c, set *SAWC to 1 before
44 returning. LEN is the length of STRING. */
45 char *
46 ansicstr (string, len, sawc)
47 char *string;
48 int len, *sawc;
49 {
50 int c;
51 char *ret, *r, *s;
52
53 if (string == 0 || *string == '\0')
54 return ((char *)NULL);
55
56 ret = xmalloc (len + 1);
57 for (r = ret, s = string; s && *s; )
58 {
59 c = *s++;
60 if (c != '\\' || *s == '\0')
61 *r++ = c;
62 else
63 {
64 switch (c = *s++)
65 {
66 #if defined (__STDC__)
67 case 'a': c = '\a'; break;
68 case 'v': c = '\v'; break;
69 #else
70 case 'a': c = '\007'; break;
71 case 'v': c = (int) 0x0B; break;
72 #endif
73 case 'b': c = '\b'; break;
74 case 'e': c = '\033'; break; /* ESC -- non-ANSI */
75 case 'E': c = '\033'; break; /* ESC -- non-ANSI */
76 case 'f': c = '\f'; break;
77 case 'n': c = '\n'; break;
78 case 'r': c = '\r'; break;
79 case 't': c = '\t'; break;
80 case '0': case '1': case '2': case '3':
81 case '4': case '5': case '6': case '7':
82 c -= '0';
83 if (*s >= '0' && *s <= '7')
84 c = c * 8 + (*s++ - '0');
85 if (*s >= '0' && *s <= '7')
86 c = c * 8 + (*s++ - '0');
87 break;
88 case '\\':
89 case '\'':
90 break;
91 case 'c':
92 if (sawc)
93 {
94 *sawc = 1;
95 *r = '\0';
96 return ret;
97 }
98 default: *r++ = '\\'; break;
99 }
100 *r++ = c;
101 }
102 }
103 *r = '\0';
104 return ret;
105 }
106
107 /* **************************************************************** */
108 /* */
109 /* Functions to manage arrays of strings */
110 /* */
111 /* **************************************************************** */
112
113 /* Find NAME in ARRAY. Return the index of NAME, or -1 if not present.
114 ARRAY should be NULL terminated. */
115 int
116 find_name_in_array (name, array)
117 char *name, **array;
118 {
119 int i;
120
121 for (i = 0; array[i]; i++)
122 if (STREQ (name, array[i]))
123 return (i);
124
125 return (-1);
126 }
127
128 /* Return the length of ARRAY, a NULL terminated array of char *. */
129 int
130 array_len (array)
131 char **array;
132 {
133 register int i;
134
135 for (i = 0; array[i]; i++);
136 return (i);
137 }
138
139 /* Free the contents of ARRAY, a NULL terminated array of char *. */
140 void
141 free_array_members (array)
142 char **array;
143 {
144 register int i;
145
146 if (array == 0)
147 return;
148
149 for (i = 0; array[i]; i++)
150 free (array[i]);
151 }
152
153 void
154 free_array (array)
155 char **array;
156 {
157 if (array == 0)
158 return;
159
160 free_array_members (array);
161 free (array);
162 }
163
164 /* Allocate and return a new copy of ARRAY and its contents. */
165 char **
166 copy_array (array)
167 char **array;
168 {
169 register int i;
170 int len;
171 char **new_array;
172
173 len = array_len (array);
174
175 new_array = (char **)xmalloc ((len + 1) * sizeof (char *));
176 for (i = 0; array[i]; i++)
177 new_array[i] = savestring (array[i]);
178 new_array[i] = (char *)NULL;
179
180 return (new_array);
181 }
182
183 /* Comparison routine for use with qsort() on arrays of strings. Uses
184 strcoll(3) if available, otherwise it uses strcmp(3). */
185 int
186 qsort_string_compare (s1, s2)
187 register char **s1, **s2;
188 {
189 #if defined (HAVE_STRCOLL)
190 return (strcoll (*s1, *s2));
191 #else /* !HAVE_STRCOLL */
192 int result;
193
194 if ((result = **s1 - **s2) == 0)
195 result = strcmp (*s1, *s2);
196
197 return (result);
198 #endif /* !HAVE_STRCOLL */
199 }
200
201 /* Sort ARRAY, a null terminated array of pointers to strings. */
202 void
203 sort_char_array (array)
204 char **array;
205 {
206 qsort (array, array_len (array), sizeof (char *),
207 (Function *)qsort_string_compare);
208 }
209
210 /* Cons up a new array of words. The words are taken from LIST,
211 which is a WORD_LIST *. If COPY is true, everything is malloc'ed,
212 so you should free everything in this array when you are done.
213 The array is NULL terminated. If IP is non-null, it gets the
214 number of words in the returned array. STARTING_INDEX says where
215 to start filling in the returned array; it can be used to reserve
216 space at the beginning of the array. */
217 char **
218 word_list_to_argv (list, copy, starting_index, ip)
219 WORD_LIST *list;
220 int copy, starting_index, *ip;
221 {
222 int count;
223 char **array;
224
225 count = list_length (list);
226 array = (char **)xmalloc ((1 + count + starting_index) * sizeof (char *));
227
228 for (count = 0; count < starting_index; count++)
229 array[count] = (char *)NULL;
230 for (count = starting_index; list; count++, list = list->next)
231 array[count] = copy ? savestring (list->word->word) : list->word->word;
232 array[count] = (char *)NULL;
233
234 if (ip)
235 *ip = count;
236 return (array);
237 }
238
239 /* Convert an array of strings into the form used internally by the shell.
240 COPY means to copy the values in ARRAY into the returned list rather
241 than allocate new storage. STARTING_INDEX says where in ARRAY to begin. */
242 WORD_LIST *
243 argv_to_word_list (array, copy, starting_index)
244 char **array;
245 int copy, starting_index;
246 {
247 WORD_LIST *list;
248 WORD_DESC *w;
249 int i, count;
250
251 if (array == 0 || array[0] == 0)
252 return (WORD_LIST *)NULL;
253
254 for (count = 0; array[count]; count++)
255 ;
256
257 for (i = starting_index, list = (WORD_LIST *)NULL; i < count; i++)
258 {
259 w = make_bare_word (copy ? "" : array[i]);
260 if (copy)
261 {
262 free (w->word);
263 w->word = array[i];
264 }
265 list = make_word_list (w, list);
266 }
267 return (REVERSE_LIST(list, WORD_LIST *));
268 }
269
270 /* **************************************************************** */
271 /* */
272 /* String Management Functions */
273 /* */
274 /* **************************************************************** */
275
276 /* Replace occurrences of PAT with REP in STRING. If GLOBAL is non-zero,
277 replace all occurrences, otherwise replace only the first.
278 This returns a new string; the caller should free it. */
279 char *
280 strsub (string, pat, rep, global)
281 char *string, *pat, *rep;
282 int global;
283 {
284 int patlen, templen, tempsize, repl, i;
285 char *temp, *r;
286
287 patlen = strlen (pat);
288 for (temp = (char *)NULL, i = templen = tempsize = 0, repl = 1; string[i]; )
289 {
290 if (repl && STREQN (string + i, pat, patlen))
291 {
292 RESIZE_MALLOCED_BUFFER (temp, templen, patlen, tempsize, (patlen * 2));
293
294 for (r = rep; *r; )
295 temp[templen++] = *r++;
296
297 i += patlen;
298 repl = global != 0;
299 }
300 else
301 {
302 RESIZE_MALLOCED_BUFFER (temp, templen, 1, tempsize, 16);
303 temp[templen++] = string[i++];
304 }
305 }
306 temp[templen] = 0;
307 return (temp);
308 }
309
310 /* Remove all leading whitespace from STRING. This includes
311 newlines. STRING should be terminated with a zero. */
312 void
313 strip_leading (string)
314 char *string;
315 {
316 char *start = string;
317
318 while (*string && (whitespace (*string) || *string == '\n'))
319 string++;
320
321 if (string != start)
322 {
323 int len = strlen (string);
324 FASTCOPY (string, start, len);
325 start[len] = '\0';
326 }
327 }
328
329 /* Remove all trailing whitespace from STRING. This includes
330 newlines. If NEWLINES_ONLY is non-zero, only trailing newlines
331 are removed. STRING should be terminated with a zero. */
332 void
333 strip_trailing (string, newlines_only)
334 char *string;
335 int newlines_only;
336 {
337 int len = strlen (string) - 1;
338
339 while (len >= 0)
340 {
341 if ((newlines_only && string[len] == '\n') ||
342 (!newlines_only && whitespace (string[len])))
343 len--;
344 else
345 break;
346 }
347 string[len + 1] = '\0';
348 }
349
350 /* Determine if s2 occurs in s1. If so, return a pointer to the
351 match in s1. The compare is case insensitive. This is a
352 case-insensitive strstr(3). */
353 char *
354 strindex (s1, s2)
355 char *s1, *s2;
356 {
357 register int i, l, len, c;
358
359 c = to_upper (s2[0]);
360 for (i = 0, len = strlen (s1), l = strlen (s2); (len - i) >= l; i++)
361 if ((to_upper (s1[i]) == c) && (strncasecmp (s1 + i, s2, l) == 0))
362 return (s1 + i);
363 return ((char *)NULL);
364 }
365
366 /* A wrapper for bcopy that can be prototyped in general.h */
367 void
368 xbcopy (s, d, n)
369 char *s, *d;
370 int n;
371 {
372 FASTCOPY (s, d, n);
373 }