str.c revision 124840
11590Srgrimes/*-
21590Srgrimes * Copyright (c) 1988, 1989, 1990, 1993
31590Srgrimes *	The Regents of the University of California.  All rights reserved.
41590Srgrimes * Copyright (c) 1989 by Berkeley Softworks
51590Srgrimes * All rights reserved.
61590Srgrimes *
71590Srgrimes * This code is derived from software contributed to Berkeley by
81590Srgrimes * Adam de Boor.
91590Srgrimes *
101590Srgrimes * Redistribution and use in source and binary forms, with or without
111590Srgrimes * modification, are permitted provided that the following conditions
121590Srgrimes * are met:
131590Srgrimes * 1. Redistributions of source code must retain the above copyright
141590Srgrimes *    notice, this list of conditions and the following disclaimer.
151590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
161590Srgrimes *    notice, this list of conditions and the following disclaimer in the
171590Srgrimes *    documentation and/or other materials provided with the distribution.
181590Srgrimes * 3. All advertising materials mentioning features or use of this software
191590Srgrimes *    must display the following acknowledgement:
201590Srgrimes *	This product includes software developed by the University of
211590Srgrimes *	California, Berkeley and its contributors.
221590Srgrimes * 4. Neither the name of the University nor the names of its contributors
231590Srgrimes *    may be used to endorse or promote products derived from this software
241590Srgrimes *    without specific prior written permission.
251590Srgrimes *
261590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
271590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
281590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
291590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
301590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
311590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
321590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
331590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
341590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
351590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
361590Srgrimes * SUCH DAMAGE.
3762833Swsanchez *
3862833Swsanchez * @(#)str.c	5.8 (Berkeley) 6/1/90
391590Srgrimes */
401590Srgrimes
4162833Swsanchez#include <sys/cdefs.h>
4294587Sobrien__FBSDID("$FreeBSD: head/usr.bin/make/str.c 124840 2004-01-22 18:17:44Z ru $");
431590Srgrimes
441590Srgrimes#include "make.h"
451590Srgrimes
465814Sjkhstatic char **argv, *buffer;
475814Sjkhstatic int argmax, curlen;
485814Sjkh
495814Sjkh/*
505814Sjkh * str_init --
515814Sjkh *	Initialize the strings package
525814Sjkh *
535814Sjkh */
545814Sjkhvoid
55104696Sjmallettstr_init(void)
565814Sjkh{
575814Sjkh    char *p1;
5818730Ssteve    argv = (char **)emalloc(((argmax = 50) + 1) * sizeof(char *));
595814Sjkh    argv[0] = Var_Value(".MAKE", VAR_GLOBAL, &p1);
605814Sjkh}
615814Sjkh
625814Sjkh
635814Sjkh/*
645814Sjkh * str_end --
655814Sjkh *	Cleanup the strings package
665814Sjkh *
675814Sjkh */
685814Sjkhvoid
69104696Sjmallettstr_end(void)
705814Sjkh{
719254Sache    if (argv) {
729254Sache	if (argv[0])
739254Sache	    free(argv[0]);
7469531Swill	free(argv);
759254Sache    }
765814Sjkh    if (buffer)
775814Sjkh	free(buffer);
785814Sjkh}
795814Sjkh
801590Srgrimes/*-
811590Srgrimes * str_concat --
821590Srgrimes *	concatenate the two strings, inserting a space or slash between them,
831590Srgrimes *	freeing them if requested.
841590Srgrimes *
851590Srgrimes * returns --
861590Srgrimes *	the resulting string in allocated space.
871590Srgrimes */
881590Srgrimeschar *
89104696Sjmallettstr_concat(char *s1, char *s2, int flags)
901590Srgrimes{
9194584Sobrien	int len1, len2;
9294584Sobrien	char *result;
931590Srgrimes
941590Srgrimes	/* get the length of both strings */
9594638Sobrien	len1 = strlen(s1);
9694638Sobrien	len2 = strlen(s2);
971590Srgrimes
981590Srgrimes	/* allocate length plus separator plus EOS */
991590Srgrimes	result = emalloc((u_int)(len1 + len2 + 2));
1001590Srgrimes
1011590Srgrimes	/* copy first string into place */
10294638Sobrien	memcpy(result, s1, len1);
1031590Srgrimes
1041590Srgrimes	/* add separator character */
10594638Sobrien	if (flags & STR_ADDSPACE) {
10694638Sobrien		result[len1] = ' ';
10794638Sobrien		++len1;
10894638Sobrien	} else if (flags & STR_ADDSLASH) {
10994638Sobrien		result[len1] = '/';
11094638Sobrien		++len1;
1111590Srgrimes	}
1121590Srgrimes
11394638Sobrien	/* copy second string plus EOS into place */
11494638Sobrien	memcpy(result + len1, s2, len2 + 1);
1151590Srgrimes
1161590Srgrimes	/* free original strings */
1171590Srgrimes	if (flags & STR_DOFREE) {
118105826Sjmallett		(void)free(s1);
119105826Sjmallett		(void)free(s2);
1201590Srgrimes	}
1211590Srgrimes	return(result);
1221590Srgrimes}
1231590Srgrimes
1241590Srgrimes/*-
1251590Srgrimes * brk_string --
1261590Srgrimes *	Fracture a string into an array of words (as delineated by tabs or
1271590Srgrimes *	spaces) taking quotation marks into account.  Leading tabs/spaces
1281590Srgrimes *	are ignored.
1291590Srgrimes *
1301590Srgrimes * returns --
1311590Srgrimes *	Pointer to the array of pointers to the words.  To make life easier,
1321590Srgrimes *	the first word is always the value of the .MAKE variable.
1331590Srgrimes */
1341590Srgrimeschar **
135104696Sjmallettbrk_string(char *str, int *store_argc, Boolean expand)
1361590Srgrimes{
13794584Sobrien	int argc, ch;
13894584Sobrien	char inquote, *p, *start, *t;
1391590Srgrimes	int len;
1401590Srgrimes
1411590Srgrimes	/* skip leading space chars. */
1421590Srgrimes	for (; *str == ' ' || *str == '\t'; ++str)
1431590Srgrimes		continue;
1441590Srgrimes
1451590Srgrimes	/* allocate room for a copy of the string */
1465814Sjkh	if ((len = strlen(str) + 1) > curlen) {
1475814Sjkh		if (buffer)
1485814Sjkh		    free(buffer);
1495814Sjkh		buffer = emalloc(curlen = len);
1505814Sjkh	}
1511590Srgrimes
1521590Srgrimes	/*
1531590Srgrimes	 * copy the string; at the same time, parse backslashes,
1541590Srgrimes	 * quotes and build the argument list.
1551590Srgrimes	 */
1561590Srgrimes	argc = 1;
1571590Srgrimes	inquote = '\0';
1585814Sjkh	for (p = str, start = t = buffer;; ++p) {
1591590Srgrimes		switch(ch = *p) {
1601590Srgrimes		case '"':
1611590Srgrimes		case '\'':
16249938Shoek			if (inquote) {
163124840Sru				if (ch == inquote)
1641590Srgrimes					inquote = '\0';
1651590Srgrimes				else
1661590Srgrimes					break;
167124840Sru			} else
1681590Srgrimes				inquote = (char) ch;
169124840Sru			if (expand)
170124840Sru				continue;
171124840Sru			break;
1721590Srgrimes		case ' ':
1731590Srgrimes		case '\t':
1745814Sjkh		case '\n':
1751590Srgrimes			if (inquote)
1761590Srgrimes				break;
1771590Srgrimes			if (!start)
1781590Srgrimes				continue;
1791590Srgrimes			/* FALLTHROUGH */
1801590Srgrimes		case '\0':
1811590Srgrimes			/*
1821590Srgrimes			 * end of a token -- make sure there's enough argv
1831590Srgrimes			 * space and save off a pointer.
1841590Srgrimes			 */
1855814Sjkh			if (!start)
1865814Sjkh			    goto done;
1875814Sjkh
1881590Srgrimes			*t++ = '\0';
1891590Srgrimes			if (argc == argmax) {
1901590Srgrimes				argmax *= 2;		/* ramp up fast */
19118730Ssteve				argv = (char **)erealloc(argv,
19218730Ssteve				    (argmax + 1) * sizeof(char *));
1931590Srgrimes			}
1941590Srgrimes			argv[argc++] = start;
1951590Srgrimes			start = (char *)NULL;
1961590Srgrimes			if (ch == '\n' || ch == '\0')
1971590Srgrimes				goto done;
1981590Srgrimes			continue;
1991590Srgrimes		case '\\':
2005814Sjkh			if (!expand) {
2015814Sjkh				if (!start)
2025814Sjkh					start = t;
2035814Sjkh				*t++ = '\\';
2045814Sjkh				ch = *++p;
2055814Sjkh				break;
2065814Sjkh			}
2078874Srgrimes
2081590Srgrimes			switch (ch = *++p) {
2091590Srgrimes			case '\0':
2101590Srgrimes			case '\n':
2111590Srgrimes				/* hmmm; fix it up as best we can */
2121590Srgrimes				ch = '\\';
2131590Srgrimes				--p;
2141590Srgrimes				break;
2151590Srgrimes			case 'b':
2161590Srgrimes				ch = '\b';
2171590Srgrimes				break;
2181590Srgrimes			case 'f':
2191590Srgrimes				ch = '\f';
2201590Srgrimes				break;
2211590Srgrimes			case 'n':
2221590Srgrimes				ch = '\n';
2231590Srgrimes				break;
2241590Srgrimes			case 'r':
2251590Srgrimes				ch = '\r';
2261590Srgrimes				break;
2271590Srgrimes			case 't':
2281590Srgrimes				ch = '\t';
2291590Srgrimes				break;
230104108Sjmallett			default:
231104108Sjmallett				break;
2321590Srgrimes			}
2331590Srgrimes			break;
234104108Sjmallett		default:
235104108Sjmallett			break;
2361590Srgrimes		}
2371590Srgrimes		if (!start)
2381590Srgrimes			start = t;
2391590Srgrimes		*t++ = (char) ch;
2401590Srgrimes	}
2411590Srgrimesdone:	argv[argc] = (char *)NULL;
2421590Srgrimes	*store_argc = argc;
2431590Srgrimes	return(argv);
2441590Srgrimes}
2451590Srgrimes
2461590Srgrimes/*
2471590Srgrimes * Str_Match --
2488874Srgrimes *
2491590Srgrimes * See if a particular string matches a particular pattern.
2508874Srgrimes *
2511590Srgrimes * Results: Non-zero is returned if string matches pattern, 0 otherwise. The
2521590Srgrimes * matching operation permits the following special characters in the
2531590Srgrimes * pattern: *?\[] (see the man page for details on what these mean).
2548874Srgrimes *
2551590Srgrimes * Side effects: None.
2561590Srgrimes */
2571590Srgrimesint
258106106SjmallettStr_Match(const char *string, const char *pattern)
2591590Srgrimes{
2601590Srgrimes	char c2;
2611590Srgrimes
2621590Srgrimes	for (;;) {
2631590Srgrimes		/*
2641590Srgrimes		 * See if we're at the end of both the pattern and the
2651590Srgrimes		 * string. If, we succeeded.  If we're at the end of the
2661590Srgrimes		 * pattern but not at the end of the string, we failed.
2671590Srgrimes		 */
2681590Srgrimes		if (*pattern == 0)
2691590Srgrimes			return(!*string);
2701590Srgrimes		if (*string == 0 && *pattern != '*')
2711590Srgrimes			return(0);
2721590Srgrimes		/*
2731590Srgrimes		 * Check for a "*" as the next pattern character.  It matches
2741590Srgrimes		 * any substring.  We handle this by calling ourselves
2751590Srgrimes		 * recursively for each postfix of string, until either we
2761590Srgrimes		 * match or we reach the end of the string.
2771590Srgrimes		 */
2781590Srgrimes		if (*pattern == '*') {
2791590Srgrimes			pattern += 1;
2801590Srgrimes			if (*pattern == 0)
2811590Srgrimes				return(1);
2821590Srgrimes			while (*string != 0) {
2831590Srgrimes				if (Str_Match(string, pattern))
2841590Srgrimes					return(1);
2851590Srgrimes				++string;
2861590Srgrimes			}
2871590Srgrimes			return(0);
2881590Srgrimes		}
2891590Srgrimes		/*
2901590Srgrimes		 * Check for a "?" as the next pattern character.  It matches
2911590Srgrimes		 * any single character.
2921590Srgrimes		 */
2931590Srgrimes		if (*pattern == '?')
2941590Srgrimes			goto thisCharOK;
2951590Srgrimes		/*
2961590Srgrimes		 * Check for a "[" as the next pattern character.  It is
2971590Srgrimes		 * followed by a list of characters that are acceptable, or
2981590Srgrimes		 * by a range (two characters separated by "-").
2991590Srgrimes		 */
3001590Srgrimes		if (*pattern == '[') {
3011590Srgrimes			++pattern;
3021590Srgrimes			for (;;) {
3031590Srgrimes				if ((*pattern == ']') || (*pattern == 0))
3041590Srgrimes					return(0);
3051590Srgrimes				if (*pattern == *string)
3061590Srgrimes					break;
3071590Srgrimes				if (pattern[1] == '-') {
3081590Srgrimes					c2 = pattern[2];
3091590Srgrimes					if (c2 == 0)
3101590Srgrimes						return(0);
3111590Srgrimes					if ((*pattern <= *string) &&
3121590Srgrimes					    (c2 >= *string))
3131590Srgrimes						break;
3141590Srgrimes					if ((*pattern >= *string) &&
3151590Srgrimes					    (c2 <= *string))
3161590Srgrimes						break;
3171590Srgrimes					pattern += 2;
3181590Srgrimes				}
3191590Srgrimes				++pattern;
3201590Srgrimes			}
3211590Srgrimes			while ((*pattern != ']') && (*pattern != 0))
3221590Srgrimes				++pattern;
3231590Srgrimes			goto thisCharOK;
3241590Srgrimes		}
3251590Srgrimes		/*
3261590Srgrimes		 * If the next pattern character is '/', just strip off the
3271590Srgrimes		 * '/' so we do exact matching on the character that follows.
3281590Srgrimes		 */
3291590Srgrimes		if (*pattern == '\\') {
3301590Srgrimes			++pattern;
3311590Srgrimes			if (*pattern == 0)
3321590Srgrimes				return(0);
3331590Srgrimes		}
3341590Srgrimes		/*
3351590Srgrimes		 * There's no special character.  Just make sure that the
3361590Srgrimes		 * next characters of each string match.
3371590Srgrimes		 */
3381590Srgrimes		if (*pattern != *string)
3391590Srgrimes			return(0);
3401590SrgrimesthisCharOK:	++pattern;
3411590Srgrimes		++string;
3421590Srgrimes	}
3431590Srgrimes}
3441590Srgrimes
3451590Srgrimes
3461590Srgrimes/*-
3471590Srgrimes *-----------------------------------------------------------------------
3481590Srgrimes * Str_SYSVMatch --
3498874Srgrimes *	Check word against pattern for a match (% is wild),
3508874Srgrimes *
3511590Srgrimes * Results:
3521590Srgrimes *	Returns the beginning position of a match or null. The number
3531590Srgrimes *	of characters matched is returned in len.
3541590Srgrimes *
3551590Srgrimes * Side Effects:
3561590Srgrimes *	None
3571590Srgrimes *
3581590Srgrimes *-----------------------------------------------------------------------
3591590Srgrimes */
360106106Sjmallettconst char *
361106106SjmallettStr_SYSVMatch(const char *word, const char *pattern, int *len)
3621590Srgrimes{
363106106Sjmallett    const char *m, *p, *w;
3641590Srgrimes
365106106Sjmallett    p = pattern;
366106106Sjmallett    w = word;
367106106Sjmallett
36896071Sjmallett    if (*w == '\0') {
36996071Sjmallett	/* Zero-length word cannot be matched against */
37096071Sjmallett	*len = 0;
37196071Sjmallett	return NULL;
37296071Sjmallett    }
37396071Sjmallett
3741590Srgrimes    if (*p == '\0') {
3751590Srgrimes	/* Null pattern is the whole string */
3761590Srgrimes	*len = strlen(w);
3771590Srgrimes	return w;
3781590Srgrimes    }
3791590Srgrimes
3801590Srgrimes    if ((m = strchr(p, '%')) != NULL) {
3811590Srgrimes	/* check that the prefix matches */
3821590Srgrimes	for (; p != m && *w && *w == *p; w++, p++)
3831590Srgrimes	     continue;
3841590Srgrimes
3851590Srgrimes	if (p != m)
3861590Srgrimes	    return NULL;	/* No match */
3871590Srgrimes
3881590Srgrimes	if (*++p == '\0') {
3891590Srgrimes	    /* No more pattern, return the rest of the string */
3901590Srgrimes	    *len = strlen(w);
3911590Srgrimes	    return w;
3921590Srgrimes	}
3931590Srgrimes    }
3941590Srgrimes
3951590Srgrimes    m = w;
3961590Srgrimes
3971590Srgrimes    /* Find a matching tail */
3981590Srgrimes    do
3991590Srgrimes	if (strcmp(p, w) == 0) {
4001590Srgrimes	    *len = w - m;
4011590Srgrimes	    return m;
4021590Srgrimes	}
4031590Srgrimes    while (*w++ != '\0');
4048874Srgrimes
4051590Srgrimes    return NULL;
4061590Srgrimes}
4071590Srgrimes
4081590Srgrimes
4091590Srgrimes/*-
4101590Srgrimes *-----------------------------------------------------------------------
4111590Srgrimes * Str_SYSVSubst --
4121590Srgrimes *	Substitute '%' on the pattern with len characters from src.
4131590Srgrimes *	If the pattern does not contain a '%' prepend len characters
4141590Srgrimes *	from src.
4158874Srgrimes *
4161590Srgrimes * Results:
4171590Srgrimes *	None
4181590Srgrimes *
4191590Srgrimes * Side Effects:
4201590Srgrimes *	Places result on buf
4211590Srgrimes *
4221590Srgrimes *-----------------------------------------------------------------------
4231590Srgrimes */
4241590Srgrimesvoid
425106106SjmallettStr_SYSVSubst(Buffer buf, const char *pat, const char *src, int len)
4261590Srgrimes{
427106106Sjmallett    const char *m;
4281590Srgrimes
4291590Srgrimes    if ((m = strchr(pat, '%')) != NULL) {
4301590Srgrimes	/* Copy the prefix */
4311590Srgrimes	Buf_AddBytes(buf, m - pat, (Byte *) pat);
4321590Srgrimes	/* skip the % */
4331590Srgrimes	pat = m + 1;
4341590Srgrimes    }
4351590Srgrimes
4361590Srgrimes    /* Copy the pattern */
4371590Srgrimes    Buf_AddBytes(buf, len, (Byte *) src);
4381590Srgrimes
4391590Srgrimes    /* append the rest */
4401590Srgrimes    Buf_AddBytes(buf, strlen(pat), (Byte *) pat);
4411590Srgrimes}
442