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