|
|
1.1 root 1: /*-
2: * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
3: * Copyright (c) 1988, 1989 by Adam de Boor
4: * Copyright (c) 1989 by Berkeley Softworks
5: * All rights reserved.
6: *
7: * This code is derived from software contributed to Berkeley by
8: * Adam de Boor.
9: *
10: * Redistribution and use in source and binary forms are permitted
11: * provided that: (1) source distributions retain this entire copyright
12: * notice and comment, and (2) distributions including binaries display
13: * the following acknowledgement: ``This product includes software
14: * developed by the University of California, Berkeley and its contributors''
15: * in the documentation or other materials provided with the distribution
16: * and in all advertising materials mentioning features or use of this
17: * software. Neither the name of the University nor the names of its
18: * contributors may be used to endorse or promote products derived
19: * from this software without specific prior written permission.
20: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
21: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
22: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
23: */
24:
25: #ifndef lint
26: static char sccsid[] = "@(#)str.c 5.8 (Berkeley) 6/1/90";
27: #endif /* not lint */
28:
29: #include "make.h"
30:
31: /*-
32: * str_concat --
33: * concatenate the two strings, inserting a space or slash between them,
34: * freeing them if requested.
35: *
36: * returns --
37: * the resulting string in allocated space.
38: */
39: char *
40: str_concat(s1, s2, flags)
41: char *s1, *s2;
42: int flags;
43: {
44: register int len1, len2;
45: register char *result;
46:
47: /* get the length of both strings */
48: len1 = strlen(s1);
49: len2 = strlen(s2);
50:
51: /* allocate length plus separator plus EOS */
52: result = emalloc((u_int)(len1 + len2 + 2));
53:
54: /* copy first string into place */
55: bcopy(s1, result, len1);
56:
57: /* add separator character */
58: if (flags & STR_ADDSPACE) {
59: result[len1] = ' ';
60: ++len1;
61: } else if (flags & STR_ADDSLASH) {
62: result[len1] = '/';
63: ++len1;
64: }
65:
66: /* copy second string plus EOS into place */
67: bcopy(s2, result + len1, len2 + 1);
68:
69: /* free original strings */
70: if (flags & STR_DOFREE) {
71: (void)free(s1);
72: (void)free(s2);
73: }
74: return(result);
75: }
76:
77: /*-
78: * brk_string --
79: * Fracture a string into an array of words (as delineated by tabs or
80: * spaces) taking quotation marks into account. Leading tabs/spaces
81: * are ignored.
82: *
83: * returns --
84: * Pointer to the array of pointers to the words. To make life easier,
85: * the first word is always the value of the .MAKE variable.
86: */
87: char **
88: brk_string(str, store_argc)
89: register char *str;
90: int *store_argc;
91: {
92: static int argmax, curlen;
93: static char **argv, *buf;
94: register int argc, ch;
95: register char inquote, *p, *start, *t;
96: int len;
97:
98: /* save off pmake variable */
99: if (!argv) {
100: argv = (char **)emalloc((argmax = 50) * sizeof(char *));
101: argv[0] = Var_Value(".MAKE", VAR_GLOBAL);
102: }
103:
104: /* skip leading space chars.
105: for (; *str == ' ' || *str == '\t'; ++str);
106:
107: /* allocate room for a copy of the string */
108: if ((len = strlen(str) + 1) > curlen)
109: buf = emalloc(curlen = len);
110:
111: /*
112: * copy the string; at the same time, parse backslashes,
113: * quotes and build the argument list.
114: */
115: argc = 1;
116: inquote = '\0';
117: for (p = str, start = t = buf;; ++p) {
118: switch(ch = *p) {
119: case '"':
120: case '\'':
121: if (inquote)
122: if (inquote == ch)
123: inquote = NULL;
124: else
125: break;
126: else
127: inquote = ch;
128: continue;
129: case ' ':
130: case '\t':
131: if (inquote)
132: break;
133: if (!start)
134: continue;
135: /* FALLTHROUGH */
136: case '\n':
137: case '\0':
138: /*
139: * end of a token -- make sure there's enough argv
140: * space and save off a pointer.
141: */
142: *t++ = '\0';
143: if (argc == argmax) {
144: argmax *= 2; /* ramp up fast */
145: if (!(argv = (char **)realloc(argv,
146: argmax * sizeof(char *))))
147: enomem();
148: }
149: argv[argc++] = start;
150: start = (char *)NULL;
151: if (ch == '\n' || ch == '\0')
152: goto done;
153: continue;
154: case '\\':
155: switch (ch = *++p) {
156: case '\0':
157: case '\n':
158: /* hmmm; fix it up as best we can */
159: ch = '\\';
160: --p;
161: break;
162: case 'b':
163: ch = '\b';
164: break;
165: case 'f':
166: ch = '\f';
167: break;
168: case 'n':
169: ch = '\n';
170: break;
171: case 'r':
172: ch = '\r';
173: break;
174: case 't':
175: ch = '\t';
176: break;
177: }
178: break;
179: }
180: if (!start)
181: start = t;
182: *t++ = ch;
183: }
184: done: argv[argc] = (char *)NULL;
185: *store_argc = argc;
186: return(argv);
187: }
188:
189: /*
190: * Str_FindSubstring -- See if a string contains a particular substring.
191: *
192: * Results: If string contains substring, the return value is the location of
193: * the first matching instance of substring in string. If string doesn't
194: * contain substring, the return value is NULL. Matching is done on an exact
195: * character-for-character basis with no wildcards or special characters.
196: *
197: * Side effects: None.
198: */
199: char *
200: Str_FindSubstring(string, substring)
201: register char *string; /* String to search. */
202: char *substring; /* Substring to find in string */
203: {
204: register char *a, *b;
205:
206: /*
207: * First scan quickly through the two strings looking for a single-
208: * character match. When it's found, then compare the rest of the
209: * substring.
210: */
211:
212: for (b = substring; *string != 0; string += 1) {
213: if (*string != *b)
214: continue;
215: a = string;
216: for (;;) {
217: if (*b == 0)
218: return(string);
219: if (*a++ != *b++)
220: break;
221: }
222: b = substring;
223: }
224: return((char *) NULL);
225: }
226:
227: /*
228: * Str_Match --
229: *
230: * See if a particular string matches a particular pattern.
231: *
232: * Results: Non-zero is returned if string matches pattern, 0 otherwise. The
233: * matching operation permits the following special characters in the
234: * pattern: *?\[] (see the man page for details on what these mean).
235: *
236: * Side effects: None.
237: */
238: Str_Match(string, pattern)
239: register char *string; /* String */
240: register char *pattern; /* Pattern */
241: {
242: char c2;
243:
244: for (;;) {
245: /*
246: * See if we're at the end of both the pattern and the
247: * string. If, we succeeded. If we're at the end of the
248: * pattern but not at the end of the string, we failed.
249: */
250: if (*pattern == 0)
251: return(!*string);
252: if (*string == 0 && *pattern != '*')
253: return(0);
254: /*
255: * Check for a "*" as the next pattern character. It matches
256: * any substring. We handle this by calling ourselves
257: * recursively for each postfix of string, until either we
258: * match or we reach the end of the string.
259: */
260: if (*pattern == '*') {
261: pattern += 1;
262: if (*pattern == 0)
263: return(1);
264: while (*string != 0) {
265: if (Str_Match(string, pattern))
266: return(1);
267: ++string;
268: }
269: return(0);
270: }
271: /*
272: * Check for a "?" as the next pattern character. It matches
273: * any single character.
274: */
275: if (*pattern == '?')
276: goto thisCharOK;
277: /*
278: * Check for a "[" as the next pattern character. It is
279: * followed by a list of characters that are acceptable, or
280: * by a range (two characters separated by "-").
281: */
282: if (*pattern == '[') {
283: ++pattern;
284: for (;;) {
285: if ((*pattern == ']') || (*pattern == 0))
286: return(0);
287: if (*pattern == *string)
288: break;
289: if (pattern[1] == '-') {
290: c2 = pattern[2];
291: if (c2 == 0)
292: return(0);
293: if ((*pattern <= *string) &&
294: (c2 >= *string))
295: break;
296: if ((*pattern >= *string) &&
297: (c2 <= *string))
298: break;
299: pattern += 2;
300: }
301: ++pattern;
302: }
303: while ((*pattern != ']') && (*pattern != 0))
304: ++pattern;
305: goto thisCharOK;
306: }
307: /*
308: * If the next pattern character is '/', just strip off the
309: * '/' so we do exact matching on the character that follows.
310: */
311: if (*pattern == '\\') {
312: ++pattern;
313: if (*pattern == 0)
314: return(0);
315: }
316: /*
317: * There's no special character. Just make sure that the
318: * next characters of each string match.
319: */
320: if (*pattern != *string)
321: return(0);
322: thisCharOK: ++pattern;
323: ++string;
324: }
325: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.