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