str.c revision 138232
1/*-
2 * Copyright (c) 1988, 1989, 1990, 1993
3 *	The Regents of the University of California.  All rights reserved.
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 * @(#)str.c	5.8 (Berkeley) 6/1/90
39 */
40
41#include <sys/cdefs.h>
42__FBSDID("$FreeBSD: head/usr.bin/make/str.c 138232 2004-11-30 17:46:29Z harti $");
43
44#include "make.h"
45
46static char **argv, *buffer;
47static int argmax, curlen;
48
49/*
50 * str_init --
51 *	Initialize the strings package
52 *
53 */
54void
55str_init(void)
56{
57    char *p1;
58
59    argv = (char **)emalloc(((argmax = 50) + 1) * sizeof(char *));
60    argv[0] = Var_Value(".MAKE", VAR_GLOBAL, &p1);
61}
62
63
64/*
65 * str_end --
66 *	Cleanup the strings package
67 *
68 */
69void
70str_end(void)
71{
72    if (argv) {
73	if (argv[0])
74	    free(argv[0]);
75	free(argv);
76    }
77    if (buffer)
78	free(buffer);
79}
80
81/*-
82 * str_concat --
83 *	concatenate the two strings, inserting a space or slash between them,
84 *	freeing them if requested.
85 *
86 * returns --
87 *	the resulting string in allocated space.
88 */
89char *
90str_concat(char *s1, char *s2, int flags)
91{
92	int len1, len2;
93	char *result;
94
95	/* get the length of both strings */
96	len1 = strlen(s1);
97	len2 = strlen(s2);
98
99	/* allocate length plus separator plus EOS */
100	result = emalloc((u_int)(len1 + len2 + 2));
101
102	/* copy first string into place */
103	memcpy(result, s1, len1);
104
105	/* add separator character */
106	if (flags & STR_ADDSPACE) {
107		result[len1] = ' ';
108		++len1;
109	} else if (flags & STR_ADDSLASH) {
110		result[len1] = '/';
111		++len1;
112	}
113
114	/* copy second string plus EOS into place */
115	memcpy(result + len1, s2, len2 + 1);
116
117	/* free original strings */
118	if (flags & STR_DOFREE) {
119		free(s1);
120		free(s2);
121	}
122	return (result);
123}
124
125/*-
126 * brk_string --
127 *	Fracture a string into an array of words (as delineated by tabs or
128 *	spaces) taking quotation marks into account.  Leading tabs/spaces
129 *	are ignored.
130 *
131 * returns --
132 *	Pointer to the array of pointers to the words.  To make life easier,
133 *	the first word is always the value of the .MAKE variable.
134 */
135char **
136brk_string(char *str, int *store_argc, Boolean expand)
137{
138	int argc, ch;
139	char inquote, *p, *start, *t;
140	int len;
141
142	/* skip leading space chars. */
143	for (; *str == ' ' || *str == '\t'; ++str)
144		continue;
145
146	/* allocate room for a copy of the string */
147	if ((len = strlen(str) + 1) > curlen) {
148		if (buffer)
149		    free(buffer);
150		buffer = emalloc(curlen = len);
151	}
152
153	/*
154	 * copy the string; at the same time, parse backslashes,
155	 * quotes and build the argument list.
156	 */
157	argc = 1;
158	inquote = '\0';
159	for (p = str, start = t = buffer;; ++p) {
160		switch(ch = *p) {
161		case '"':
162		case '\'':
163			if (inquote) {
164				if (ch != inquote)
165					break;
166				inquote = '\0';
167				/* Don't miss "" or '' */
168				if (!start)
169					start = t;
170			} else
171				inquote = (char) ch;
172			if (expand)
173				continue;
174			break;
175		case ' ':
176		case '\t':
177		case '\n':
178			if (inquote)
179				break;
180			if (!start)
181				continue;
182			/* FALLTHROUGH */
183		case '\0':
184			/*
185			 * end of a token -- make sure there's enough argv
186			 * space and save off a pointer.
187			 */
188			if (!start)
189			    goto done;
190
191			*t++ = '\0';
192			if (argc == argmax) {
193				argmax *= 2;		/* ramp up fast */
194				argv = (char **)erealloc(argv,
195				    (argmax + 1) * sizeof(char *));
196			}
197			argv[argc++] = start;
198			start = (char *)NULL;
199			if (ch == '\n' || ch == '\0')
200				goto done;
201			continue;
202		case '\\':
203			if (!expand) {
204				if (!start)
205					start = t;
206				*t++ = '\\';
207				ch = *++p;
208				break;
209			}
210
211			switch (ch = *++p) {
212			case '\0':
213			case '\n':
214				/* hmmm; fix it up as best we can */
215				ch = '\\';
216				--p;
217				break;
218			case 'b':
219				ch = '\b';
220				break;
221			case 'f':
222				ch = '\f';
223				break;
224			case 'n':
225				ch = '\n';
226				break;
227			case 'r':
228				ch = '\r';
229				break;
230			case 't':
231				ch = '\t';
232				break;
233			default:
234				break;
235			}
236			break;
237		default:
238			break;
239		}
240		if (!start)
241			start = t;
242		*t++ = (char)ch;
243	}
244done:	argv[argc] = (char *)NULL;
245	*store_argc = argc;
246	return (argv);
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 */
260int
261Str_Match(const char *string, const char *pattern)
262{
263	char c2;
264
265	for (;;) {
266		/*
267		 * See if we're at the end of both the pattern and the
268		 * string. If, we succeeded.  If we're at the end of the
269		 * pattern but not at the end of the string, we failed.
270		 */
271		if (*pattern == 0)
272			return (!*string);
273		if (*string == 0 && *pattern != '*')
274			return (0);
275		/*
276		 * Check for a "*" as the next pattern character.  It matches
277		 * any substring.  We handle this by calling ourselves
278		 * recursively for each postfix of string, until either we
279		 * match or we reach the end of the string.
280		 */
281		if (*pattern == '*') {
282			pattern += 1;
283			if (*pattern == 0)
284				return (1);
285			while (*string != 0) {
286				if (Str_Match(string, pattern))
287					return (1);
288				++string;
289			}
290			return (0);
291		}
292		/*
293		 * Check for a "?" as the next pattern character.  It matches
294		 * any single character.
295		 */
296		if (*pattern == '?')
297			goto thisCharOK;
298		/*
299		 * Check for a "[" as the next pattern character.  It is
300		 * followed by a list of characters that are acceptable, or
301		 * by a range (two characters separated by "-").
302		 */
303		if (*pattern == '[') {
304			++pattern;
305			for (;;) {
306				if ((*pattern == ']') || (*pattern == 0))
307					return (0);
308				if (*pattern == *string)
309					break;
310				if (pattern[1] == '-') {
311					c2 = pattern[2];
312					if (c2 == 0)
313						return (0);
314					if ((*pattern <= *string) &&
315					    (c2 >= *string))
316						break;
317					if ((*pattern >= *string) &&
318					    (c2 <= *string))
319						break;
320					pattern += 2;
321				}
322				++pattern;
323			}
324			while ((*pattern != ']') && (*pattern != 0))
325				++pattern;
326			goto thisCharOK;
327		}
328		/*
329		 * If the next pattern character is '/', just strip off the
330		 * '/' so we do exact matching on the character that follows.
331		 */
332		if (*pattern == '\\') {
333			++pattern;
334			if (*pattern == 0)
335				return (0);
336		}
337		/*
338		 * There's no special character.  Just make sure that the
339		 * next characters of each string match.
340		 */
341		if (*pattern != *string)
342			return (0);
343thisCharOK:	++pattern;
344		++string;
345	}
346}
347
348
349/*-
350 *-----------------------------------------------------------------------
351 * Str_SYSVMatch --
352 *	Check word against pattern for a match (% is wild),
353 *
354 * Results:
355 *	Returns the beginning position of a match or null. The number
356 *	of characters matched is returned in len.
357 *
358 * Side Effects:
359 *	None
360 *
361 *-----------------------------------------------------------------------
362 */
363const char *
364Str_SYSVMatch(const char *word, const char *pattern, int *len)
365{
366    const char *m, *p, *w;
367
368    p = pattern;
369    w = word;
370
371    if (*w == '\0') {
372	/* Zero-length word cannot be matched against */
373	*len = 0;
374	return (NULL);
375    }
376
377    if (*p == '\0') {
378	/* Null pattern is the whole string */
379	*len = strlen(w);
380	return (w);
381    }
382
383    if ((m = strchr(p, '%')) != NULL) {
384	/* check that the prefix matches */
385	for (; p != m && *w && *w == *p; w++, p++)
386	     continue;
387
388	if (p != m)
389	    return (NULL);	/* No match */
390
391	if (*++p == '\0') {
392	    /* No more pattern, return the rest of the string */
393	    *len = strlen(w);
394	    return (w);
395	}
396    }
397
398    m = w;
399
400    /* Find a matching tail */
401    do
402	if (strcmp(p, w) == 0) {
403	    *len = w - m;
404	    return (m);
405	}
406    while (*w++ != '\0');
407
408    return (NULL);
409}
410
411
412/*-
413 *-----------------------------------------------------------------------
414 * Str_SYSVSubst --
415 *	Substitute '%' on the pattern with len characters from src.
416 *	If the pattern does not contain a '%' prepend len characters
417 *	from src.
418 *
419 * Results:
420 *	None
421 *
422 * Side Effects:
423 *	Places result on buf
424 *
425 *-----------------------------------------------------------------------
426 */
427void
428Str_SYSVSubst(Buffer buf, const char *pat, const char *src, int len)
429{
430    const char *m;
431
432    if ((m = strchr(pat, '%')) != NULL) {
433	/* Copy the prefix */
434	Buf_AddBytes(buf, m - pat, (Byte *)pat);
435	/* skip the % */
436	pat = m + 1;
437    }
438
439    /* Copy the pattern */
440    Buf_AddBytes(buf, len, (Byte *)src);
441
442    /* append the rest */
443    Buf_AddBytes(buf, strlen(pat), (Byte *)pat);
444}
445