d232837dd9f492e48204afbc8d7860604b097b5c
[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 /* **************************************************************** */
42 /*                                                                  */
43 /*              Functions to manage arrays of strings               */
44 /*                                                                  */
45 /* **************************************************************** */
46
47 /* Cons up a new array of words.  The words are taken from LIST,
48    which is a WORD_LIST *.  If COPY is true, everything is malloc'ed,
49    so you should free everything in this array when you are done.
50    The array is NULL terminated.  If IP is non-null, it gets the
51    number of words in the returned array.  STARTING_INDEX says where
52    to start filling in the returned array; it can be used to reserve
53    space at the beginning of the array. */
54 char **
55 word_list_to_argv (list, copy, starting_index, ip)
56      WORD_LIST *list;
57      int copy, starting_index, *ip;
58 {
59   int count;
60   char **array;
61
62   count = list_length (list);
63   array = (char **)xmalloc ((1 + count + starting_index) * sizeof (char *));
64
65   for (count = 0; count < starting_index; count++)
66     array[count] = (char *)NULL;
67   for (count = starting_index; list; count++, list = list->next)
68     array[count] = copy ? savestring (list->word->word) : list->word->word;
69   array[count] = (char *)NULL;
70
71   if (ip)
72     *ip = count;
73   return (array);
74 }
75
76 /* Convert an array of strings into the form used internally by the shell.
77    COPY means to copy the values in ARRAY into the returned list rather
78    than allocate new storage.  STARTING_INDEX says where in ARRAY to begin. */
79 WORD_LIST *
80 argv_to_word_list (array, copy, starting_index)
81      char **array;
82      int copy, starting_index;
83 {
84   WORD_LIST *list;
85   WORD_DESC *w;
86   int i, count;
87
88   if (array == 0 || array[0] == 0)
89     return (WORD_LIST *)NULL;
90
91   for (count = 0; array[count]; count++)
92     ;
93
94   for (i = starting_index, list = (WORD_LIST *)NULL; i < count; i++)
95     {
96       w = make_bare_word (copy ? "" : array[i]);
97       if (copy)
98         {
99           free (w->word);
100           w->word = array[i];
101         }
102       list = make_word_list (w, list);
103     }
104   return (REVERSE_LIST(list, WORD_LIST *));
105 }
106
107 /* Find STRING in ALIST, a list of string key/int value pairs.  If FLAGS
108    is 1, STRING is treated as a pattern and matched using fnmatch. */
109 int
110 find_string_in_alist (string, alist, flags)
111      char *string;
112      STRING_INT_ALIST *alist;
113      int flags;
114 {
115   register int i;
116   int r;
117
118   for (i = r = 0; alist[i].word; i++)
119     {
120 #if defined (EXTENDED_GLOB)
121       if (flags)
122         r = fnmatch (alist[i].word, string, FNM_EXTMATCH) != FNM_NOMATCH;
123       else
124 #endif
125         r = STREQ (string, alist[i].word);
126
127       if (r)
128         return (alist[i].token);
129     }
130   return -1;
131 }
132
133 /* **************************************************************** */
134 /*                                                                  */
135 /*                  String Management Functions                     */
136 /*                                                                  */
137 /* **************************************************************** */
138
139 /* Replace occurrences of PAT with REP in STRING.  If GLOBAL is non-zero,
140    replace all occurrences, otherwise replace only the first.
141    This returns a new string; the caller should free it. */
142 char *
143 strsub (string, pat, rep, global)
144      char *string, *pat, *rep;
145      int global;
146 {
147   int patlen, replen, templen, tempsize, repl, i;
148   char *temp, *r;
149
150   patlen = strlen (pat);
151   replen = strlen (rep);
152   for (temp = (char *)NULL, i = templen = tempsize = 0, repl = 1; string[i]; )
153     {
154       if (repl && STREQN (string + i, pat, patlen))
155         {
156           RESIZE_MALLOCED_BUFFER (temp, templen, replen, tempsize, (replen * 2));
157
158           for (r = rep; *r; )
159             temp[templen++] = *r++;
160
161           i += patlen;
162           repl = global != 0;
163         }
164       else
165         {
166           RESIZE_MALLOCED_BUFFER (temp, templen, 1, tempsize, 16);
167           temp[templen++] = string[i++];
168         }
169     }
170   temp[templen] = 0;
171   return (temp);
172 }
173
174 /* Replace all instances of C in STRING with TEXT.  TEXT may be empty or
175    NULL.  If DO_GLOB is non-zero, we quote the replacement text for
176    globbing.  Backslash may be used to quote C. */
177 char *
178 strcreplace (string, c, text, do_glob)
179      char *string;
180      int c;
181      char *text;
182      int do_glob;
183 {
184   char *ret, *p, *r, *t;
185   int len, rlen, ind, tlen;
186
187   len = STRLEN (text);
188   rlen = len + strlen (string) + 2;
189   ret = xmalloc (rlen);
190
191   for (p = string, r = ret; p && *p; )
192     {
193       if (*p == c)
194         {
195           if (len)
196             {
197               ind = r - ret;
198               if (do_glob && (glob_pattern_p (text) || strchr (text, '\\')))
199                 {
200                   t = quote_globbing_chars (text);
201                   tlen = strlen (t);
202                   RESIZE_MALLOCED_BUFFER (ret, ind, tlen, rlen, rlen);
203                   r = ret + ind;        /* in case reallocated */
204                   strcpy (r, t);
205                   r += tlen;
206                   free (t);
207                 }
208               else
209                 {
210                   RESIZE_MALLOCED_BUFFER (ret, ind, len, rlen, rlen);
211                   r = ret + ind;        /* in case reallocated */
212                   strcpy (r, text);
213                   r += len;
214                 }
215             }
216           p++;
217           continue;
218         }
219
220       if (*p == '\\' && p[1] == c)
221         p++;
222
223       RESIZE_MALLOCED_BUFFER (ret, ind, 2, rlen, rlen);
224       r = ret + ind;                    /* in case reallocated */
225       *r++ = *p++;
226     }
227   *r = '\0';
228
229   return ret;
230 }
231
232 #ifdef INCLUDE_UNUSED
233 /* Remove all leading whitespace from STRING.  This includes
234    newlines.  STRING should be terminated with a zero. */
235 void
236 strip_leading (string)
237      char *string;
238 {
239   char *start = string;
240
241   while (*string && (whitespace (*string) || *string == '\n'))
242     string++;
243
244   if (string != start)
245     {
246       int len = strlen (string);
247       FASTCOPY (string, start, len);
248       start[len] = '\0';
249     }
250 }
251 #endif
252
253 /* Remove all trailing whitespace from STRING.  This includes
254    newlines.  If NEWLINES_ONLY is non-zero, only trailing newlines
255    are removed.  STRING should be terminated with a zero. */
256 void
257 strip_trailing (string, len, newlines_only)
258      char *string;
259      int len;
260      int newlines_only;
261 {
262   while (len >= 0)
263     {
264       if ((newlines_only && string[len] == '\n') ||
265           (!newlines_only && whitespace (string[len])))
266         len--;
267       else
268         break;
269     }
270   string[len + 1] = '\0';
271 }
272
273 /* A wrapper for bcopy that can be prototyped in general.h */
274 void
275 xbcopy (s, d, n)
276      char *s, *d;
277      int n;
278 {
279   FASTCOPY (s, d, n);
280 }