Annotation of src/usr.bin/make/str.c, Revision 1.10
1.10 ! espie 1: /* $OpenBSD: str.c,v 1.9 1999/12/06 22:18:56 espie 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.10 ! espie 46: static char rcsid[] = "$OpenBSD: str.c,v 1.9 1999/12/06 22:18:56 espie 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_Match --
1.5 millert 230: *
1.1 deraadt 231: * See if a particular string matches a particular pattern.
1.5 millert 232: *
1.1 deraadt 233: * Results: Non-zero is returned if string matches pattern, 0 otherwise. The
234: * matching operation permits the following special characters in the
235: * pattern: *?\[] (see the man page for details on what these mean).
1.5 millert 236: *
1.1 deraadt 237: * Side effects: None.
238: */
239: int
240: Str_Match(string, pattern)
241: register char *string; /* String */
242: register char *pattern; /* Pattern */
243: {
244: char c2;
245:
246: for (;;) {
247: /*
248: * See if we're at the end of both the pattern and the
249: * string. If, we succeeded. If we're at the end of the
250: * pattern but not at the end of the string, we failed.
251: */
252: if (*pattern == 0)
253: return(!*string);
254: if (*string == 0 && *pattern != '*')
255: return(0);
256: /*
257: * Check for a "*" as the next pattern character. It matches
258: * any substring. We handle this by calling ourselves
259: * recursively for each postfix of string, until either we
260: * match or we reach the end of the string.
261: */
262: if (*pattern == '*') {
263: pattern += 1;
264: if (*pattern == 0)
265: return(1);
266: while (*string != 0) {
267: if (Str_Match(string, pattern))
268: return(1);
269: ++string;
270: }
271: return(0);
272: }
273: /*
274: * Check for a "?" as the next pattern character. It matches
275: * any single character.
276: */
277: if (*pattern == '?')
278: goto thisCharOK;
279: /*
280: * Check for a "[" as the next pattern character. It is
281: * followed by a list of characters that are acceptable, or
282: * by a range (two characters separated by "-").
283: */
284: if (*pattern == '[') {
285: ++pattern;
286: for (;;) {
287: if ((*pattern == ']') || (*pattern == 0))
288: return(0);
289: if (*pattern == *string)
290: break;
291: if (pattern[1] == '-') {
292: c2 = pattern[2];
293: if (c2 == 0)
294: return(0);
295: if ((*pattern <= *string) &&
296: (c2 >= *string))
297: break;
298: if ((*pattern >= *string) &&
299: (c2 <= *string))
300: break;
301: pattern += 2;
302: }
303: ++pattern;
304: }
305: while ((*pattern != ']') && (*pattern != 0))
306: ++pattern;
307: goto thisCharOK;
308: }
309: /*
310: * If the next pattern character is '/', just strip off the
311: * '/' so we do exact matching on the character that follows.
312: */
313: if (*pattern == '\\') {
314: ++pattern;
315: if (*pattern == 0)
316: return(0);
317: }
318: /*
319: * There's no special character. Just make sure that the
320: * next characters of each string match.
321: */
322: if (*pattern != *string)
323: return(0);
324: thisCharOK: ++pattern;
325: ++string;
326: }
327: }
328:
329:
330: /*-
331: *-----------------------------------------------------------------------
332: * Str_SYSVMatch --
1.5 millert 333: * Check word against pattern for a match (% is wild),
334: *
1.1 deraadt 335: * Results:
336: * Returns the beginning position of a match or null. The number
337: * of characters matched is returned in len.
338: *
339: * Side Effects:
340: * None
341: *
342: *-----------------------------------------------------------------------
343: */
344: char *
345: Str_SYSVMatch(word, pattern, len)
346: char *word; /* Word to examine */
347: char *pattern; /* Pattern to examine against */
348: int *len; /* Number of characters to substitute */
349: {
350: char *p = pattern;
351: char *w = word;
352: char *m;
353:
354: if (*p == '\0') {
355: /* Null pattern is the whole string */
356: *len = strlen(w);
357: return w;
358: }
359:
360: if ((m = strchr(p, '%')) != NULL) {
361: /* check that the prefix matches */
362: for (; p != m && *w && *w == *p; w++, p++)
363: continue;
364:
365: if (p != m)
366: return NULL; /* No match */
367:
368: if (*++p == '\0') {
369: /* No more pattern, return the rest of the string */
370: *len = strlen(w);
371: return w;
372: }
373: }
374:
375: m = w;
376:
377: /* Find a matching tail */
378: do
379: if (strcmp(p, w) == 0) {
380: *len = w - m;
381: return m;
382: }
383: while (*w++ != '\0');
1.5 millert 384:
1.1 deraadt 385: return NULL;
386: }
387:
388:
389: /*-
390: *-----------------------------------------------------------------------
391: * Str_SYSVSubst --
392: * Substitute '%' on the pattern with len characters from src.
393: * If the pattern does not contain a '%' prepend len characters
394: * from src.
1.5 millert 395: *
1.1 deraadt 396: * Results:
397: * None
398: *
399: * Side Effects:
400: * Places result on buf
401: *
402: *-----------------------------------------------------------------------
403: */
404: void
405: Str_SYSVSubst(buf, pat, src, len)
406: Buffer buf;
407: char *pat;
408: char *src;
409: int len;
410: {
411: char *m;
412:
413: if ((m = strchr(pat, '%')) != NULL) {
414: /* Copy the prefix */
1.10 ! espie 415: Buf_AddChars(buf, m - pat, pat);
1.1 deraadt 416: /* skip the % */
417: pat = m + 1;
418: }
419:
420: /* Copy the pattern */
1.10 ! espie 421: Buf_AddChars(buf, len, src);
1.1 deraadt 422:
423: /* append the rest */
1.10 ! espie 424: Buf_AddChars(buf, strlen(pat), pat);
1.9 espie 425: }
426:
427: char *
428: interval_dup(begin, end)
429: const char *begin;
430: const char *end;
431: {
432: char *s;
433:
434: s = emalloc(end - begin + 1);
435: memcpy(s, begin, end - begin);
436: s[end-begin] = '\0';
437: return s;
1.1 deraadt 438: }