]> git.ipfire.org Git - thirdparty/bash.git/blob - stringlib.c
Imported from ../bash-2.04.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, 59 Temple Place, Suite 330, Boston, MA 02111 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 #include "pathexp.h"
36
37 #if defined (EXTENDED_GLOB)
38 # include <glob/fnmatch.h>
39 #endif
40
41 #ifndef to_upper
42 # define to_upper(c) (islower(c) ? toupper(c) : (c))
43 # define to_lower(c) (isupper(c) ? tolower(c) : (c))
44 #endif
45
46 #define ISOCTAL(c) ((c) >= '0' && (c) <= '7')
47 #define OCTVALUE(c) ((c) - '0')
48
49 #ifndef isxdigit
50 # define isxdigit(c) (isdigit((c)) || ((c) >= 'a' && (c) <= 'f') || ((c) >= 'A' && (c) <= 'F'))
51 #endif
52
53 #define HEXVALUE(c) \
54 ((c) >= 'a' && (c) <= 'f' ? (c)-'a'+10 : (c) >= 'A' && (c) <= 'F' ? (c)-'A'+10 : (c)-'0')
55
56 /* Convert STRING by expanding the escape sequences specified by the
57 ANSI C standard. If SAWC is non-null, recognize `\c' and use that
58 as a string terminator. If we see \c, set *SAWC to 1 before
59 returning. LEN is the length of STRING. FOR_ECHO is a flag that
60 means, if non-zero, that we're translating a string for `echo -e',
61 and therefore should not treat a single quote as a character that
62 may be escaped with a backslash. */
63 char *
64 ansicstr (string, len, for_echo, sawc, rlen)
65 char *string;
66 int len, for_echo, *sawc, *rlen;
67 {
68 int c, temp;
69 char *ret, *r, *s;
70
71 if (string == 0 || *string == '\0')
72 return ((char *)NULL);
73
74 ret = xmalloc (len + 1);
75 for (r = ret, s = string; s && *s; )
76 {
77 c = *s++;
78 if (c != '\\' || *s == '\0')
79 *r++ = c;
80 else
81 {
82 switch (c = *s++)
83 {
84 #if defined (__STDC__)
85 case 'a': c = '\a'; break;
86 case 'v': c = '\v'; break;
87 #else
88 case 'a': c = '\007'; break;
89 case 'v': c = (int) 0x0B; break;
90 #endif
91 case 'b': c = '\b'; break;
92 case 'e': case 'E': /* ESC -- non-ANSI */
93 c = '\033'; break;
94 case 'f': c = '\f'; break;
95 case 'n': c = '\n'; break;
96 case 'r': c = '\r'; break;
97 case 't': c = '\t'; break;
98 case '0': case '1': case '2': case '3':
99 case '4': case '5': case '6': case '7':
100 for (temp = 2, c -= '0'; ISOCTAL (*s) && temp--; s++)
101 c = (c * 8) + OCTVALUE (*s);
102 break;
103 case 'x': /* Hex digit -- non-ANSI */
104 for (temp = 3, c = 0; isxdigit (*s) && temp--; s++)
105 c = (c * 16) + HEXVALUE (*s);
106 /* \x followed by non-hex digits is passed through unchanged */
107 if (temp == 3)
108 {
109 *r++ = '\\';
110 c = 'x';
111 }
112 break;
113 case '\\':
114 break;
115 case '\'':
116 if (for_echo)
117 *r++ = '\\';
118 break;
119 case 'c':
120 if (sawc)
121 {
122 *sawc = 1;
123 *r = '\0';
124 if (rlen)
125 *rlen = r - ret;
126 return ret;
127 }
128 default: *r++ = '\\'; break;
129 }
130 *r++ = c;
131 }
132 }
133 *r = '\0';
134 if (rlen)
135 *rlen = r - ret;
136 return ret;
137 }
138
139 /* **************************************************************** */
140 /* */
141 /* Functions to manage arrays of strings */
142 /* */
143 /* **************************************************************** */
144
145 #ifdef INCLUDE_UNUSED
146 /* Find NAME in ARRAY. Return the index of NAME, or -1 if not present.
147 ARRAY should be NULL terminated. */
148 int
149 find_name_in_array (name, array)
150 char *name, **array;
151 {
152 int i;
153
154 for (i = 0; array[i]; i++)
155 if (STREQ (name, array[i]))
156 return (i);
157
158 return (-1);
159 }
160 #endif
161
162 /* Allocate an array of strings with room for N members. */
163 char **
164 alloc_array (n)
165 int n;
166 {
167 return ((char **)xmalloc ((n) * sizeof (char *)));
168 }
169
170 /* Return the length of ARRAY, a NULL terminated array of char *. */
171 int
172 array_len (array)
173 char **array;
174 {
175 register int i;
176
177 for (i = 0; array[i]; i++);
178 return (i);
179 }
180
181 /* Free the contents of ARRAY, a NULL terminated array of char *. */
182 void
183 free_array_members (array)
184 char **array;
185 {
186 register int i;
187
188 if (array == 0)
189 return;
190
191 for (i = 0; array[i]; i++)
192 free (array[i]);
193 }
194
195 void
196 free_array (array)
197 char **array;
198 {
199 if (array == 0)
200 return;
201
202 free_array_members (array);
203 free (array);
204 }
205
206 /* Allocate and return a new copy of ARRAY and its contents. */
207 char **
208 copy_array (array)
209 char **array;
210 {
211 register int i;
212 int len;
213 char **new_array;
214
215 len = array_len (array);
216
217 new_array = (char **)xmalloc ((len + 1) * sizeof (char *));
218 for (i = 0; array[i]; i++)
219 new_array[i] = savestring (array[i]);
220 new_array[i] = (char *)NULL;
221
222 return (new_array);
223 }
224
225 /* Comparison routine for use with qsort() on arrays of strings. Uses
226 strcoll(3) if available, otherwise it uses strcmp(3). */
227 int
228 qsort_string_compare (s1, s2)
229 register char **s1, **s2;
230 {
231 #if defined (HAVE_STRCOLL)
232 return (strcoll (*s1, *s2));
233 #else /* !HAVE_STRCOLL */
234 int result;
235
236 if ((result = **s1 - **s2) == 0)
237 result = strcmp (*s1, *s2);
238
239 return (result);
240 #endif /* !HAVE_STRCOLL */
241 }
242
243 /* Sort ARRAY, a null terminated array of pointers to strings. */
244 void
245 sort_char_array (array)
246 char **array;
247 {
248 qsort (array, array_len (array), sizeof (char *),
249 (Function *)qsort_string_compare);
250 }
251
252 /* Cons up a new array of words. The words are taken from LIST,
253 which is a WORD_LIST *. If COPY is true, everything is malloc'ed,
254 so you should free everything in this array when you are done.
255 The array is NULL terminated. If IP is non-null, it gets the
256 number of words in the returned array. STARTING_INDEX says where
257 to start filling in the returned array; it can be used to reserve
258 space at the beginning of the array. */
259 char **
260 word_list_to_argv (list, copy, starting_index, ip)
261 WORD_LIST *list;
262 int copy, starting_index, *ip;
263 {
264 int count;
265 char **array;
266
267 count = list_length (list);
268 array = (char **)xmalloc ((1 + count + starting_index) * sizeof (char *));
269
270 for (count = 0; count < starting_index; count++)
271 array[count] = (char *)NULL;
272 for (count = starting_index; list; count++, list = list->next)
273 array[count] = copy ? savestring (list->word->word) : list->word->word;
274 array[count] = (char *)NULL;
275
276 if (ip)
277 *ip = count;
278 return (array);
279 }
280
281 /* Convert an array of strings into the form used internally by the shell.
282 COPY means to copy the values in ARRAY into the returned list rather
283 than allocate new storage. STARTING_INDEX says where in ARRAY to begin. */
284 WORD_LIST *
285 argv_to_word_list (array, copy, starting_index)
286 char **array;
287 int copy, starting_index;
288 {
289 WORD_LIST *list;
290 WORD_DESC *w;
291 int i, count;
292
293 if (array == 0 || array[0] == 0)
294 return (WORD_LIST *)NULL;
295
296 for (count = 0; array[count]; count++)
297 ;
298
299 for (i = starting_index, list = (WORD_LIST *)NULL; i < count; i++)
300 {
301 w = make_bare_word (copy ? "" : array[i]);
302 if (copy)
303 {
304 free (w->word);
305 w->word = array[i];
306 }
307 list = make_word_list (w, list);
308 }
309 return (REVERSE_LIST(list, WORD_LIST *));
310 }
311
312 /* Find STRING in ALIST, a list of string key/int value pairs. If FLAGS
313 is 1, STRING is treated as a pattern and matched using fnmatch. */
314 int
315 find_string_in_alist (string, alist, flags)
316 char *string;
317 STRING_INT_ALIST *alist;
318 int flags;
319 {
320 register int i;
321 int r;
322
323 for (i = r = 0; alist[i].word; i++)
324 {
325 #if defined (EXTENDED_GLOB)
326 if (flags)
327 r = fnmatch (alist[i].word, string, FNM_EXTMATCH) != FNM_NOMATCH;
328 else
329 #endif
330 r = STREQ (string, alist[i].word);
331
332 if (r)
333 return (alist[i].token);
334 }
335 return -1;
336 }
337
338 /* **************************************************************** */
339 /* */
340 /* String Management Functions */
341 /* */
342 /* **************************************************************** */
343
344 /* Replace occurrences of PAT with REP in STRING. If GLOBAL is non-zero,
345 replace all occurrences, otherwise replace only the first.
346 This returns a new string; the caller should free it. */
347 char *
348 strsub (string, pat, rep, global)
349 char *string, *pat, *rep;
350 int global;
351 {
352 int patlen, replen, templen, tempsize, repl, i;
353 char *temp, *r;
354
355 patlen = strlen (pat);
356 replen = strlen (rep);
357 for (temp = (char *)NULL, i = templen = tempsize = 0, repl = 1; string[i]; )
358 {
359 if (repl && STREQN (string + i, pat, patlen))
360 {
361 RESIZE_MALLOCED_BUFFER (temp, templen, replen, tempsize, (replen * 2));
362
363 for (r = rep; *r; )
364 temp[templen++] = *r++;
365
366 i += patlen;
367 repl = global != 0;
368 }
369 else
370 {
371 RESIZE_MALLOCED_BUFFER (temp, templen, 1, tempsize, 16);
372 temp[templen++] = string[i++];
373 }
374 }
375 temp[templen] = 0;
376 return (temp);
377 }
378
379 /* Replace all instances of C in STRING with TEXT. TEXT may be empty or
380 NULL. If DO_GLOB is non-zero, we quote the replacement text for
381 globbing. Backslash may be used to quote C. */
382 char *
383 strcreplace (string, c, text, do_glob)
384 char *string;
385 int c;
386 char *text;
387 int do_glob;
388 {
389 char *ret, *p, *r, *t;
390 int len, rlen, ind, tlen;
391
392 len = STRLEN (text);
393 rlen = len + strlen (string) + 2;
394 ret = xmalloc (rlen);
395
396 for (p = string, r = ret; p && *p; )
397 {
398 if (*p == c)
399 {
400 if (len)
401 {
402 ind = r - ret;
403 if (do_glob && (glob_pattern_p (text) || strchr (text, '\\')))
404 {
405 t = quote_globbing_chars (text);
406 tlen = strlen (t);
407 RESIZE_MALLOCED_BUFFER (ret, ind, tlen, rlen, rlen);
408 r = ret + ind; /* in case reallocated */
409 strcpy (r, t);
410 r += tlen;
411 free (t);
412 }
413 else
414 {
415 RESIZE_MALLOCED_BUFFER (ret, ind, len, rlen, rlen);
416 r = ret + ind; /* in case reallocated */
417 strcpy (r, text);
418 r += len;
419 }
420 }
421 p++;
422 continue;
423 }
424
425 if (*p == '\\' && p[1] == '&')
426 p++;
427
428 *r++ = *p++;
429 }
430 *r = '\0';
431
432 return ret;
433 }
434
435 #ifdef INCLUDE_UNUSED
436 /* Remove all leading whitespace from STRING. This includes
437 newlines. STRING should be terminated with a zero. */
438 void
439 strip_leading (string)
440 char *string;
441 {
442 char *start = string;
443
444 while (*string && (whitespace (*string) || *string == '\n'))
445 string++;
446
447 if (string != start)
448 {
449 int len = strlen (string);
450 FASTCOPY (string, start, len);
451 start[len] = '\0';
452 }
453 }
454 #endif
455
456 /* Remove all trailing whitespace from STRING. This includes
457 newlines. If NEWLINES_ONLY is non-zero, only trailing newlines
458 are removed. STRING should be terminated with a zero. */
459 void
460 strip_trailing (string, len, newlines_only)
461 char *string;
462 int len;
463 int newlines_only;
464 {
465 while (len >= 0)
466 {
467 if ((newlines_only && string[len] == '\n') ||
468 (!newlines_only && whitespace (string[len])))
469 len--;
470 else
471 break;
472 }
473 string[len + 1] = '\0';
474 }
475
476 /* Determine if s2 occurs in s1. If so, return a pointer to the
477 match in s1. The compare is case insensitive. This is a
478 case-insensitive strstr(3). */
479 char *
480 strindex (s1, s2)
481 char *s1, *s2;
482 {
483 register int i, l, len, c;
484
485 c = to_upper (s2[0]);
486 for (i = 0, len = strlen (s1), l = strlen (s2); (len - i) >= l; i++)
487 if ((to_upper (s1[i]) == c) && (strncasecmp (s1 + i, s2, l) == 0))
488 return (s1 + i);
489 return ((char *)NULL);
490 }
491
492 /* A wrapper for bcopy that can be prototyped in general.h */
493 void
494 xbcopy (s, d, n)
495 char *s, *d;
496 int n;
497 {
498 FASTCOPY (s, d, n);
499 }