xref: /original-bsd/usr.bin/make/str.c (revision eeb6993a)
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  * %sccs.include.redist.c%
11  */
12 
13 #ifndef lint
14 static char     sccsid[] = "@(#)str.c	5.8 (Berkeley) 06/01/90";
15 #endif				/* not lint */
16 
17 #include "make.h"
18 
19 /*-
20  * str_concat --
21  *	concatenate the two strings, inserting a space or slash between them,
22  *	freeing them if requested.
23  *
24  * returns --
25  *	the resulting string in allocated space.
26  */
27 char *
28 str_concat(s1, s2, flags)
29 	char *s1, *s2;
30 	int flags;
31 {
32 	register int len1, len2;
33 	register char *result;
34 
35 	/* get the length of both strings */
36 	len1 = strlen(s1);
37 	len2 = strlen(s2);
38 
39 	/* allocate length plus separator plus EOS */
40 	result = emalloc((u_int)(len1 + len2 + 2));
41 
42 	/* copy first string into place */
43 	bcopy(s1, result, len1);
44 
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 	}
53 
54 	/* copy second string plus EOS into place */
55 	bcopy(s2, result + len1, len2 + 1);
56 
57 	/* free original strings */
58 	if (flags & STR_DOFREE) {
59 		(void)free(s1);
60 		(void)free(s2);
61 	}
62 	return(result);
63 }
64 
65 /*-
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.
70  *
71  * returns --
72  *	Pointer to the array of pointers to the words.  To make life easier,
73  *	the first word is always the value of the .MAKE variable.
74  */
75 char **
76 brk_string(str, store_argc)
77 	register char *str;
78 	int *store_argc;
79 {
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;
85 
86 	/* save off pmake variable */
87 	if (!argv) {
88 		argv = (char **)emalloc((argmax = 50) * sizeof(char *));
89 		argv[0] = Var_Value(".MAKE", VAR_GLOBAL);
90 	}
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 
99 	/*
100 	 * copy the string; at the same time, parse backslashes,
101 	 * quotes and build the argument list.
102 	 */
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 	}
172 done:	argv[argc] = (char *)NULL;
173 	*store_argc = argc;
174 	return(argv);
175 }
176 
177 /*
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.
186  */
187 char *
188 Str_FindSubstring(string, substring)
189 	register char *string;		/* String to search. */
190 	char *substring;		/* Substring to find in string */
191 {
192 	register char *a, *b;
193 
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;
211 	}
212 	return((char *) NULL);
213 }
214 
215 /*
216  * Str_Match --
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.
225  */
226 Str_Match(string, pattern)
227 	register char *string;		/* String */
228 	register char *pattern;		/* Pattern */
229 {
230 	char c2;
231 
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);
310 thisCharOK:	++pattern;
311 		++string;
312 	}
313 }
314