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