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