xref: /netbsd-src/usr.bin/make/str.c (revision ae1bfcddc410612bc8c58b807e1830becb69a24c)
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
40 /* from: static char     sccsid[] = "@(#)str.c	5.8 (Berkeley) 6/1/90"; */
41 static char *rcsid = "$Id: str.c,v 1.6 1994/05/17 15:55:42 jtc Exp $";
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 	memcpy(result, s1, 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 	memcpy(result + len1, s2, 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 		continue;
122 
123 	/* allocate room for a copy of the string */
124 	if ((len = strlen(str) + 1) > curlen)
125 		buf = emalloc(curlen = len);
126 
127 	/*
128 	 * copy the string; at the same time, parse backslashes,
129 	 * quotes and build the argument list.
130 	 */
131 	argc = 1;
132 	inquote = '\0';
133 	for (p = str, start = t = buf;; ++p) {
134 		switch(ch = *p) {
135 		case '"':
136 		case '\'':
137 			if (inquote)
138 				if (inquote == ch)
139 					inquote = '\0';
140 				else
141 					break;
142 			else {
143 				inquote = (char) ch;
144 				/* Don't miss "" or '' */
145 				if (start == NULL && p[1] == inquote) {
146 					start = t + 1;
147 					break;
148 				}
149 			}
150 			continue;
151 		case ' ':
152 		case '\t':
153 			if (inquote)
154 				break;
155 			if (!start)
156 				continue;
157 			/* FALLTHROUGH */
158 		case '\n':
159 		case '\0':
160 			/*
161 			 * end of a token -- make sure there's enough argv
162 			 * space and save off a pointer.
163 			 */
164 			*t++ = '\0';
165 			if (argc == argmax) {
166 				argmax *= 2;		/* ramp up fast */
167 				if (!(argv = (char **)realloc(argv,
168 				    argmax * sizeof(char *))))
169 				enomem();
170 			}
171 			argv[argc++] = start;
172 			start = (char *)NULL;
173 			if (ch == '\n' || ch == '\0')
174 				goto done;
175 			continue;
176 		case '\\':
177 			switch (ch = *++p) {
178 			case '\0':
179 			case '\n':
180 				/* hmmm; fix it up as best we can */
181 				ch = '\\';
182 				--p;
183 				break;
184 			case 'b':
185 				ch = '\b';
186 				break;
187 			case 'f':
188 				ch = '\f';
189 				break;
190 			case 'n':
191 				ch = '\n';
192 				break;
193 			case 'r':
194 				ch = '\r';
195 				break;
196 			case 't':
197 				ch = '\t';
198 				break;
199 			}
200 			break;
201 		}
202 		if (!start)
203 			start = t;
204 		*t++ = (char) ch;
205 	}
206 done:	argv[argc] = (char *)NULL;
207 	*store_argc = argc;
208 	return(argv);
209 }
210 
211 /*
212  * Str_FindSubstring -- See if a string contains a particular substring.
213  *
214  * Results: If string contains substring, the return value is the location of
215  * the first matching instance of substring in string.  If string doesn't
216  * contain substring, the return value is NULL.  Matching is done on an exact
217  * character-for-character basis with no wildcards or special characters.
218  *
219  * Side effects: None.
220  */
221 char *
222 Str_FindSubstring(string, substring)
223 	register char *string;		/* String to search. */
224 	char *substring;		/* Substring to find in string */
225 {
226 	register char *a, *b;
227 
228 	/*
229 	 * First scan quickly through the two strings looking for a single-
230 	 * character match.  When it's found, then compare the rest of the
231 	 * substring.
232 	 */
233 
234 	for (b = substring; *string != 0; string += 1) {
235 		if (*string != *b)
236 			continue;
237 		a = string;
238 		for (;;) {
239 			if (*b == 0)
240 				return(string);
241 			if (*a++ != *b++)
242 				break;
243 		}
244 		b = substring;
245 	}
246 	return((char *) NULL);
247 }
248 
249 /*
250  * Str_Match --
251  *
252  * See if a particular string matches a particular pattern.
253  *
254  * Results: Non-zero is returned if string matches pattern, 0 otherwise. The
255  * matching operation permits the following special characters in the
256  * pattern: *?\[] (see the man page for details on what these mean).
257  *
258  * Side effects: None.
259  */
260 int
261 Str_Match(string, pattern)
262 	register char *string;		/* String */
263 	register char *pattern;		/* Pattern */
264 {
265 	char c2;
266 
267 	for (;;) {
268 		/*
269 		 * See if we're at the end of both the pattern and the
270 		 * string. If, we succeeded.  If we're at the end of the
271 		 * pattern but not at the end of the string, we failed.
272 		 */
273 		if (*pattern == 0)
274 			return(!*string);
275 		if (*string == 0 && *pattern != '*')
276 			return(0);
277 		/*
278 		 * Check for a "*" as the next pattern character.  It matches
279 		 * any substring.  We handle this by calling ourselves
280 		 * recursively for each postfix of string, until either we
281 		 * match or we reach the end of the string.
282 		 */
283 		if (*pattern == '*') {
284 			pattern += 1;
285 			if (*pattern == 0)
286 				return(1);
287 			while (*string != 0) {
288 				if (Str_Match(string, pattern))
289 					return(1);
290 				++string;
291 			}
292 			return(0);
293 		}
294 		/*
295 		 * Check for a "?" as the next pattern character.  It matches
296 		 * any single character.
297 		 */
298 		if (*pattern == '?')
299 			goto thisCharOK;
300 		/*
301 		 * Check for a "[" as the next pattern character.  It is
302 		 * followed by a list of characters that are acceptable, or
303 		 * by a range (two characters separated by "-").
304 		 */
305 		if (*pattern == '[') {
306 			++pattern;
307 			for (;;) {
308 				if ((*pattern == ']') || (*pattern == 0))
309 					return(0);
310 				if (*pattern == *string)
311 					break;
312 				if (pattern[1] == '-') {
313 					c2 = pattern[2];
314 					if (c2 == 0)
315 						return(0);
316 					if ((*pattern <= *string) &&
317 					    (c2 >= *string))
318 						break;
319 					if ((*pattern >= *string) &&
320 					    (c2 <= *string))
321 						break;
322 					pattern += 2;
323 				}
324 				++pattern;
325 			}
326 			while ((*pattern != ']') && (*pattern != 0))
327 				++pattern;
328 			goto thisCharOK;
329 		}
330 		/*
331 		 * If the next pattern character is '/', just strip off the
332 		 * '/' so we do exact matching on the character that follows.
333 		 */
334 		if (*pattern == '\\') {
335 			++pattern;
336 			if (*pattern == 0)
337 				return(0);
338 		}
339 		/*
340 		 * There's no special character.  Just make sure that the
341 		 * next characters of each string match.
342 		 */
343 		if (*pattern != *string)
344 			return(0);
345 thisCharOK:	++pattern;
346 		++string;
347 	}
348 }
349 
350 
351 /*-
352  *-----------------------------------------------------------------------
353  * Str_SYSVMatch --
354  *	Check word against pattern for a match (% is wild),
355  *
356  * Results:
357  *	Returns the beginning position of a match or null. The number
358  *	of characters matched is returned in len.
359  *
360  * Side Effects:
361  *	None
362  *
363  *-----------------------------------------------------------------------
364  */
365 char *
366 Str_SYSVMatch(word, pattern, len)
367     char	*word;		/* Word to examine */
368     char	*pattern;	/* Pattern to examine against */
369     int		*len;		/* Number of characters to substitute */
370 {
371     char *p = pattern;
372     char *w = word;
373     char *m;
374 
375     if (*p == '\0') {
376 	/* Null pattern is the whole string */
377 	*len = strlen(w);
378 	return w;
379     }
380 
381     if ((m = strchr(p, '%')) != NULL) {
382 	/* check that the prefix matches */
383 	for (; p != m && *w && *w == *p; w++, p++)
384 	     continue;
385 
386 	if (p != m)
387 	    return NULL;	/* No match */
388 
389 	if (*++p == '\0') {
390 	    /* No more pattern, return the rest of the string */
391 	    *len = strlen(w);
392 	    return w;
393 	}
394     }
395 
396     m = w;
397 
398     /* Find a matching tail */
399     do
400 	if (strcmp(p, w) == 0) {
401 	    *len = w - m;
402 	    return m;
403 	}
404     while (*w++ != '\0');
405 
406     return NULL;
407 }
408 
409 
410 /*-
411  *-----------------------------------------------------------------------
412  * Str_SYSVSubst --
413  *	Substitute '%' on the pattern with len characters from src.
414  *	If the pattern does not contain a '%' prepend len characters
415  *	from src.
416  *
417  * Results:
418  *	None
419  *
420  * Side Effects:
421  *	Places result on buf
422  *
423  *-----------------------------------------------------------------------
424  */
425 void
426 Str_SYSVSubst(buf, pat, src, len)
427     Buffer buf;
428     char *pat;
429     char *src;
430     int   len;
431 {
432     char *m;
433 
434     if ((m = strchr(pat, '%')) != NULL) {
435 	/* Copy the prefix */
436 	Buf_AddBytes(buf, m - pat, (Byte *) pat);
437 	/* skip the % */
438 	pat = m + 1;
439     }
440 
441     /* Copy the pattern */
442     Buf_AddBytes(buf, len, (Byte *) src);
443 
444     /* append the rest */
445     Buf_AddBytes(buf, strlen(pat), (Byte *) pat);
446 }
447