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