1 /*-
2 * Copyright (c) 1988, 1989, 1990, 1993
3 * The Regents of the University of California. All rights reserved.
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 * %sccs.include.redist.c%
11 */
12
13 #ifndef lint
14 static char sccsid[] = "@(#)str.c 8.6 (Berkeley) 04/28/95";
15 #endif /* not lint */
16
17 #include "make.h"
18
19 static char **argv, *buffer;
20 static int argmax, curlen;
21
22 /*
23 * str_init --
24 * Initialize the strings package
25 *
26 */
27 void
str_init()28 str_init()
29 {
30 char *p1;
31 argv = (char **)emalloc((argmax = 50) * sizeof(char *));
32 argv[0] = Var_Value(".MAKE", VAR_GLOBAL, &p1);
33 }
34
35
36 /*
37 * str_end --
38 * Cleanup the strings package
39 *
40 */
41 void
str_end()42 str_end()
43 {
44 if (argv[0]) {
45 free(argv[0]);
46 free((Address) argv);
47 }
48 if (buffer)
49 free(buffer);
50 }
51
52
53 /*-
54 * str_concat --
55 * concatenate the two strings, inserting a space or slash between them,
56 * freeing them if requested.
57 *
58 * returns --
59 * the resulting string in allocated space.
60 */
61 char *
str_concat(s1,s2,flags)62 str_concat(s1, s2, flags)
63 char *s1, *s2;
64 int flags;
65 {
66 register int len1, len2;
67 register char *result;
68
69 /* get the length of both strings */
70 len1 = strlen(s1);
71 len2 = strlen(s2);
72
73 /* allocate length plus separator plus EOS */
74 result = emalloc((u_int)(len1 + len2 + 2));
75
76 /* copy first string into place */
77 memcpy(result, s1, len1);
78
79 /* add separator character */
80 if (flags & STR_ADDSPACE) {
81 result[len1] = ' ';
82 ++len1;
83 } else if (flags & STR_ADDSLASH) {
84 result[len1] = '/';
85 ++len1;
86 }
87
88 /* copy second string plus EOS into place */
89 memcpy(result + len1, s2, len2 + 1);
90
91 /* free original strings */
92 if (flags & STR_DOFREE) {
93 (void)free(s1);
94 (void)free(s2);
95 }
96 return(result);
97 }
98
99 /*-
100 * brk_string --
101 * Fracture a string into an array of words (as delineated by tabs or
102 * spaces) taking quotation marks into account. Leading tabs/spaces
103 * are ignored.
104 *
105 * returns --
106 * Pointer to the array of pointers to the words. To make life easier,
107 * the first word is always the value of the .MAKE variable.
108 */
109 char **
brk_string(str,store_argc,expand)110 brk_string(str, store_argc, expand)
111 register char *str;
112 int *store_argc;
113 Boolean expand;
114 {
115 register int argc, ch;
116 register char inquote, *p, *start, *t;
117 int len;
118
119 /* skip leading space chars. */
120 for (; *str == ' ' || *str == '\t'; ++str)
121 continue;
122
123 /* allocate room for a copy of the string */
124 if ((len = strlen(str) + 1) > curlen) {
125 if (buffer)
126 free(buffer);
127 buffer = emalloc(curlen = len);
128 }
129
130 /*
131 * copy the string; at the same time, parse backslashes,
132 * quotes and build the argument list.
133 */
134 argc = 1;
135 inquote = '\0';
136 for (p = str, start = t = buffer;; ++p) {
137 switch(ch = *p) {
138 case '"':
139 case '\'':
140 if (inquote)
141 if (inquote == ch)
142 inquote = '\0';
143 else
144 break;
145 else {
146 inquote = (char) ch;
147 /* Don't miss "" or '' */
148 if (start == NULL && p[1] == inquote) {
149 start = t + 1;
150 break;
151 }
152 }
153 if (!expand) {
154 if (!start)
155 start = t;
156 *t++ = ch;
157 }
158 continue;
159 case ' ':
160 case '\t':
161 case '\n':
162 if (inquote)
163 break;
164 if (!start)
165 continue;
166 /* FALLTHROUGH */
167 case '\0':
168 /*
169 * end of a token -- make sure there's enough argv
170 * space and save off a pointer.
171 */
172 if (!start)
173 goto done;
174
175 *t++ = '\0';
176 if (argc == argmax) {
177 argmax *= 2; /* ramp up fast */
178 if (!(argv = (char **)realloc(argv,
179 argmax * sizeof(char *))))
180 enomem();
181 }
182 argv[argc++] = start;
183 start = (char *)NULL;
184 if (ch == '\n' || ch == '\0')
185 goto done;
186 continue;
187 case '\\':
188 if (!expand) {
189 if (!start)
190 start = t;
191 *t++ = '\\';
192 ch = *++p;
193 break;
194 }
195
196 switch (ch = *++p) {
197 case '\0':
198 case '\n':
199 /* hmmm; fix it up as best we can */
200 ch = '\\';
201 --p;
202 break;
203 case 'b':
204 ch = '\b';
205 break;
206 case 'f':
207 ch = '\f';
208 break;
209 case 'n':
210 ch = '\n';
211 break;
212 case 'r':
213 ch = '\r';
214 break;
215 case 't':
216 ch = '\t';
217 break;
218 }
219 break;
220 }
221 if (!start)
222 start = t;
223 *t++ = (char) ch;
224 }
225 done: argv[argc] = (char *)NULL;
226 *store_argc = argc;
227 return(argv);
228 }
229
230 /*
231 * Str_FindSubstring -- See if a string contains a particular substring.
232 *
233 * Results: If string contains substring, the return value is the location of
234 * the first matching instance of substring in string. If string doesn't
235 * contain substring, the return value is NULL. Matching is done on an exact
236 * character-for-character basis with no wildcards or special characters.
237 *
238 * Side effects: None.
239 */
240 char *
Str_FindSubstring(string,substring)241 Str_FindSubstring(string, substring)
242 register char *string; /* String to search. */
243 char *substring; /* Substring to find in string */
244 {
245 register char *a, *b;
246
247 /*
248 * First scan quickly through the two strings looking for a single-
249 * character match. When it's found, then compare the rest of the
250 * substring.
251 */
252
253 for (b = substring; *string != 0; string += 1) {
254 if (*string != *b)
255 continue;
256 a = string;
257 for (;;) {
258 if (*b == 0)
259 return(string);
260 if (*a++ != *b++)
261 break;
262 }
263 b = substring;
264 }
265 return((char *) NULL);
266 }
267
268 /*
269 * Str_Match --
270 *
271 * See if a particular string matches a particular pattern.
272 *
273 * Results: Non-zero is returned if string matches pattern, 0 otherwise. The
274 * matching operation permits the following special characters in the
275 * pattern: *?\[] (see the man page for details on what these mean).
276 *
277 * Side effects: None.
278 */
279 int
Str_Match(string,pattern)280 Str_Match(string, pattern)
281 register char *string; /* String */
282 register char *pattern; /* Pattern */
283 {
284 char c2;
285
286 for (;;) {
287 /*
288 * See if we're at the end of both the pattern and the
289 * string. If, we succeeded. If we're at the end of the
290 * pattern but not at the end of the string, we failed.
291 */
292 if (*pattern == 0)
293 return(!*string);
294 if (*string == 0 && *pattern != '*')
295 return(0);
296 /*
297 * Check for a "*" as the next pattern character. It matches
298 * any substring. We handle this by calling ourselves
299 * recursively for each postfix of string, until either we
300 * match or we reach the end of the string.
301 */
302 if (*pattern == '*') {
303 pattern += 1;
304 if (*pattern == 0)
305 return(1);
306 while (*string != 0) {
307 if (Str_Match(string, pattern))
308 return(1);
309 ++string;
310 }
311 return(0);
312 }
313 /*
314 * Check for a "?" as the next pattern character. It matches
315 * any single character.
316 */
317 if (*pattern == '?')
318 goto thisCharOK;
319 /*
320 * Check for a "[" as the next pattern character. It is
321 * followed by a list of characters that are acceptable, or
322 * by a range (two characters separated by "-").
323 */
324 if (*pattern == '[') {
325 ++pattern;
326 for (;;) {
327 if ((*pattern == ']') || (*pattern == 0))
328 return(0);
329 if (*pattern == *string)
330 break;
331 if (pattern[1] == '-') {
332 c2 = pattern[2];
333 if (c2 == 0)
334 return(0);
335 if ((*pattern <= *string) &&
336 (c2 >= *string))
337 break;
338 if ((*pattern >= *string) &&
339 (c2 <= *string))
340 break;
341 pattern += 2;
342 }
343 ++pattern;
344 }
345 while ((*pattern != ']') && (*pattern != 0))
346 ++pattern;
347 goto thisCharOK;
348 }
349 /*
350 * If the next pattern character is '/', just strip off the
351 * '/' so we do exact matching on the character that follows.
352 */
353 if (*pattern == '\\') {
354 ++pattern;
355 if (*pattern == 0)
356 return(0);
357 }
358 /*
359 * There's no special character. Just make sure that the
360 * next characters of each string match.
361 */
362 if (*pattern != *string)
363 return(0);
364 thisCharOK: ++pattern;
365 ++string;
366 }
367 }
368
369
370 /*-
371 *-----------------------------------------------------------------------
372 * Str_SYSVMatch --
373 * Check word against pattern for a match (% is wild),
374 *
375 * Results:
376 * Returns the beginning position of a match or null. The number
377 * of characters matched is returned in len.
378 *
379 * Side Effects:
380 * None
381 *
382 *-----------------------------------------------------------------------
383 */
384 char *
Str_SYSVMatch(word,pattern,len)385 Str_SYSVMatch(word, pattern, len)
386 char *word; /* Word to examine */
387 char *pattern; /* Pattern to examine against */
388 int *len; /* Number of characters to substitute */
389 {
390 char *p = pattern;
391 char *w = word;
392 char *m;
393
394 if (*p == '\0') {
395 /* Null pattern is the whole string */
396 *len = strlen(w);
397 return w;
398 }
399
400 if ((m = strchr(p, '%')) != NULL) {
401 /* check that the prefix matches */
402 for (; p != m && *w && *w == *p; w++, p++)
403 continue;
404
405 if (p != m)
406 return NULL; /* No match */
407
408 if (*++p == '\0') {
409 /* No more pattern, return the rest of the string */
410 *len = strlen(w);
411 return w;
412 }
413 }
414
415 m = w;
416
417 /* Find a matching tail */
418 do
419 if (strcmp(p, w) == 0) {
420 *len = w - m;
421 return m;
422 }
423 while (*w++ != '\0');
424
425 return NULL;
426 }
427
428
429 /*-
430 *-----------------------------------------------------------------------
431 * Str_SYSVSubst --
432 * Substitute '%' on the pattern with len characters from src.
433 * If the pattern does not contain a '%' prepend len characters
434 * from src.
435 *
436 * Results:
437 * None
438 *
439 * Side Effects:
440 * Places result on buf
441 *
442 *-----------------------------------------------------------------------
443 */
444 void
Str_SYSVSubst(buf,pat,src,len)445 Str_SYSVSubst(buf, pat, src, len)
446 Buffer buf;
447 char *pat;
448 char *src;
449 int len;
450 {
451 char *m;
452
453 if ((m = strchr(pat, '%')) != NULL) {
454 /* Copy the prefix */
455 Buf_AddBytes(buf, m - pat, (Byte *) pat);
456 /* skip the % */
457 pat = m + 1;
458 }
459
460 /* Copy the pattern */
461 Buf_AddBytes(buf, len, (Byte *) src);
462
463 /* append the rest */
464 Buf_AddBytes(buf, strlen(pat), (Byte *) pat);
465 }
466