Imported from ../bash-2.02.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 #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
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. */
55 char *
56 ansicstr (string, len, sawc, rlen)
57      char *string;
58      int len, *sawc, *rlen;
59 {
60   int c, temp;
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;
84             case 'e': case 'E':         /* ESC -- non-ANSI */
85               c = '\033'; break;
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':
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                 }
104               break;
105             case '\\':
106             case '\'':
107               break;
108             case 'c':
109               if (sawc)
110                 {
111                   *sawc = 1;
112                   *r = '\0';
113                   if (rlen)
114                     *rlen = r - ret;
115                   return ret;
116                 }
117             default:  *r++ = '\\'; break;
118             }
119           *r++ = c;
120         }
121     }
122   *r = '\0';
123   if (rlen)
124     *rlen = r - ret;
125   return ret;
126 }
127
128 /* **************************************************************** */
129 /*                                                                  */
130 /*              Functions to manage arrays of strings               */
131 /*                                                                  */
132 /* **************************************************************** */
133
134 #ifdef INCLUDE_UNUSED
135 /* Find NAME in ARRAY.  Return the index of NAME, or -1 if not present.
136    ARRAY should be NULL terminated. */
137 int
138 find_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 }
149 #endif
150
151 /* Return the length of ARRAY, a NULL terminated array of char *. */
152 int
153 array_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 *. */
163 void
164 free_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
176 void
177 free_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. */
188 char **
189 copy_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). */
208 int
209 qsort_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. */
225 void
226 sort_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. */
240 char **
241 word_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. */
265 WORD_LIST *
266 argv_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. */
302 char *
303 strsub (string, pat, rep, global)
304      char *string, *pat, *rep;
305      int global;
306 {
307   int patlen, replen, templen, tempsize, repl, i;
308   char *temp, *r;
309
310   patlen = strlen (pat);
311   replen = strlen (rep);
312   for (temp = (char *)NULL, i = templen = tempsize = 0, repl = 1; string[i]; )
313     {
314       if (repl && STREQN (string + i, pat, patlen))
315         {
316           RESIZE_MALLOCED_BUFFER (temp, templen, replen, tempsize, (replen * 2));
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
334 #ifdef INCLUDE_UNUSED
335 /* Remove all leading whitespace from STRING.  This includes
336    newlines.  STRING should be terminated with a zero. */
337 void
338 strip_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 }
353 #endif
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. */
358 void
359 strip_trailing (string, len, newlines_only)
360      char *string;
361      int len;
362      int newlines_only;
363 {
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). */
378 char *
379 strindex (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 */
392 void
393 xbcopy (s, d, n)
394      char *s, *d;
395      int n;
396 {
397   FASTCOPY (s, d, n);
398 }