Annotation of src/usr.bin/make/str.c, Revision 1.17
1.17 ! espie 1: /* $OpenPackages$ */
! 2: /* $OpenBSD: str.c,v 1.7 1998/12/05 00:06:29 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.17 ! espie 50: static char rcsid[] = "$OpenBSD: str.c,v 1.7 1998/12/05 00:06:29 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 */
86: memcpy(result + len1, s2, len2 + 1);
87: return result;
1.1 deraadt 88: }
89:
90: /*-
91: * brk_string --
92: * Fracture a string into an array of words (as delineated by tabs or
93: * spaces) taking quotation marks into account. Leading tabs/spaces
94: * are ignored.
95: *
96: * returns --
1.17 ! espie 97: * Pointer to the array of pointers to the words. To make life easier,
1.1 deraadt 98: * the first word is always the value of the .MAKE variable.
99: */
100: char **
1.17 ! espie 101: brk_string(str, store_argc, buffer)
! 102: const char *str;
! 103: int *store_argc;
! 104: char **buffer;
1.1 deraadt 105: {
1.17 ! espie 106: int argc;
! 107: char ch;
! 108: char inquote;
! 109: const char *p;
! 110: char *start, *t;
! 111: size_t len;
! 112: int argmax = 50;
! 113: size_t curlen = 0;
! 114: char **argv = emalloc((argmax + 1) * sizeof(char *));
! 115:
! 116: /* skip leading space chars. */
! 117: for (; *str == ' ' || *str == '\t'; ++str)
! 118: continue;
! 119:
! 120: /* allocate room for a copy of the string */
! 121: if ((len = strlen(str) + 1) > curlen)
! 122: *buffer = emalloc(curlen = len);
! 123:
! 124: /*
! 125: * copy the string; at the same time, parse backslashes,
! 126: * quotes and build the argument list.
! 127: */
! 128: argc = 0;
! 129: inquote = '\0';
! 130: for (p = str, start = t = *buffer;; ++p) {
! 131: switch (ch = *p) {
! 132: case '"':
! 133: case '\'':
! 134: if (inquote) {
! 135: if (inquote == ch)
! 136: inquote = '\0';
! 137: else
! 138: break;
! 139: } else {
! 140: inquote = ch;
! 141: /* Don't miss "" or '' */
! 142: if (start == NULL && p[1] == inquote) {
! 143: start = t + 1;
! 144: break;
! 145: }
! 146: }
! 147: continue;
! 148: case ' ':
! 149: case '\t':
! 150: case '\n':
! 151: if (inquote)
! 152: break;
! 153: if (!start)
1.1 deraadt 154: continue;
1.17 ! espie 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 */
! 167: argv = erealloc(argv, (argmax + 1) * sizeof(char *));
! 168: }
! 169: argv[argc++] = start;
! 170: start = NULL;
! 171: if (ch == '\n' || ch == '\0')
! 172: goto done;
! 173: continue;
! 174: case '\\':
! 175: switch (ch = *++p) {
! 176: case '\0':
! 177: case '\n':
! 178: /* hmmm; fix it up as best we can */
! 179: ch = '\\';
! 180: --p;
! 181: break;
! 182: case 'b':
! 183: ch = '\b';
! 184: break;
! 185: case 'f':
! 186: ch = '\f';
! 187: break;
! 188: case 'n':
! 189: ch = '\n';
! 190: break;
! 191: case 'r':
! 192: ch = '\r';
! 193: break;
! 194: case 't':
! 195: ch = '\t';
! 196: break;
! 197: }
! 198: break;
1.1 deraadt 199: }
1.17 ! espie 200: if (!start)
! 201: start = t;
! 202: *t++ = ch;
! 203: }
! 204: done:
! 205: argv[argc] = NULL;
! 206: *store_argc = argc;
! 207: return argv;
1.1 deraadt 208: }
209:
1.16 espie 210: /* Iterate through a string word by word,
211: * without needing to copy anything.
212: * More light-weight than brk_string, handles \ ' " as well.
213: *
214: * position = s;
215: * while ((begin = iterate_words(&position)) != NULL) {
216: * do_something_with_word_interval(begin, position);
217: * }
218: */
219: const char *
220: iterate_words(end)
1.17 ! espie 221: const char **end;
1.16 espie 222: {
1.17 ! espie 223: const char *start, *p;
1.16 espie 224: char state = 0;
225: start = *end;
226:
227: while (isspace(*start))
1.17 ! espie 228: start++;
1.16 espie 229: if (*start == '\0')
1.17 ! espie 230: return NULL;
1.16 espie 231:
232: for (p = start;; p++)
1.17 ! espie 233: switch(*p) {
1.16 espie 234: case '\\':
1.17 ! espie 235: if (p[1] != '\0')
1.16 espie 236: p++;
237: break;
238: case '\'':
239: case '"':
1.17 ! espie 240: if (state == *p)
1.16 espie 241: state = 0;
242: else if (state == 0)
243: state = *p;
244: break;
245: case ' ':
246: case '\t':
1.17 ! espie 247: if (state != 0)
1.16 espie 248: break;
1.17 ! espie 249: /* FALLTHROUGH */
1.16 espie 250: case '\0':
1.17 ! espie 251: *end = p;
1.16 espie 252: return start;
253: default:
1.17 ! espie 254: break;
1.16 espie 255: }
256: }
1.17 ! espie 257:
1.1 deraadt 258: /*
1.17 ! espie 259: * Str_Matchi --
1.5 millert 260: *
1.1 deraadt 261: * See if a particular string matches a particular pattern.
1.5 millert 262: *
1.14 espie 263: * Results: TRUE is returned if string matches pattern, FALSE otherwise. The
1.1 deraadt 264: * matching operation permits the following special characters in the
265: * pattern: *?\[] (see the man page for details on what these mean).
266: */
1.14 espie 267: Boolean
1.17 ! espie 268: Str_Matchi(string, pattern, end)
! 269: const char *string; /* String */
1.14 espie 270: const char *pattern; /* Pattern */
1.17 ! espie 271: const char *end; /* End of Pattern */
1.1 deraadt 272: {
1.17 ! espie 273: while (pattern != end) {
1.14 espie 274: /* Check for a "*" as the next pattern character. It matches
275: * any substring. We handle this by calling ourselves
276: * recursively for each postfix of string, until either we
277: * match or we reach the end of the string. */
278: if (*pattern == '*') {
279: pattern++;
280: /* Skip over contiguous sequences of `?*', so that recursive
281: * calls only occur on `real' characters. */
1.17 ! espie 282: while (pattern != end && (*pattern == '?' || *pattern == '*')) {
1.14 espie 283: if (*pattern == '?') {
284: if (*string == '\0')
285: return FALSE;
286: else
287: string++;
288: }
289: pattern++;
290: }
1.17 ! espie 291: if (pattern == end)
1.14 espie 292: return TRUE;
293: for (; *string != '\0'; string++)
1.17 ! espie 294: if (Str_Matchi(string, pattern, end))
1.14 espie 295: return TRUE;
296: return FALSE;
1.17 ! espie 297: } else if (*string == '\0')
1.14 espie 298: return FALSE;
299: /* Check for a "[" as the next pattern character. It is
300: * followed by a list of characters that are acceptable, or
301: * by a range (two characters separated by "-"). */
302: else if (*pattern == '[') {
303: pattern++;
1.17 ! espie 304: if (pattern == end)
! 305: return FALSE;
1.14 espie 306: if (*pattern == '!' || *pattern == '^') {
307: pattern++;
1.17 ! espie 308: if (pattern == end)
1.14 espie 309: return FALSE;
310: /* Negative match */
311: for (;;) {
312: if (*pattern == '\\') {
1.17 ! espie 313: if (++pattern == end)
1.14 espie 314: return FALSE;
315: }
316: if (*pattern == *string)
317: return FALSE;
318: if (pattern[1] == '-') {
1.17 ! espie 319: if (pattern + 2 == end)
1.14 espie 320: return FALSE;
321: if (*pattern < *string && *string <= pattern[2])
322: return FALSE;
323: if (pattern[2] <= *string && *string < *pattern)
324: return FALSE;
325: pattern += 3;
326: } else
327: pattern++;
1.17 ! espie 328: if (pattern == end)
! 329: return FALSE;
1.14 espie 330: /* The test for ']' is done at the end so that ']'
331: * can be used at the start of the range without '\' */
332: if (*pattern == ']')
1.17 ! espie 333: break;
1.1 deraadt 334: }
1.14 espie 335: } else {
336: for (;;) {
337: if (*pattern == '\\') {
1.17 ! espie 338: if (++pattern == end)
1.14 espie 339: return FALSE;
340: }
341: if (*pattern == *string)
342: break;
343: if (pattern[1] == '-') {
1.17 ! espie 344: if (pattern + 2 == end)
1.14 espie 345: return FALSE;
346: if (*pattern < *string && *string <= pattern[2])
347: break;
348: if (pattern[2] <= *string && *string < *pattern)
349: break;
350: pattern += 3;
351: } else
352: pattern++;
353: /* The test for ']' is done at the end so that ']'
354: * can be used at the start of the range without '\' */
1.17 ! espie 355: if (pattern == end || *pattern == ']')
! 356: return FALSE;
1.1 deraadt 357: }
1.14 espie 358: /* Found matching character, skip over rest of class. */
359: while (*pattern != ']') {
360: if (*pattern == '\\')
361: pattern++;
1.17 ! espie 362: /* A non-terminated character class is ok. */
! 363: if (pattern == end)
1.14 espie 364: break;
365: pattern++;
1.1 deraadt 366: }
1.14 espie 367: }
1.1 deraadt 368: }
1.14 espie 369: /* '?' matches any single character, so shunt test. */
370: else if (*pattern != '?') {
371: /* If the next pattern character is '\', just strip off the
372: * '\' so we do exact matching on the character that follows. */
373: if (*pattern == '\\') {
1.17 ! espie 374: if (++pattern == end)
1.14 espie 375: return FALSE;
376: }
1.17 ! espie 377: /* There's no special character. Just make sure that
1.14 espie 378: * the next characters of each string match. */
379: if (*pattern != *string)
380: return FALSE;
381: }
382: pattern++;
383: string++;
384: }
385: if (*string == '\0')
386: return TRUE;
387: else
388: return FALSE;
1.1 deraadt 389: }
390:
1.17 ! espie 391:
1.1 deraadt 392: /*-
393: *-----------------------------------------------------------------------
394: * Str_SYSVMatch --
1.5 millert 395: * Check word against pattern for a match (% is wild),
396: *
1.1 deraadt 397: * Results:
398: * Returns the beginning position of a match or null. The number
399: * of characters matched is returned in len.
400: *-----------------------------------------------------------------------
401: */
1.13 espie 402: const char *
1.1 deraadt 403: Str_SYSVMatch(word, pattern, len)
1.13 espie 404: const char *word; /* Word to examine */
405: const char *pattern; /* Pattern to examine against */
406: size_t *len; /* Number of characters to substitute */
1.1 deraadt 407: {
1.13 espie 408: const char *p = pattern;
409: const char *w = word;
410: const char *m;
1.1 deraadt 411:
412: if (*p == '\0') {
1.17 ! espie 413: /* Null pattern is the whole string. */
1.1 deraadt 414: *len = strlen(w);
415: return w;
416: }
417:
418: if ((m = strchr(p, '%')) != NULL) {
1.17 ! espie 419: /* Check that the prefix matches. */
1.1 deraadt 420: for (; p != m && *w && *w == *p; w++, p++)
421: continue;
422:
423: if (p != m)
1.17 ! espie 424: return NULL; /* No match. */
1.1 deraadt 425:
426: if (*++p == '\0') {
1.17 ! espie 427: /* No more pattern, return the rest of the string. */
1.1 deraadt 428: *len = strlen(w);
429: return w;
430: }
431: }
432:
433: m = w;
434:
1.17 ! espie 435: /* Find a matching tail. */
! 436: do {
1.1 deraadt 437: if (strcmp(p, w) == 0) {
438: *len = w - m;
439: return m;
440: }
1.17 ! espie 441: } while (*w++ != '\0');
! 442:
1.5 millert 443:
1.1 deraadt 444: return NULL;
445: }
446:
447:
448: /*-
449: *-----------------------------------------------------------------------
450: * Str_SYSVSubst --
451: * Substitute '%' on the pattern with len characters from src.
452: * If the pattern does not contain a '%' prepend len characters
453: * from src.
1.5 millert 454: *
1.1 deraadt 455: * Side Effects:
456: * Places result on buf
457: *-----------------------------------------------------------------------
458: */
459: void
460: Str_SYSVSubst(buf, pat, src, len)
461: Buffer buf;
1.13 espie 462: const char *pat;
463: const char *src;
464: size_t len;
1.1 deraadt 465: {
1.13 espie 466: const char *m;
1.1 deraadt 467:
468: if ((m = strchr(pat, '%')) != NULL) {
1.17 ! espie 469: /* Copy the prefix. */
1.11 espie 470: Buf_AddInterval(buf, pat, m);
1.17 ! espie 471: /* Skip the %. */
1.1 deraadt 472: pat = m + 1;
473: }
474:
1.17 ! espie 475: /* Copy the pattern. */
1.10 espie 476: Buf_AddChars(buf, len, src);
1.1 deraadt 477:
1.17 ! espie 478: /* Append the rest. */
1.11 espie 479: Buf_AddString(buf, pat);
1.9 espie 480: }
481:
482: char *
483: interval_dup(begin, end)
484: const char *begin;
485: const char *end;
486: {
487: char *s;
488:
489: s = emalloc(end - begin + 1);
490: memcpy(s, begin, end - begin);
491: s[end-begin] = '\0';
492: return s;
1.1 deraadt 493: }
1.16 espie 494:
495: /* copy interval, skipping characters in the set. */
496: char *
497: escape_dup(begin, end, set)
498: const char *begin;
499: const char *end;
500: const char *set;
501: {
502: char *s, *t;
503:
504: t = s = emalloc(end - begin + 1);
505: while (begin != end) {
1.17 ! espie 506: if (*begin == '\\') {
1.16 espie 507: begin++;
508: if (begin == end) {
1.17 ! espie 509: *t++ = '\\';
1.16 espie 510: break;
511: }
1.17 ! espie 512: if (strchr(set, *begin) == NULL)
! 513: *t++ = '\\';
1.16 espie 514: }
515: *t++ = *begin++;
516: }
517: *t++ = '\0';
518: return s;
519: }
520:
1.17 ! espie 521: char *
! 522: lastchar(s, e, c)
! 523: const char *s;
! 524: const char *e;
! 525: int c;
! 526: {
! 527: if (s != e)
! 528: do {
! 529: if (*--e == c)
! 530: return (char *)e;
! 531: } while (e != s);
! 532: return NULL;
! 533: }