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