xref: /original-bsd/usr.bin/make/str.c (revision 80efab63)
1 /*
2  * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
3  * Copyright (c) 1988, 1989 by Adam de Boor
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 are permitted
11  * provided that the above copyright notice and this paragraph are
12  * duplicated in all such forms and that any documentation,
13  * advertising materials, and other materials related to such
14  * distribution and use acknowledge that the software was developed
15  * by the University of California, Berkeley.  The name of the
16  * University may not be used to endorse or promote products derived
17  * from this software without specific prior written permission.
18  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
21  */
22 
23 #ifndef lint
24 static char sccsid[] = "@(#)str.c	5.2 (Berkeley) 03/11/90";
25 #endif /* not lint */
26 
27 /*-
28  * str.c --
29  *	General utilites for handling strings.
30  *
31  * Interface:
32  *	Str_Concat	     	Concatenate two strings, placing some sort
33  *	    	  	    	of separator between them and freeing
34  *	    	  	    	the two strings, all this under the control
35  *	    	  	    	of the STR_ flags given as the third arg.
36  *
37  *	Str_New	  	    	Duplicate a string and return the copy.
38  *
39  *	Str_FindSubstring   	Find a substring within a string (from
40  *	    	  	    	original Sprite libc).
41  *
42  *	Str_Match   	    	Pattern match two strings.
43  */
44 
45 #include    "make.h"
46 
47 /*-
48  *-----------------------------------------------------------------------
49  * Str_Concat  --
50  *	Str_Concatenate and the two strings, inserting a space between them
51  *	and/or freeing them if requested
52  *
53  * Results:
54  *	the resulting string
55  *
56  * Side Effects:
57  *	The strings s1 and s2 are free'd
58  *-----------------------------------------------------------------------
59  */
60 char *
61 Str_Concat (s1, s2, flags)
62     char           *s1;		/* first string */
63     char           *s2;		/* second string */
64     int             flags;	/* flags governing Str_Concatenation */
65 {
66     int             len;	/* total length */
67     register char  *cp1,	/* pointer into s1 */
68                    *cp2,	/* pointer into s2 */
69                    *cp;		/* pointer into result */
70     char           *result;	/* result string */
71 
72     /*
73      * get the length of both strings
74      */
75     for (cp1 = s1; *cp1; cp1++) {
76 	 /* void */ ;
77     }
78     for (cp2 = s2; *cp2; cp2++) {
79 	 /* void */ ;
80     }
81 
82     len = (cp1 - s1) +
83 	(cp2 - s2) +
84 	    (flags & (STR_ADDSPACE | STR_ADDSLASH) ? 1 : 0) +
85 		1;
86 
87     result = malloc (len);
88 
89     for (cp1 = s1, cp = result; *cp1 != '\0'; cp++, cp1++) {
90 	*cp = *cp1;
91     }
92 
93     if (flags & STR_ADDSPACE) {
94 	*cp++ = ' ';
95     } else if (flags & STR_ADDSLASH) {
96 	*cp++ = '/';
97     }
98 
99     for (cp2 = s2; *cp2 != '\0'; cp++, cp2++) {
100 	*cp = *cp2;
101     }
102 
103     *cp = '\0';
104 
105     if (flags & STR_DOFREE) {
106 	free (s1);
107 	free (s2);
108     }
109     return (result);
110 }
111 
112 /*-
113  *-----------------------------------------------------------------------
114  * Str_New  --
115  *	Create a new unique copy of the given string
116  *
117  * Results:
118  *	A pointer to the new copy of it
119  *
120  * Side Effects:
121  *	None
122  *-----------------------------------------------------------------------
123  */
124 char *
125 Str_New (str)
126     char           *str;	/* string to duplicate */
127 {
128     register char  *cp;		/* new space */
129 
130     cp = malloc (strlen (str) + 1);
131     (void) strcpy (cp, str);
132     return (cp);
133 }
134 
135 static char
136 DoBackslash (c)
137     char c;
138 {
139     switch (c) {
140 	case 'n': return ('\n');
141 	case 't': return ('\t');
142 	case 'b': return ('\b');
143 	case 'r': return ('\r');
144 	case 'f': return ('\f');
145 	default:  return (c);
146     }
147 }
148 
149 /*-
150  *-----------------------------------------------------------------------
151  * Str_BreakString --
152  *	Fracture a string into an array of words, taking quotation marks
153  *	into account. The string should have its leading 'breaks'
154  *	characters removed.
155  *
156  * Results:
157  *	Pointer to the array of pointers to the words. This array must
158  *	be freed by the caller. To make life easier, the first word is
159  *	always the value of the .PMAKE variable.
160  *
161  * Side Effects:
162  *	None.
163  *
164  *-----------------------------------------------------------------------
165  */
166 char **
167 Str_BreakString (str, breaks, end, argcPtr)
168     register char 	*str;	    	/* String to fracture */
169     register char 	*breaks;    	/* Word delimiters */
170     register char 	*end;	    	/* Characters to end on */
171     int	    	  	*argcPtr;   	/* OUT: Place to stuff number of
172 					 * words */
173 {
174     char            	*defargv[256]; 	/* Temporary argument vector.
175 					 * Big enough for most purposes. */
176     char    	    	**argv;	    	/* Argv being built */
177     int	    	    	maxargc;    	/* Length of argv */
178     register int    	argc;	    	/* Count of words */
179     char            	**av;	    	/* Returned vector */
180     register char   	*tstr;	    	/* Pointer into tstring */
181     char            	tstring[512];	/* Temporary storage for the
182 					 * current word */
183 
184     argc = 1;
185     argv = defargv;
186     maxargc = sizeof(defargv)/sizeof(defargv[0]);
187     argv[0] = Var_Value (".PMAKE", VAR_GLOBAL);
188 
189     tstr = tstring;
190     while ((*str != '\0') && (index (end, *str) == (char *)NULL)) {
191 	if (index (breaks, *str) != (char *)NULL) {
192 	    *tstr++ = '\0';
193 	    argv[argc++] = Str_New(tstring);
194 	    while ((*str != '\0') &&
195 		   (index (breaks, *str) != (char *)NULL) &&
196 		   (index (end, *str) == (char *)NULL)) {
197 		       str++;
198 		   }
199 	    tstr = tstring;
200 	    /*
201 	     * Enlarge the argument vector, if necessary
202 	     */
203 	    if (argc == maxargc) {
204 		maxargc *= 2;
205 		if (argv == defargv) {
206 		    argv = (char **)malloc(maxargc*sizeof(char *));
207 		    bcopy(defargv, argv, sizeof(defargv));
208 		} else {
209 		    argv = (char **)realloc(argv,
210 					    maxargc*sizeof(char *));
211 		}
212 	    }
213 	} else if (*str == '"') {
214 	    str += 1;
215 	    while ((*str != '"') &&
216 		   (index (end, *str) == (char *)NULL)) {
217 		       if (*str == '\\') {
218 			   str += 1;
219 			   *tstr = DoBackslash(*str);
220 		       } else {
221 			   *tstr = *str;
222 		       }
223 		       str += 1;
224 		       tstr += 1;
225 		   }
226 
227 	    if (*str == '"') {
228 		str+=1;
229 	    }
230 	} else if (*str == '\'') {
231 	    str += 1;
232 	    while ((*str != '\'') &&
233 		   (index (end, *str) == (char *)NULL)) {
234 		       if (*str == '\\') {
235 			   str += 1;
236 			   *tstr = DoBackslash(*str);
237 		       } else {
238 			   *tstr = *str;
239 		       }
240 		       str += 1;
241 		       tstr += 1;
242 		   }
243 
244 	    if (*str == '\'') {
245 		str+=1;
246 	    }
247 	} else if (*str == '\\') {
248 	    str += 1;
249 	    *tstr = DoBackslash(*str);
250 	    str += 1;
251 	    tstr += 1;
252 	} else {
253 	    *tstr = *str;
254 	    tstr += 1;
255 	    str += 1;
256 	}
257     }
258     if (tstr != tstring) {
259 	/*
260 	 * If any word is left over, add it to the vector
261 	 */
262 	*tstr = '\0';
263 	argv[argc++] = Str_New(tstring);
264     }
265     argv[argc] = (char *) 0;
266     *argcPtr = argc;
267     if (argv == defargv) {
268 	av = (char **) malloc ((argc+1) * sizeof(char *));
269 	bcopy ((char *)argv, (char *)av, (argc + 1) * sizeof(char *));
270     } else {
271 	/*
272 	 * Shrink vector to match actual number of args.
273 	 */
274 	av = (char **)realloc(argv, (argc+1) * sizeof(char *));
275     }
276 
277     return av;
278 }
279 
280 /*-
281  *-----------------------------------------------------------------------
282  * Str_FreeVec --
283  *	Free a string vector returned by Str_BreakString. Frees all the
284  *	strings in the vector and then frees the vector itself.
285  *
286  * Results:
287  *	None.
288  *
289  * Side Effects:
290  *	The blocks addressed by the vector are freed.
291  *
292  *-----------------------------------------------------------------------
293  */
294 void
295 Str_FreeVec (count, vecPtr)
296     register int  count;
297     register char **vecPtr;
298 {
299     for (count -= 1; count > 0; count -= 1) {
300 	free (vecPtr[count]);
301     }
302     free (vecPtr);
303 }
304 #ifndef Sprite
305 
306 /*
307  *----------------------------------------------------------------------
308  * Str_FindSubstring --
309  *	See if a string contains a particular substring.
310  *
311  * Results:
312  *	If string contains substring, the return value is the
313  *	location of the first matching instance of substring
314  *	in string.  If string doesn't contain substring, the
315  *	return value is NULL.  Matching is done on an exact
316  *	character-for-character basis with no wildcards or special
317  *	characters.
318  *
319  * Side effects:
320  *	None.
321  *----------------------------------------------------------------------
322  */
323 char *
324 Str_FindSubstring(string, substring)
325     register char *string;	/* String to search. */
326     char *substring;		/* Substring to try to find in string. */
327 {
328     register char *a, *b;
329 
330     /*
331      * First scan quickly through the two strings looking for a
332      * single-character match.  When it's found, then compare the
333      * rest of the substring.
334      */
335 
336     b = substring;
337     for ( ; *string != 0; string += 1) {
338 	if (*string != *b) {
339 	    continue;
340 	}
341 	a = string;
342 	while (TRUE) {
343 	    if (*b == 0) {
344 		return string;
345 	    }
346 	    if (*a++ != *b++) {
347 		break;
348 	    }
349 	}
350 	b = substring;
351     }
352     return (char *) NULL;
353 }
354 
355 #endif /* !Sprite */
356 
357 /*
358  *----------------------------------------------------------------------
359  *
360  * Str_Match --
361  *
362  *      See if a particular string matches a particular pattern.
363  *
364  * Results:
365  *      Non-zero is returned if string matches pattern, 0 otherwise.
366  *      The matching operation permits the following special characters
367  *      in the pattern: *?\[] (see the man page for details on what
368  *      these mean).
369  *
370  * Side effects:
371  *      None.
372  *
373  *----------------------------------------------------------------------
374  */
375 
376 int
377 Str_Match(string, pattern)
378     register char *string;              /* String. */
379     register char *pattern;             /* Pattern, which may contain
380                                          * special characters.
381                                          */
382 {
383     char c2;
384 
385     while (1) {
386         /* See if we're at the end of both the pattern and the string.
387          * If, we succeeded.  If we're at the end of the pattern but
388          * not at the end of the string, we failed.
389          */
390 
391         if (*pattern == 0) {
392             if (*string == 0) {
393                 return 1;
394             } else {
395                 return 0;
396             }
397         }
398         if ((*string == 0) && (*pattern != '*')) {
399             return 0;
400         }
401 
402         /* Check for a "*" as the next pattern character.  It matches
403          * any substring.  We handle this by calling ourselves
404          * recursively for each postfix of string, until either we
405          * match or we reach the end of the string.
406          */
407 
408         if (*pattern == '*') {
409             pattern += 1;
410             if (*pattern == 0) {
411                 return 1;
412             }
413             while (*string != 0) {
414                 if (Str_Match(string, pattern)) {
415                     return 1;
416                 }
417                 string += 1;
418             }
419             return 0;
420         }
421 
422         /* Check for a "?" as the next pattern character.  It matches
423          * any single character.
424          */
425 
426         if (*pattern == '?') {
427             goto thisCharOK;
428         }
429 
430         /* Check for a "[" as the next pattern character.  It is followed
431          * by a list of characters that are acceptable, or by a range
432          * (two characters separated by "-").
433          */
434 
435         if (*pattern == '[') {
436             pattern += 1;
437             while (1) {
438                 if ((*pattern == ']') || (*pattern == 0)) {
439                     return 0;
440                 }
441                 if (*pattern == *string) {
442                     break;
443                 }
444                 if (pattern[1] == '-') {
445                     c2 = pattern[2];
446                     if (c2 == 0) {
447                         return 0;
448                     }
449                     if ((*pattern <= *string) && (c2 >= *string)) {
450                         break;
451                     }
452                     if ((*pattern >= *string) && (c2 <= *string)) {
453                         break;
454                     }
455                     pattern += 2;
456                 }
457                 pattern += 1;
458             }
459             while ((*pattern != ']') && (*pattern != 0)) {
460                 pattern += 1;
461             }
462             goto thisCharOK;
463         }
464 
465         /* If the next pattern character is '/', just strip off the '/'
466          * so we do exact matching on the character that follows.
467          */
468 
469         if (*pattern == '\\') {
470             pattern += 1;
471             if (*pattern == 0) {
472                 return 0;
473             }
474         }
475 
476         /* There's no special character.  Just make sure that the next
477          * characters of each string match.
478          */
479 
480         if (*pattern != *string) {
481             return 0;
482         }
483 
484         thisCharOK: pattern += 1;
485         string += 1;
486     }
487 }
488