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