blob: 3c541656ed83818640f9a21f1b7528baecb63f4a [file] [log] [blame]
Jari Aaltoccc6cda1996-12-23 17:02:34 +00001/* 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
Jari Aaltocce855b1998-04-17 19:52:44 +000041#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
Jari Aaltoccc6cda1996-12-23 17:02:34 +000051/* 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. */
55char *
Jari Aaltod166f041997-06-05 14:59:13 +000056ansicstr (string, len, sawc, rlen)
Jari Aaltoccc6cda1996-12-23 17:02:34 +000057 char *string;
Jari Aaltod166f041997-06-05 14:59:13 +000058 int len, *sawc, *rlen;
Jari Aaltoccc6cda1996-12-23 17:02:34 +000059{
Jari Aaltocce855b1998-04-17 19:52:44 +000060 int c, temp;
Jari Aaltoccc6cda1996-12-23 17:02:34 +000061 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;
Jari Aaltocce855b1998-04-17 19:52:44 +000084 case 'e': case 'E': /* ESC -- non-ANSI */
85 c = '\033'; break;
Jari Aaltoccc6cda1996-12-23 17:02:34 +000086 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':
Jari Aaltocce855b1998-04-17 19:52:44 +000092 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 }
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000104 break;
105 case '\\':
106 case '\'':
107 break;
108 case 'c':
109 if (sawc)
110 {
111 *sawc = 1;
112 *r = '\0';
Jari Aaltod166f041997-06-05 14:59:13 +0000113 if (rlen)
114 *rlen = r - ret;
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000115 return ret;
116 }
117 default: *r++ = '\\'; break;
118 }
119 *r++ = c;
120 }
121 }
122 *r = '\0';
Jari Aaltod166f041997-06-05 14:59:13 +0000123 if (rlen)
124 *rlen = r - ret;
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000125 return ret;
126}
127
128/* **************************************************************** */
129/* */
130/* Functions to manage arrays of strings */
131/* */
132/* **************************************************************** */
133
Jari Aaltocce855b1998-04-17 19:52:44 +0000134#ifdef INCLUDE_UNUSED
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000135/* Find NAME in ARRAY. Return the index of NAME, or -1 if not present.
136 ARRAY should be NULL terminated. */
137int
138find_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}
Jari Aaltocce855b1998-04-17 19:52:44 +0000149#endif
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000150
151/* Return the length of ARRAY, a NULL terminated array of char *. */
152int
153array_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 *. */
163void
164free_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
176void
177free_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. */
188char **
189copy_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). */
208int
209qsort_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. */
225void
226sort_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. */
240char **
241word_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. */
265WORD_LIST *
266argv_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. */
302char *
303strsub (string, pat, rep, global)
304 char *string, *pat, *rep;
305 int global;
306{
Jari Aaltocce855b1998-04-17 19:52:44 +0000307 int patlen, replen, templen, tempsize, repl, i;
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000308 char *temp, *r;
309
310 patlen = strlen (pat);
Jari Aaltocce855b1998-04-17 19:52:44 +0000311 replen = strlen (rep);
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000312 for (temp = (char *)NULL, i = templen = tempsize = 0, repl = 1; string[i]; )
313 {
314 if (repl && STREQN (string + i, pat, patlen))
315 {
Jari Aaltocce855b1998-04-17 19:52:44 +0000316 RESIZE_MALLOCED_BUFFER (temp, templen, replen, tempsize, (replen * 2));
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000317
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
Jari Aaltod166f041997-06-05 14:59:13 +0000334#ifdef INCLUDE_UNUSED
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000335/* Remove all leading whitespace from STRING. This includes
336 newlines. STRING should be terminated with a zero. */
337void
338strip_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}
Jari Aaltod166f041997-06-05 14:59:13 +0000353#endif
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000354
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. */
358void
Jari Aaltod166f041997-06-05 14:59:13 +0000359strip_trailing (string, len, newlines_only)
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000360 char *string;
Jari Aaltod166f041997-06-05 14:59:13 +0000361 int len;
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000362 int newlines_only;
363{
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000364 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). */
378char *
379strindex (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 */
392void
393xbcopy (s, d, n)
394 char *s, *d;
395 int n;
396{
397 FASTCOPY (s, d, n);
398}