1 /* stringlib.c - Miscellaneous string functions. */
2 
3 /* Copyright (C) 1996-2009 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
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation, either version 3 of the License, or
10    (at your option) any later version.
11 
12    Bash is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16 
17    You should have received a copy of the GNU General Public License
18    along with Bash.  If not, see <http://www.gnu.org/licenses/>.
19 */
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
find_string_in_alist(string,alist,flags)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 *
find_token_in_alist(token,alist,flags)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
find_index_in_alist(string,alist,flags)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 *
substring(string,start,end)127 substring (string, start, end)
128      const 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   memcpy (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 *
strsub(string,pat,rep,global)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; )	/* can rep == "" */
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   if (temp)
174     temp[templen] = 0;
175   else
176     temp = savestring (string);
177   return (temp);
178 }
179 
180 /* Replace all instances of C in STRING with TEXT.  TEXT may be empty or
181    NULL.  If DO_GLOB is non-zero, we quote the replacement text for
182    globbing.  Backslash may be used to quote C. */
183 char *
strcreplace(string,c,text,do_glob)184 strcreplace (string, c, text, do_glob)
185      char *string;
186      int c;
187      const char *text;
188      int do_glob;
189 {
190   char *ret, *p, *r, *t;
191   int len, rlen, ind, tlen;
192 
193   len = STRLEN (text);
194   rlen = len + strlen (string) + 2;
195   ret = (char *)xmalloc (rlen);
196 
197   for (p = string, r = ret; p && *p; )
198     {
199       if (*p == c)
200 	{
201 	  if (len)
202 	    {
203 	      ind = r - ret;
204 	      if (do_glob && (glob_pattern_p (text) || strchr (text, '\\')))
205 		{
206 		  t = quote_globbing_chars (text);
207 		  tlen = strlen (t);
208 		  RESIZE_MALLOCED_BUFFER (ret, ind, tlen, rlen, rlen);
209 		  r = ret + ind;	/* in case reallocated */
210 		  strcpy (r, t);
211 		  r += tlen;
212 		  free (t);
213 		}
214 	      else
215 		{
216 		  RESIZE_MALLOCED_BUFFER (ret, ind, len, rlen, rlen);
217 		  r = ret + ind;	/* in case reallocated */
218 		  strcpy (r, text);
219 		  r += len;
220 		}
221 	    }
222 	  p++;
223 	  continue;
224 	}
225 
226       if (*p == '\\' && p[1] == c)
227 	p++;
228 
229       ind = r - ret;
230       RESIZE_MALLOCED_BUFFER (ret, ind, 2, rlen, rlen);
231       r = ret + ind;			/* in case reallocated */
232       *r++ = *p++;
233     }
234   *r = '\0';
235 
236   return ret;
237 }
238 
239 #ifdef INCLUDE_UNUSED
240 /* Remove all leading whitespace from STRING.  This includes
241    newlines.  STRING should be terminated with a zero. */
242 void
strip_leading(string)243 strip_leading (string)
244      char *string;
245 {
246   char *start = string;
247 
248   while (*string && (whitespace (*string) || *string == '\n'))
249     string++;
250 
251   if (string != start)
252     {
253       int len = strlen (string);
254       FASTCOPY (string, start, len);
255       start[len] = '\0';
256     }
257 }
258 #endif
259 
260 /* Remove all trailing whitespace from STRING.  This includes
261    newlines.  If NEWLINES_ONLY is non-zero, only trailing newlines
262    are removed.  STRING should be terminated with a zero. */
263 void
strip_trailing(string,len,newlines_only)264 strip_trailing (string, len, newlines_only)
265      char *string;
266      int len;
267      int newlines_only;
268 {
269   while (len >= 0)
270     {
271       if ((newlines_only && string[len] == '\n') ||
272 	  (!newlines_only && whitespace (string[len])))
273 	len--;
274       else
275 	break;
276     }
277   string[len + 1] = '\0';
278 }
279 
280 /* A wrapper for bcopy that can be prototyped in general.h */
281 void
xbcopy(s,d,n)282 xbcopy (s, d, n)
283      char *s, *d;
284      int n;
285 {
286   FASTCOPY (s, d, n);
287 }
288