471c8face11db05215bfc0c4e37cecefde60d065
[platform/upstream/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 }