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