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