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