]> git.ipfire.org Git - thirdparty/bash.git/blob - stringlib.c
Bash-5.2 patch 10: slightly relax check for binary script files
[thirdparty/bash.git] / stringlib.c
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
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 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 *
145 strsub (string, pat, rep, global)
146 char *string, *pat, *rep;
147 int global;
148 {
149 size_t patlen, replen, templen, tempsize, i;
150 int repl;
151 char *temp, *r;
152
153 patlen = strlen (pat);
154 replen = strlen (rep);
155 for (temp = (char *)NULL, i = templen = tempsize = 0, repl = 1; string[i]; )
156 {
157 if (repl && STREQN (string + i, pat, patlen))
158 {
159 if (replen)
160 RESIZE_MALLOCED_BUFFER (temp, templen, replen, tempsize, (replen * 2));
161
162 for (r = rep; *r; ) /* can rep == "" */
163 temp[templen++] = *r++;
164
165 i += patlen ? patlen : 1; /* avoid infinite recursion */
166 repl = global != 0;
167 }
168 else
169 {
170 RESIZE_MALLOCED_BUFFER (temp, templen, 1, tempsize, 16);
171 temp[templen++] = string[i++];
172 }
173 }
174 if (temp)
175 temp[templen] = 0;
176 else
177 temp = savestring (string);
178 return (temp);
179 }
180
181 /* Replace all instances of C in STRING with TEXT. TEXT may be empty or
182 NULL. If (FLAGS & 1) is non-zero, we quote the replacement text for
183 globbing. Backslash may be used to quote C. If (FLAGS & 2) we allow
184 backslash to escape backslash as well. */
185 char *
186 strcreplace (string, c, text, flags)
187 char *string;
188 int c;
189 const char *text;
190 int flags;
191 {
192 char *ret, *p, *r, *t;
193 size_t len, rlen, ind, tlen;
194 int do_glob, escape_backslash;
195
196 do_glob = flags & 1;
197 escape_backslash = flags & 2;
198
199 len = STRLEN (text);
200 rlen = len + strlen (string) + 2;
201 ret = (char *)xmalloc (rlen);
202
203 for (p = string, r = ret; p && *p; )
204 {
205 if (*p == c)
206 {
207 if (len)
208 {
209 ind = r - ret;
210 if (do_glob && (glob_pattern_p (text) || strchr (text, '\\')))
211 {
212 t = quote_globbing_chars (text);
213 tlen = strlen (t);
214 RESIZE_MALLOCED_BUFFER (ret, ind, tlen, rlen, rlen);
215 r = ret + ind; /* in case reallocated */
216 strcpy (r, t);
217 r += tlen;
218 free (t);
219 }
220 else
221 {
222 RESIZE_MALLOCED_BUFFER (ret, ind, len, rlen, rlen);
223 r = ret + ind; /* in case reallocated */
224 strcpy (r, text);
225 r += len;
226 }
227 }
228 p++;
229 continue;
230 }
231
232 if (*p == '\\' && p[1] == c)
233 p++;
234 else if (escape_backslash && *p == '\\' && p[1] == '\\')
235 p++;
236
237 ind = r - ret;
238 RESIZE_MALLOCED_BUFFER (ret, ind, 2, rlen, rlen);
239 r = ret + ind; /* in case reallocated */
240 *r++ = *p++;
241 }
242 *r = '\0';
243
244 return ret;
245 }
246
247 #ifdef INCLUDE_UNUSED
248 /* Remove all leading whitespace from STRING. This includes
249 newlines. STRING should be terminated with a zero. */
250 void
251 strip_leading (string)
252 char *string;
253 {
254 char *start = string;
255
256 while (*string && (whitespace (*string) || *string == '\n'))
257 string++;
258
259 if (string != start)
260 {
261 int len = strlen (string);
262 FASTCOPY (string, start, len);
263 start[len] = '\0';
264 }
265 }
266 #endif
267
268 /* Remove all trailing whitespace from STRING. This includes
269 newlines. If NEWLINES_ONLY is non-zero, only trailing newlines
270 are removed. STRING should be terminated with a zero. */
271 void
272 strip_trailing (string, len, newlines_only)
273 char *string;
274 int len;
275 int newlines_only;
276 {
277 while (len >= 0)
278 {
279 if ((newlines_only && string[len] == '\n') ||
280 (!newlines_only && whitespace (string[len])))
281 len--;
282 else
283 break;
284 }
285 string[len + 1] = '\0';
286 }
287
288 /* A wrapper for bcopy that can be prototyped in general.h */
289 void
290 xbcopy (s, d, n)
291 char *s, *d;
292 int n;
293 {
294 FASTCOPY (s, d, n);
295 }