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