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