Imported from ../bash-3.2.48.tar.gz.
[platform/upstream/bash.git] / stringlib.c
1 /* stringlib.c - Miscellaneous string functions. */
2
3 /* Copyright (C) 1996-2002 Free Software Foundation, Inc.
4
5    This file is part of GNU Bash, the Bourne Again SHell.
6
7    Bash is free software; you can redistribute it and/or modify it under
8    the terms of the GNU General Public License as published by the Free
9    Software Foundation; either version 2, or (at your option) any later
10    version.
11
12    Bash is distributed in the hope that it will be useful, but WITHOUT ANY
13    WARRANTY; without even the implied warranty of MERCHANTABILITY or
14    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15    for more details.
16
17    You should have received a copy of the GNU General Public License along
18    with Bash; see the file COPYING.  If not, write to the Free Software
19    Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
20
21 #include "config.h"
22
23 #include "bashtypes.h"
24
25 #if defined (HAVE_UNISTD_H)
26 #  include <unistd.h>
27 #endif
28
29 #include "bashansi.h"
30 #include <stdio.h>
31 #include "chartypes.h"
32
33 #include "shell.h"
34 #include "pathexp.h"
35
36 #include <glob/glob.h>
37
38 #if defined (EXTENDED_GLOB)
39 #  include <glob/strmatch.h>
40 #endif
41
42 /* **************************************************************** */
43 /*                                                                  */
44 /*              Functions to manage arrays of strings               */
45 /*                                                                  */
46 /* **************************************************************** */
47
48 /* Find STRING in ALIST, a list of string key/int value pairs.  If FLAGS
49    is 1, STRING is treated as a pattern and matched using strmatch. */
50 int
51 find_string_in_alist (string, alist, flags)
52      char *string;
53      STRING_INT_ALIST *alist;
54      int flags;
55 {
56   register int i;
57   int r;
58
59   for (i = r = 0; alist[i].word; i++)
60     {
61 #if defined (EXTENDED_GLOB)
62       if (flags)
63         r = strmatch (alist[i].word, string, FNM_EXTMATCH) != FNM_NOMATCH;
64       else
65 #endif
66         r = STREQ (string, alist[i].word);
67
68       if (r)
69         return (alist[i].token);
70     }
71   return -1;
72 }
73
74 /* Find TOKEN in ALIST, a list of string/int value pairs.  Return the
75    corresponding string.  Allocates memory for the returned
76    string.  FLAGS is currently ignored, but reserved. */
77 char *
78 find_token_in_alist (token, alist, flags)
79      int token;
80      STRING_INT_ALIST *alist;
81      int flags;
82 {
83   register int i;
84
85   for (i = 0; alist[i].word; i++)
86     {
87       if (alist[i].token == token)
88         return (savestring (alist[i].word));
89     }
90   return ((char *)NULL);
91 }
92
93 int
94 find_index_in_alist (string, alist, flags)
95      char *string;
96      STRING_INT_ALIST *alist;
97      int flags;
98 {
99   register int i;
100   int r;
101
102   for (i = r = 0; alist[i].word; i++)
103     {
104 #if defined (EXTENDED_GLOB)
105       if (flags)
106         r = strmatch (alist[i].word, string, FNM_EXTMATCH) != FNM_NOMATCH;
107       else
108 #endif
109         r = STREQ (string, alist[i].word);
110
111       if (r)
112         return (i);
113     }
114
115   return -1;
116 }
117
118 /* **************************************************************** */
119 /*                                                                  */
120 /*                  String Management Functions                     */
121 /*                                                                  */
122 /* **************************************************************** */
123
124 /* Cons a new string from STRING starting at START and ending at END,
125    not including END. */
126 char *
127 substring (string, start, end)
128      char *string;
129      int start, end;
130 {
131   register int len;
132   register char *result;
133
134   len = end - start;
135   result = (char *)xmalloc (len + 1);
136   strncpy (result, string + start, len);
137   result[len] = '\0';
138   return (result);
139 }
140
141 /* Replace occurrences of PAT with REP in STRING.  If GLOBAL is non-zero,
142    replace all occurrences, otherwise replace only the first.
143    This returns a new string; the caller should free it. */
144 char *
145 strsub (string, pat, rep, global)
146      char *string, *pat, *rep;
147      int global;
148 {
149   int patlen, replen, templen, tempsize, repl, i;
150   char *temp, *r;
151
152   patlen = strlen (pat);
153   replen = strlen (rep);
154   for (temp = (char *)NULL, i = templen = tempsize = 0, repl = 1; string[i]; )
155     {
156       if (repl && STREQN (string + i, pat, patlen))
157         {
158           if (replen)
159             RESIZE_MALLOCED_BUFFER (temp, templen, replen, tempsize, (replen * 2));
160
161           for (r = rep; *r; )
162             temp[templen++] = *r++;
163
164           i += patlen ? patlen : 1;     /* avoid infinite recursion */
165           repl = global != 0;
166         }
167       else
168         {
169           RESIZE_MALLOCED_BUFFER (temp, templen, 1, tempsize, 16);
170           temp[templen++] = string[i++];
171         }
172     }
173   temp[templen] = 0;
174   return (temp);
175 }
176
177 /* Replace all instances of C in STRING with TEXT.  TEXT may be empty or
178    NULL.  If DO_GLOB is non-zero, we quote the replacement text for
179    globbing.  Backslash may be used to quote C. */
180 char *
181 strcreplace (string, c, text, do_glob)
182      char *string;
183      int c;
184      char *text;
185      int do_glob;
186 {
187   char *ret, *p, *r, *t;
188   int len, rlen, ind, tlen;
189
190   len = STRLEN (text);
191   rlen = len + strlen (string) + 2;
192   ret = (char *)xmalloc (rlen);
193
194   for (p = string, r = ret; p && *p; )
195     {
196       if (*p == c)
197         {
198           if (len)
199             {
200               ind = r - ret;
201               if (do_glob && (glob_pattern_p (text) || strchr (text, '\\')))
202                 {
203                   t = quote_globbing_chars (text);
204                   tlen = strlen (t);
205                   RESIZE_MALLOCED_BUFFER (ret, ind, tlen, rlen, rlen);
206                   r = ret + ind;        /* in case reallocated */
207                   strcpy (r, t);
208                   r += tlen;
209                   free (t);
210                 }
211               else
212                 {
213                   RESIZE_MALLOCED_BUFFER (ret, ind, len, rlen, rlen);
214                   r = ret + ind;        /* in case reallocated */
215                   strcpy (r, text);
216                   r += len;
217                 }
218             }
219           p++;
220           continue;
221         }
222
223       if (*p == '\\' && p[1] == c)
224         p++;
225
226       ind = r - ret;
227       RESIZE_MALLOCED_BUFFER (ret, ind, 2, rlen, rlen);
228       r = ret + ind;                    /* in case reallocated */
229       *r++ = *p++;
230     }
231   *r = '\0';
232
233   return ret;
234 }
235
236 #ifdef INCLUDE_UNUSED
237 /* Remove all leading whitespace from STRING.  This includes
238    newlines.  STRING should be terminated with a zero. */
239 void
240 strip_leading (string)
241      char *string;
242 {
243   char *start = string;
244
245   while (*string && (whitespace (*string) || *string == '\n'))
246     string++;
247
248   if (string != start)
249     {
250       int len = strlen (string);
251       FASTCOPY (string, start, len);
252       start[len] = '\0';
253     }
254 }
255 #endif
256
257 /* Remove all trailing whitespace from STRING.  This includes
258    newlines.  If NEWLINES_ONLY is non-zero, only trailing newlines
259    are removed.  STRING should be terminated with a zero. */
260 void
261 strip_trailing (string, len, newlines_only)
262      char *string;
263      int len;
264      int newlines_only;
265 {
266   while (len >= 0)
267     {
268       if ((newlines_only && string[len] == '\n') ||
269           (!newlines_only && whitespace (string[len])))
270         len--;
271       else
272         break;
273     }
274   string[len + 1] = '\0';
275 }
276
277 /* A wrapper for bcopy that can be prototyped in general.h */
278 void
279 xbcopy (s, d, n)
280      char *s, *d;
281      int n;
282 {
283   FASTCOPY (s, d, n);
284 }