Home | History | Annotate | Line # | Download | only in make
str.c revision 1.14
      1 /*	$NetBSD: str.c,v 1.14 1997/07/01 21:17:37 christos Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1988, 1989, 1990, 1993
      5  *	The Regents of the University of California.  All rights reserved.
      6  * Copyright (c) 1989 by Berkeley Softworks
      7  * All rights reserved.
      8  *
      9  * This code is derived from software contributed to Berkeley by
     10  * Adam de Boor.
     11  *
     12  * Redistribution and use in source and binary forms, with or without
     13  * modification, are permitted provided that the following conditions
     14  * are met:
     15  * 1. Redistributions of source code must retain the above copyright
     16  *    notice, this list of conditions and the following disclaimer.
     17  * 2. Redistributions in binary form must reproduce the above copyright
     18  *    notice, this list of conditions and the following disclaimer in the
     19  *    documentation and/or other materials provided with the distribution.
     20  * 3. All advertising materials mentioning features or use of this software
     21  *    must display the following acknowledgement:
     22  *	This product includes software developed by the University of
     23  *	California, Berkeley and its contributors.
     24  * 4. Neither the name of the University nor the names of its contributors
     25  *    may be used to endorse or promote products derived from this software
     26  *    without specific prior written permission.
     27  *
     28  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     29  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     30  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     31  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     32  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     33  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     34  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     35  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     36  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     37  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     38  * SUCH DAMAGE.
     39  */
     40 
     41 #include <sys/cdefs.h>
     42 #ifndef lint
     43 #if 0
     44 static char     sccsid[] = "@(#)str.c	5.8 (Berkeley) 6/1/90";
     45 #else
     46 __RCSID("$NetBSD: str.c,v 1.14 1997/07/01 21:17:37 christos Exp $");
     47 #endif
     48 #endif				/* not lint */
     49 
     50 #include "make.h"
     51 
     52 static char **argv, *buffer;
     53 static int argmax, curlen;
     54 
     55 /*
     56  * str_init --
     57  *	Initialize the strings package
     58  *
     59  */
     60 void
     61 str_init()
     62 {
     63     char *p1;
     64     argv = (char **)emalloc(((argmax = 50) + 1) * sizeof(char *));
     65     argv[0] = Var_Value(".MAKE", VAR_GLOBAL, &p1);
     66 }
     67 
     68 
     69 /*
     70  * str_end --
     71  *	Cleanup the strings package
     72  *
     73  */
     74 void
     75 str_end()
     76 {
     77     if (argv) {
     78 	if (argv[0])
     79 	    free(argv[0]);
     80 	free((Address) argv);
     81     }
     82     if (buffer)
     83 	free(buffer);
     84 }
     85 
     86 /*-
     87  * str_concat --
     88  *	concatenate the two strings, inserting a space or slash between them,
     89  *	freeing them if requested.
     90  *
     91  * returns --
     92  *	the resulting string in allocated space.
     93  */
     94 char *
     95 str_concat(s1, s2, flags)
     96 	char *s1, *s2;
     97 	int flags;
     98 {
     99 	register int len1, len2;
    100 	register char *result;
    101 
    102 	/* get the length of both strings */
    103 	len1 = strlen(s1);
    104 	len2 = strlen(s2);
    105 
    106 	/* allocate length plus separator plus EOS */
    107 	result = emalloc((u_int)(len1 + len2 + 2));
    108 
    109 	/* copy first string into place */
    110 	memcpy(result, s1, len1);
    111 
    112 	/* add separator character */
    113 	if (flags & STR_ADDSPACE) {
    114 		result[len1] = ' ';
    115 		++len1;
    116 	} else if (flags & STR_ADDSLASH) {
    117 		result[len1] = '/';
    118 		++len1;
    119 	}
    120 
    121 	/* copy second string plus EOS into place */
    122 	memcpy(result + len1, s2, len2 + 1);
    123 
    124 	/* free original strings */
    125 	if (flags & STR_DOFREE) {
    126 		(void)free(s1);
    127 		(void)free(s2);
    128 	}
    129 	return(result);
    130 }
    131 
    132 /*-
    133  * brk_string --
    134  *	Fracture a string into an array of words (as delineated by tabs or
    135  *	spaces) taking quotation marks into account.  Leading tabs/spaces
    136  *	are ignored.
    137  *
    138  * returns --
    139  *	Pointer to the array of pointers to the words.  To make life easier,
    140  *	the first word is always the value of the .MAKE variable.
    141  */
    142 char **
    143 brk_string(str, store_argc, expand)
    144 	register char *str;
    145 	int *store_argc;
    146 	Boolean expand;
    147 {
    148 	register int argc, ch;
    149 	register char inquote, *p, *start, *t;
    150 	int len;
    151 
    152 	/* skip leading space chars. */
    153 	for (; *str == ' ' || *str == '\t'; ++str)
    154 		continue;
    155 
    156 	/* allocate room for a copy of the string */
    157 	if ((len = strlen(str) + 1) > curlen) {
    158 		if (buffer)
    159 		    free(buffer);
    160 		buffer = emalloc(curlen = len);
    161 	}
    162 
    163 	/*
    164 	 * copy the string; at the same time, parse backslashes,
    165 	 * quotes and build the argument list.
    166 	 */
    167 	argc = 1;
    168 	inquote = '\0';
    169 	for (p = str, start = t = buffer;; ++p) {
    170 		switch(ch = *p) {
    171 		case '"':
    172 		case '\'':
    173 			if (inquote)
    174 				if (inquote == ch)
    175 					inquote = '\0';
    176 				else
    177 					break;
    178 			else {
    179 				inquote = (char) ch;
    180 				/* Don't miss "" or '' */
    181 				if (start == NULL && p[1] == inquote) {
    182 					start = t + 1;
    183 					break;
    184 				}
    185 			}
    186 			if (!expand) {
    187 				if (!start)
    188 					start = t;
    189 				*t++ = ch;
    190 			}
    191 			continue;
    192 		case ' ':
    193 		case '\t':
    194 		case '\n':
    195 			if (inquote)
    196 				break;
    197 			if (!start)
    198 				continue;
    199 			/* FALLTHROUGH */
    200 		case '\0':
    201 			/*
    202 			 * end of a token -- make sure there's enough argv
    203 			 * space and save off a pointer.
    204 			 */
    205 			if (!start)
    206 			    goto done;
    207 
    208 			*t++ = '\0';
    209 			if (argc == argmax) {
    210 				argmax *= 2;		/* ramp up fast */
    211 				argv = (char **)erealloc(argv,
    212 				    (argmax + 1) * sizeof(char *));
    213 			}
    214 			argv[argc++] = start;
    215 			start = (char *)NULL;
    216 			if (ch == '\n' || ch == '\0')
    217 				goto done;
    218 			continue;
    219 		case '\\':
    220 			if (!expand) {
    221 				if (!start)
    222 					start = t;
    223 				*t++ = '\\';
    224 				ch = *++p;
    225 				break;
    226 			}
    227 
    228 			switch (ch = *++p) {
    229 			case '\0':
    230 			case '\n':
    231 				/* hmmm; fix it up as best we can */
    232 				ch = '\\';
    233 				--p;
    234 				break;
    235 			case 'b':
    236 				ch = '\b';
    237 				break;
    238 			case 'f':
    239 				ch = '\f';
    240 				break;
    241 			case 'n':
    242 				ch = '\n';
    243 				break;
    244 			case 'r':
    245 				ch = '\r';
    246 				break;
    247 			case 't':
    248 				ch = '\t';
    249 				break;
    250 			}
    251 			break;
    252 		}
    253 		if (!start)
    254 			start = t;
    255 		*t++ = (char) ch;
    256 	}
    257 done:	argv[argc] = (char *)NULL;
    258 	*store_argc = argc;
    259 	return(argv);
    260 }
    261 
    262 /*
    263  * Str_FindSubstring -- See if a string contains a particular substring.
    264  *
    265  * Results: If string contains substring, the return value is the location of
    266  * the first matching instance of substring in string.  If string doesn't
    267  * contain substring, the return value is NULL.  Matching is done on an exact
    268  * character-for-character basis with no wildcards or special characters.
    269  *
    270  * Side effects: None.
    271  */
    272 char *
    273 Str_FindSubstring(string, substring)
    274 	register char *string;		/* String to search. */
    275 	char *substring;		/* Substring to find in string */
    276 {
    277 	register char *a, *b;
    278 
    279 	/*
    280 	 * First scan quickly through the two strings looking for a single-
    281 	 * character match.  When it's found, then compare the rest of the
    282 	 * substring.
    283 	 */
    284 
    285 	for (b = substring; *string != 0; string += 1) {
    286 		if (*string != *b)
    287 			continue;
    288 		a = string;
    289 		for (;;) {
    290 			if (*b == 0)
    291 				return(string);
    292 			if (*a++ != *b++)
    293 				break;
    294 		}
    295 		b = substring;
    296 	}
    297 	return((char *) NULL);
    298 }
    299 
    300 /*
    301  * Str_Match --
    302  *
    303  * See if a particular string matches a particular pattern.
    304  *
    305  * Results: Non-zero is returned if string matches pattern, 0 otherwise. The
    306  * matching operation permits the following special characters in the
    307  * pattern: *?\[] (see the man page for details on what these mean).
    308  *
    309  * Side effects: None.
    310  */
    311 int
    312 Str_Match(string, pattern)
    313 	register char *string;		/* String */
    314 	register char *pattern;		/* Pattern */
    315 {
    316 	char c2;
    317 
    318 	for (;;) {
    319 		/*
    320 		 * See if we're at the end of both the pattern and the
    321 		 * string. If, we succeeded.  If we're at the end of the
    322 		 * pattern but not at the end of the string, we failed.
    323 		 */
    324 		if (*pattern == 0)
    325 			return(!*string);
    326 		if (*string == 0 && *pattern != '*')
    327 			return(0);
    328 		/*
    329 		 * Check for a "*" as the next pattern character.  It matches
    330 		 * any substring.  We handle this by calling ourselves
    331 		 * recursively for each postfix of string, until either we
    332 		 * match or we reach the end of the string.
    333 		 */
    334 		if (*pattern == '*') {
    335 			pattern += 1;
    336 			if (*pattern == 0)
    337 				return(1);
    338 			while (*string != 0) {
    339 				if (Str_Match(string, pattern))
    340 					return(1);
    341 				++string;
    342 			}
    343 			return(0);
    344 		}
    345 		/*
    346 		 * Check for a "?" as the next pattern character.  It matches
    347 		 * any single character.
    348 		 */
    349 		if (*pattern == '?')
    350 			goto thisCharOK;
    351 		/*
    352 		 * Check for a "[" as the next pattern character.  It is
    353 		 * followed by a list of characters that are acceptable, or
    354 		 * by a range (two characters separated by "-").
    355 		 */
    356 		if (*pattern == '[') {
    357 			++pattern;
    358 			for (;;) {
    359 				if ((*pattern == ']') || (*pattern == 0))
    360 					return(0);
    361 				if (*pattern == *string)
    362 					break;
    363 				if (pattern[1] == '-') {
    364 					c2 = pattern[2];
    365 					if (c2 == 0)
    366 						return(0);
    367 					if ((*pattern <= *string) &&
    368 					    (c2 >= *string))
    369 						break;
    370 					if ((*pattern >= *string) &&
    371 					    (c2 <= *string))
    372 						break;
    373 					pattern += 2;
    374 				}
    375 				++pattern;
    376 			}
    377 			while ((*pattern != ']') && (*pattern != 0))
    378 				++pattern;
    379 			goto thisCharOK;
    380 		}
    381 		/*
    382 		 * If the next pattern character is '/', just strip off the
    383 		 * '/' so we do exact matching on the character that follows.
    384 		 */
    385 		if (*pattern == '\\') {
    386 			++pattern;
    387 			if (*pattern == 0)
    388 				return(0);
    389 		}
    390 		/*
    391 		 * There's no special character.  Just make sure that the
    392 		 * next characters of each string match.
    393 		 */
    394 		if (*pattern != *string)
    395 			return(0);
    396 thisCharOK:	++pattern;
    397 		++string;
    398 	}
    399 }
    400 
    401 
    402 /*-
    403  *-----------------------------------------------------------------------
    404  * Str_SYSVMatch --
    405  *	Check word against pattern for a match (% is wild),
    406  *
    407  * Results:
    408  *	Returns the beginning position of a match or null. The number
    409  *	of characters matched is returned in len.
    410  *
    411  * Side Effects:
    412  *	None
    413  *
    414  *-----------------------------------------------------------------------
    415  */
    416 char *
    417 Str_SYSVMatch(word, pattern, len)
    418     char	*word;		/* Word to examine */
    419     char	*pattern;	/* Pattern to examine against */
    420     int		*len;		/* Number of characters to substitute */
    421 {
    422     char *p = pattern;
    423     char *w = word;
    424     char *m;
    425 
    426     if (*p == '\0') {
    427 	/* Null pattern is the whole string */
    428 	*len = strlen(w);
    429 	return w;
    430     }
    431 
    432     if ((m = strchr(p, '%')) != NULL) {
    433 	/* check that the prefix matches */
    434 	for (; p != m && *w && *w == *p; w++, p++)
    435 	     continue;
    436 
    437 	if (p != m)
    438 	    return NULL;	/* No match */
    439 
    440 	if (*++p == '\0') {
    441 	    /* No more pattern, return the rest of the string */
    442 	    *len = strlen(w);
    443 	    return w;
    444 	}
    445     }
    446 
    447     m = w;
    448 
    449     /* Find a matching tail */
    450     do
    451 	if (strcmp(p, w) == 0) {
    452 	    *len = w - m;
    453 	    return m;
    454 	}
    455     while (*w++ != '\0');
    456 
    457     return NULL;
    458 }
    459 
    460 
    461 /*-
    462  *-----------------------------------------------------------------------
    463  * Str_SYSVSubst --
    464  *	Substitute '%' on the pattern with len characters from src.
    465  *	If the pattern does not contain a '%' prepend len characters
    466  *	from src.
    467  *
    468  * Results:
    469  *	None
    470  *
    471  * Side Effects:
    472  *	Places result on buf
    473  *
    474  *-----------------------------------------------------------------------
    475  */
    476 void
    477 Str_SYSVSubst(buf, pat, src, len)
    478     Buffer buf;
    479     char *pat;
    480     char *src;
    481     int   len;
    482 {
    483     char *m;
    484 
    485     if ((m = strchr(pat, '%')) != NULL) {
    486 	/* Copy the prefix */
    487 	Buf_AddBytes(buf, m - pat, (Byte *) pat);
    488 	/* skip the % */
    489 	pat = m + 1;
    490     }
    491 
    492     /* Copy the pattern */
    493     Buf_AddBytes(buf, len, (Byte *) src);
    494 
    495     /* append the rest */
    496     Buf_AddBytes(buf, strlen(pat), (Byte *) pat);
    497 }
    498