Commit | Line | Data |
---|---|---|
1503f905 | 1 | /*- |
9320ab9e | 2 | * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. |
ab950546 KB |
3 | * Copyright (c) 1988, 1989 by Adam de Boor |
4 | * Copyright (c) 1989 by Berkeley Softworks | |
9320ab9e | 5 | * All rights reserved. |
ab950546 | 6 | * |
9320ab9e KB |
7 | * This code is derived from software contributed to Berkeley by |
8 | * Adam de Boor. | |
9 | * | |
87198c0c | 10 | * %sccs.include.redist.c% |
9320ab9e KB |
11 | */ |
12 | ||
13 | #ifndef lint | |
87198c0c | 14 | static char sccsid[] = "@(#)str.c 5.8 (Berkeley) %G%"; |
1503f905 | 15 | #endif /* not lint */ |
ab950546 | 16 | |
1503f905 | 17 | #include "make.h" |
ab950546 KB |
18 | |
19 | /*- | |
1503f905 KB |
20 | * str_concat -- |
21 | * concatenate the two strings, inserting a space or slash between them, | |
22 | * freeing them if requested. | |
ab950546 | 23 | * |
1503f905 KB |
24 | * returns -- |
25 | * the resulting string in allocated space. | |
ab950546 KB |
26 | */ |
27 | char * | |
1503f905 KB |
28 | str_concat(s1, s2, flags) |
29 | char *s1, *s2; | |
30 | int flags; | |
ab950546 | 31 | { |
1503f905 KB |
32 | register int len1, len2; |
33 | register char *result; | |
ab950546 | 34 | |
1503f905 KB |
35 | /* get the length of both strings */ |
36 | len1 = strlen(s1); | |
37 | len2 = strlen(s2); | |
ab950546 | 38 | |
1503f905 KB |
39 | /* allocate length plus separator plus EOS */ |
40 | result = emalloc((u_int)(len1 + len2 + 2)); | |
ab950546 | 41 | |
1503f905 KB |
42 | /* copy first string into place */ |
43 | bcopy(s1, result, len1); | |
ab950546 | 44 | |
1503f905 KB |
45 | /* add separator character */ |
46 | if (flags & STR_ADDSPACE) { | |
47 | result[len1] = ' '; | |
48 | ++len1; | |
49 | } else if (flags & STR_ADDSLASH) { | |
50 | result[len1] = '/'; | |
51 | ++len1; | |
52 | } | |
ab950546 | 53 | |
1503f905 KB |
54 | /* copy second string plus EOS into place */ |
55 | bcopy(s2, result + len1, len2 + 1); | |
ab950546 | 56 | |
1503f905 KB |
57 | /* free original strings */ |
58 | if (flags & STR_DOFREE) { | |
59 | (void)free(s1); | |
60 | (void)free(s2); | |
61 | } | |
62 | return(result); | |
ab950546 | 63 | } |
182ca07d | 64 | |
ab950546 | 65 | /*- |
1503f905 KB |
66 | * brk_string -- |
67 | * Fracture a string into an array of words (as delineated by tabs or | |
68 | * spaces) taking quotation marks into account. Leading tabs/spaces | |
69 | * are ignored. | |
ab950546 | 70 | * |
1503f905 KB |
71 | * returns -- |
72 | * Pointer to the array of pointers to the words. To make life easier, | |
82fe1445 | 73 | * the first word is always the value of the .MAKE variable. |
ab950546 KB |
74 | */ |
75 | char ** | |
1503f905 KB |
76 | brk_string(str, store_argc) |
77 | register char *str; | |
78 | int *store_argc; | |
ab950546 | 79 | { |
1503f905 KB |
80 | static int argmax, curlen; |
81 | static char **argv, *buf; | |
82 | register int argc, ch; | |
83 | register char inquote, *p, *start, *t; | |
84 | int len; | |
ab950546 | 85 | |
1503f905 KB |
86 | /* save off pmake variable */ |
87 | if (!argv) { | |
88 | argv = (char **)emalloc((argmax = 50) * sizeof(char *)); | |
82fe1445 | 89 | argv[0] = Var_Value(".MAKE", VAR_GLOBAL); |
ab950546 | 90 | } |
1503f905 KB |
91 | |
92 | /* skip leading space chars. | |
93 | for (; *str == ' ' || *str == '\t'; ++str); | |
94 | ||
95 | /* allocate room for a copy of the string */ | |
96 | if ((len = strlen(str) + 1) > curlen) | |
97 | buf = emalloc(curlen = len); | |
98 | ||
ab950546 | 99 | /* |
1503f905 KB |
100 | * copy the string; at the same time, parse backslashes, |
101 | * quotes and build the argument list. | |
ab950546 | 102 | */ |
1503f905 KB |
103 | argc = 1; |
104 | inquote = '\0'; | |
105 | for (p = str, start = t = buf;; ++p) { | |
106 | switch(ch = *p) { | |
107 | case '"': | |
108 | case '\'': | |
109 | if (inquote) | |
110 | if (inquote == ch) | |
111 | inquote = NULL; | |
112 | else | |
113 | break; | |
114 | else | |
115 | inquote = ch; | |
116 | continue; | |
117 | case ' ': | |
118 | case '\t': | |
119 | if (inquote) | |
120 | break; | |
121 | if (!start) | |
122 | continue; | |
123 | /* FALLTHROUGH */ | |
124 | case '\n': | |
125 | case '\0': | |
126 | /* | |
127 | * end of a token -- make sure there's enough argv | |
128 | * space and save off a pointer. | |
129 | */ | |
130 | *t++ = '\0'; | |
131 | if (argc == argmax) { | |
132 | argmax *= 2; /* ramp up fast */ | |
133 | if (!(argv = (char **)realloc(argv, | |
134 | argmax * sizeof(char *)))) | |
135 | enomem(); | |
136 | } | |
137 | argv[argc++] = start; | |
138 | start = (char *)NULL; | |
139 | if (ch == '\n' || ch == '\0') | |
140 | goto done; | |
141 | continue; | |
142 | case '\\': | |
143 | switch (ch = *++p) { | |
144 | case '\0': | |
145 | case '\n': | |
146 | /* hmmm; fix it up as best we can */ | |
147 | ch = '\\'; | |
148 | --p; | |
149 | break; | |
150 | case 'b': | |
151 | ch = '\b'; | |
152 | break; | |
153 | case 'f': | |
154 | ch = '\f'; | |
155 | break; | |
156 | case 'n': | |
157 | ch = '\n'; | |
158 | break; | |
159 | case 'r': | |
160 | ch = '\r'; | |
161 | break; | |
162 | case 't': | |
163 | ch = '\t'; | |
164 | break; | |
165 | } | |
166 | break; | |
167 | } | |
168 | if (!start) | |
169 | start = t; | |
170 | *t++ = ch; | |
171 | } | |
172 | done: argv[argc] = (char *)NULL; | |
173 | *store_argc = argc; | |
174 | return(argv); | |
ab950546 | 175 | } |
182ca07d | 176 | |
ab950546 | 177 | /* |
1503f905 KB |
178 | * Str_FindSubstring -- See if a string contains a particular substring. |
179 | * | |
180 | * Results: If string contains substring, the return value is the location of | |
181 | * the first matching instance of substring in string. If string doesn't | |
182 | * contain substring, the return value is NULL. Matching is done on an exact | |
183 | * character-for-character basis with no wildcards or special characters. | |
184 | * | |
185 | * Side effects: None. | |
ab950546 KB |
186 | */ |
187 | char * | |
188 | Str_FindSubstring(string, substring) | |
1503f905 KB |
189 | register char *string; /* String to search. */ |
190 | char *substring; /* Substring to find in string */ | |
ab950546 | 191 | { |
1503f905 | 192 | register char *a, *b; |
ab950546 | 193 | |
1503f905 KB |
194 | /* |
195 | * First scan quickly through the two strings looking for a single- | |
196 | * character match. When it's found, then compare the rest of the | |
197 | * substring. | |
198 | */ | |
199 | ||
200 | for (b = substring; *string != 0; string += 1) { | |
201 | if (*string != *b) | |
202 | continue; | |
203 | a = string; | |
204 | for (;;) { | |
205 | if (*b == 0) | |
206 | return(string); | |
207 | if (*a++ != *b++) | |
208 | break; | |
209 | } | |
210 | b = substring; | |
ab950546 | 211 | } |
1503f905 | 212 | return((char *) NULL); |
ab950546 KB |
213 | } |
214 | ||
ab950546 | 215 | /* |
ab950546 | 216 | * Str_Match -- |
1503f905 KB |
217 | * |
218 | * See if a particular string matches a particular pattern. | |
219 | * | |
220 | * Results: Non-zero is returned if string matches pattern, 0 otherwise. The | |
221 | * matching operation permits the following special characters in the | |
222 | * pattern: *?\[] (see the man page for details on what these mean). | |
223 | * | |
224 | * Side effects: None. | |
ab950546 | 225 | */ |
ab950546 | 226 | Str_Match(string, pattern) |
1503f905 KB |
227 | register char *string; /* String */ |
228 | register char *pattern; /* Pattern */ | |
ab950546 | 229 | { |
1503f905 | 230 | char c2; |
ab950546 | 231 | |
1503f905 KB |
232 | for (;;) { |
233 | /* | |
234 | * See if we're at the end of both the pattern and the | |
235 | * string. If, we succeeded. If we're at the end of the | |
236 | * pattern but not at the end of the string, we failed. | |
237 | */ | |
238 | if (*pattern == 0) | |
239 | return(!*string); | |
240 | if (*string == 0 && *pattern != '*') | |
241 | return(0); | |
242 | /* | |
243 | * Check for a "*" as the next pattern character. It matches | |
244 | * any substring. We handle this by calling ourselves | |
245 | * recursively for each postfix of string, until either we | |
246 | * match or we reach the end of the string. | |
247 | */ | |
248 | if (*pattern == '*') { | |
249 | pattern += 1; | |
250 | if (*pattern == 0) | |
251 | return(1); | |
252 | while (*string != 0) { | |
253 | if (Str_Match(string, pattern)) | |
254 | return(1); | |
255 | ++string; | |
256 | } | |
257 | return(0); | |
258 | } | |
259 | /* | |
260 | * Check for a "?" as the next pattern character. It matches | |
261 | * any single character. | |
262 | */ | |
263 | if (*pattern == '?') | |
264 | goto thisCharOK; | |
265 | /* | |
266 | * Check for a "[" as the next pattern character. It is | |
267 | * followed by a list of characters that are acceptable, or | |
268 | * by a range (two characters separated by "-"). | |
269 | */ | |
270 | if (*pattern == '[') { | |
271 | ++pattern; | |
272 | for (;;) { | |
273 | if ((*pattern == ']') || (*pattern == 0)) | |
274 | return(0); | |
275 | if (*pattern == *string) | |
276 | break; | |
277 | if (pattern[1] == '-') { | |
278 | c2 = pattern[2]; | |
279 | if (c2 == 0) | |
280 | return(0); | |
281 | if ((*pattern <= *string) && | |
282 | (c2 >= *string)) | |
283 | break; | |
284 | if ((*pattern >= *string) && | |
285 | (c2 <= *string)) | |
286 | break; | |
287 | pattern += 2; | |
288 | } | |
289 | ++pattern; | |
290 | } | |
291 | while ((*pattern != ']') && (*pattern != 0)) | |
292 | ++pattern; | |
293 | goto thisCharOK; | |
294 | } | |
295 | /* | |
296 | * If the next pattern character is '/', just strip off the | |
297 | * '/' so we do exact matching on the character that follows. | |
298 | */ | |
299 | if (*pattern == '\\') { | |
300 | ++pattern; | |
301 | if (*pattern == 0) | |
302 | return(0); | |
303 | } | |
304 | /* | |
305 | * There's no special character. Just make sure that the | |
306 | * next characters of each string match. | |
307 | */ | |
308 | if (*pattern != *string) | |
309 | return(0); | |
310 | thisCharOK: ++pattern; | |
311 | ++string; | |
312 | } | |
ab950546 | 313 | } |