Commit | Line | Data |
---|---|---|
e72c71e5 WJ |
1 | /*- |
2 | * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. | |
3 | * Copyright (c) 1988, 1989 by Adam de Boor | |
4 | * Copyright (c) 1989 by Berkeley Softworks | |
5 | * All rights reserved. | |
6 | * | |
7 | * This code is derived from software contributed to Berkeley by | |
8 | * Adam de Boor. | |
9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | |
15 | * 2. Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution. | |
18 | * 3. All advertising materials mentioning features or use of this software | |
19 | * must display the following acknowledgement: | |
20 | * This product includes software developed by the University of | |
21 | * California, Berkeley and its contributors. | |
22 | * 4. Neither the name of the University nor the names of its contributors | |
23 | * may be used to endorse or promote products derived from this software | |
24 | * without specific prior written permission. | |
25 | * | |
26 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
27 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
28 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
29 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
30 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
31 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
32 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
33 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
34 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
35 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
36 | * SUCH DAMAGE. | |
37 | */ | |
38 | ||
39 | #ifndef lint | |
40 | static char sccsid[] = "@(#)str.c 5.8 (Berkeley) 6/1/90"; | |
41 | #endif /* not lint */ | |
42 | ||
43 | #include "make.h" | |
44 | ||
45 | /*- | |
46 | * str_concat -- | |
47 | * concatenate the two strings, inserting a space or slash between them, | |
48 | * freeing them if requested. | |
49 | * | |
50 | * returns -- | |
51 | * the resulting string in allocated space. | |
52 | */ | |
53 | char * | |
54 | str_concat(s1, s2, flags) | |
55 | char *s1, *s2; | |
56 | int flags; | |
57 | { | |
58 | register int len1, len2; | |
59 | register char *result; | |
60 | ||
61 | /* get the length of both strings */ | |
62 | len1 = strlen(s1); | |
63 | len2 = strlen(s2); | |
64 | ||
65 | /* allocate length plus separator plus EOS */ | |
66 | result = emalloc((u_int)(len1 + len2 + 2)); | |
67 | ||
68 | /* copy first string into place */ | |
69 | bcopy(s1, result, len1); | |
70 | ||
71 | /* add separator character */ | |
72 | if (flags & STR_ADDSPACE) { | |
73 | result[len1] = ' '; | |
74 | ++len1; | |
75 | } else if (flags & STR_ADDSLASH) { | |
76 | result[len1] = '/'; | |
77 | ++len1; | |
78 | } | |
79 | ||
80 | /* copy second string plus EOS into place */ | |
81 | bcopy(s2, result + len1, len2 + 1); | |
82 | ||
83 | /* free original strings */ | |
84 | if (flags & STR_DOFREE) { | |
85 | (void)free(s1); | |
86 | (void)free(s2); | |
87 | } | |
88 | return(result); | |
89 | } | |
90 | ||
91 | /*- | |
92 | * brk_string -- | |
93 | * Fracture a string into an array of words (as delineated by tabs or | |
94 | * spaces) taking quotation marks into account. Leading tabs/spaces | |
95 | * are ignored. | |
96 | * | |
97 | * returns -- | |
98 | * Pointer to the array of pointers to the words. To make life easier, | |
99 | * the first word is always the value of the .MAKE variable. | |
100 | */ | |
101 | char ** | |
102 | brk_string(str, store_argc) | |
103 | register char *str; | |
104 | int *store_argc; | |
105 | { | |
106 | static int argmax, curlen; | |
107 | static char **argv, *buf; | |
108 | register int argc, ch; | |
109 | register char inquote, *p, *start, *t; | |
110 | int len; | |
111 | ||
112 | /* save off pmake variable */ | |
113 | if (!argv) { | |
114 | argv = (char **)emalloc((argmax = 50) * sizeof(char *)); | |
115 | argv[0] = Var_Value(".MAKE", VAR_GLOBAL); | |
116 | } | |
117 | ||
118 | /* skip leading space chars. | |
119 | for (; *str == ' ' || *str == '\t'; ++str); | |
120 | ||
121 | /* allocate room for a copy of the string */ | |
122 | if ((len = strlen(str) + 1) > curlen) | |
123 | buf = emalloc(curlen = len); | |
124 | ||
125 | /* | |
126 | * copy the string; at the same time, parse backslashes, | |
127 | * quotes and build the argument list. | |
128 | */ | |
129 | argc = 1; | |
130 | inquote = '\0'; | |
131 | for (p = str, start = t = buf;; ++p) { | |
132 | switch(ch = *p) { | |
133 | case '"': | |
134 | case '\'': | |
135 | if (inquote) | |
136 | if (inquote == ch) | |
137 | inquote = NULL; | |
138 | else | |
139 | break; | |
140 | else | |
141 | inquote = ch; | |
142 | continue; | |
143 | case ' ': | |
144 | case '\t': | |
145 | if (inquote) | |
146 | break; | |
147 | if (!start) | |
148 | continue; | |
149 | /* FALLTHROUGH */ | |
150 | case '\n': | |
151 | case '\0': | |
152 | /* | |
153 | * end of a token -- make sure there's enough argv | |
154 | * space and save off a pointer. | |
155 | */ | |
156 | *t++ = '\0'; | |
157 | if (argc == argmax) { | |
158 | argmax *= 2; /* ramp up fast */ | |
159 | if (!(argv = (char **)realloc(argv, | |
160 | argmax * sizeof(char *)))) | |
161 | enomem(); | |
162 | } | |
163 | argv[argc++] = start; | |
164 | start = (char *)NULL; | |
165 | if (ch == '\n' || ch == '\0') | |
166 | goto done; | |
167 | continue; | |
168 | case '\\': | |
169 | switch (ch = *++p) { | |
170 | case '\0': | |
171 | case '\n': | |
172 | /* hmmm; fix it up as best we can */ | |
173 | ch = '\\'; | |
174 | --p; | |
175 | break; | |
176 | case 'b': | |
177 | ch = '\b'; | |
178 | break; | |
179 | case 'f': | |
180 | ch = '\f'; | |
181 | break; | |
182 | case 'n': | |
183 | ch = '\n'; | |
184 | break; | |
185 | case 'r': | |
186 | ch = '\r'; | |
187 | break; | |
188 | case 't': | |
189 | ch = '\t'; | |
190 | break; | |
191 | } | |
192 | break; | |
193 | } | |
194 | if (!start) | |
195 | start = t; | |
196 | *t++ = ch; | |
197 | } | |
198 | done: argv[argc] = (char *)NULL; | |
199 | *store_argc = argc; | |
200 | return(argv); | |
201 | } | |
202 | ||
203 | /* | |
204 | * Str_FindSubstring -- See if a string contains a particular substring. | |
205 | * | |
206 | * Results: If string contains substring, the return value is the location of | |
207 | * the first matching instance of substring in string. If string doesn't | |
208 | * contain substring, the return value is NULL. Matching is done on an exact | |
209 | * character-for-character basis with no wildcards or special characters. | |
210 | * | |
211 | * Side effects: None. | |
212 | */ | |
213 | char * | |
214 | Str_FindSubstring(string, substring) | |
215 | register char *string; /* String to search. */ | |
216 | char *substring; /* Substring to find in string */ | |
217 | { | |
218 | register char *a, *b; | |
219 | ||
220 | /* | |
221 | * First scan quickly through the two strings looking for a single- | |
222 | * character match. When it's found, then compare the rest of the | |
223 | * substring. | |
224 | */ | |
225 | ||
226 | for (b = substring; *string != 0; string += 1) { | |
227 | if (*string != *b) | |
228 | continue; | |
229 | a = string; | |
230 | for (;;) { | |
231 | if (*b == 0) | |
232 | return(string); | |
233 | if (*a++ != *b++) | |
234 | break; | |
235 | } | |
236 | b = substring; | |
237 | } | |
238 | return((char *) NULL); | |
239 | } | |
240 | ||
241 | /* | |
242 | * Str_Match -- | |
243 | * | |
244 | * See if a particular string matches a particular pattern. | |
245 | * | |
246 | * Results: Non-zero is returned if string matches pattern, 0 otherwise. The | |
247 | * matching operation permits the following special characters in the | |
248 | * pattern: *?\[] (see the man page for details on what these mean). | |
249 | * | |
250 | * Side effects: None. | |
251 | */ | |
252 | Str_Match(string, pattern) | |
253 | register char *string; /* String */ | |
254 | register char *pattern; /* Pattern */ | |
255 | { | |
256 | char c2; | |
257 | ||
258 | for (;;) { | |
259 | /* | |
260 | * See if we're at the end of both the pattern and the | |
261 | * string. If, we succeeded. If we're at the end of the | |
262 | * pattern but not at the end of the string, we failed. | |
263 | */ | |
264 | if (*pattern == 0) | |
265 | return(!*string); | |
266 | if (*string == 0 && *pattern != '*') | |
267 | return(0); | |
268 | /* | |
269 | * Check for a "*" as the next pattern character. It matches | |
270 | * any substring. We handle this by calling ourselves | |
271 | * recursively for each postfix of string, until either we | |
272 | * match or we reach the end of the string. | |
273 | */ | |
274 | if (*pattern == '*') { | |
275 | pattern += 1; | |
276 | if (*pattern == 0) | |
277 | return(1); | |
278 | while (*string != 0) { | |
279 | if (Str_Match(string, pattern)) | |
280 | return(1); | |
281 | ++string; | |
282 | } | |
283 | return(0); | |
284 | } | |
285 | /* | |
286 | * Check for a "?" as the next pattern character. It matches | |
287 | * any single character. | |
288 | */ | |
289 | if (*pattern == '?') | |
290 | goto thisCharOK; | |
291 | /* | |
292 | * Check for a "[" as the next pattern character. It is | |
293 | * followed by a list of characters that are acceptable, or | |
294 | * by a range (two characters separated by "-"). | |
295 | */ | |
296 | if (*pattern == '[') { | |
297 | ++pattern; | |
298 | for (;;) { | |
299 | if ((*pattern == ']') || (*pattern == 0)) | |
300 | return(0); | |
301 | if (*pattern == *string) | |
302 | break; | |
303 | if (pattern[1] == '-') { | |
304 | c2 = pattern[2]; | |
305 | if (c2 == 0) | |
306 | return(0); | |
307 | if ((*pattern <= *string) && | |
308 | (c2 >= *string)) | |
309 | break; | |
310 | if ((*pattern >= *string) && | |
311 | (c2 <= *string)) | |
312 | break; | |
313 | pattern += 2; | |
314 | } | |
315 | ++pattern; | |
316 | } | |
317 | while ((*pattern != ']') && (*pattern != 0)) | |
318 | ++pattern; | |
319 | goto thisCharOK; | |
320 | } | |
321 | /* | |
322 | * If the next pattern character is '/', just strip off the | |
323 | * '/' so we do exact matching on the character that follows. | |
324 | */ | |
325 | if (*pattern == '\\') { | |
326 | ++pattern; | |
327 | if (*pattern == 0) | |
328 | return(0); | |
329 | } | |
330 | /* | |
331 | * There's no special character. Just make sure that the | |
332 | * next characters of each string match. | |
333 | */ | |
334 | if (*pattern != *string) | |
335 | return(0); | |
336 | thisCharOK: ++pattern; | |
337 | ++string; | |
338 | } | |
339 | } |