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