Merge from vendor branch LIBARCHIVE:
[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.2 2004/02/23 12:10:57 ru Exp $
40  * $DragonFly: src/usr.bin/make/str.c,v 1.3 2004/10/24 22:43:58 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 (ch != inquote)
168                                         break;
169                                 inquote = '\0';
170                                 /* Don't miss "" or '' */
171                                 if (!start)
172                                         start = t;
173                         } else
174                                 inquote = (char) ch;
175                         if (expand)
176                                 continue;
177                         break;
178                 case ' ':
179                 case '\t':
180                 case '\n':
181                         if (inquote)
182                                 break;
183                         if (!start)
184                                 continue;
185                         /* FALLTHROUGH */
186                 case '\0':
187                         /*
188                          * end of a token -- make sure there's enough argv
189                          * space and save off a pointer.
190                          */
191                         if (!start)
192                             goto done;
193
194                         *t++ = '\0';
195                         if (argc == argmax) {
196                                 argmax *= 2;            /* ramp up fast */
197                                 argv = (char **)erealloc(argv,
198                                     (argmax + 1) * sizeof(char *));
199                         }
200                         argv[argc++] = start;
201                         start = (char *)NULL;
202                         if (ch == '\n' || ch == '\0')
203                                 goto done;
204                         continue;
205                 case '\\':
206                         if (!expand) {
207                                 if (!start)
208                                         start = t;
209                                 *t++ = '\\';
210                                 ch = *++p;
211                                 break;
212                         }
213
214                         switch (ch = *++p) {
215                         case '\0':
216                         case '\n':
217                                 /* hmmm; fix it up as best we can */
218                                 ch = '\\';
219                                 --p;
220                                 break;
221                         case 'b':
222                                 ch = '\b';
223                                 break;
224                         case 'f':
225                                 ch = '\f';
226                                 break;
227                         case 'n':
228                                 ch = '\n';
229                                 break;
230                         case 'r':
231                                 ch = '\r';
232                                 break;
233                         case 't':
234                                 ch = '\t';
235                                 break;
236                         }
237                         break;
238                 }
239                 if (!start)
240                         start = t;
241                 *t++ = (char) ch;
242         }
243 done:   argv[argc] = (char *)NULL;
244         *store_argc = argc;
245         return(argv);
246 }
247
248 /*
249  * Str_FindSubstring -- See if a string contains a particular substring.
250  *
251  * Results: If string contains substring, the return value is the location of
252  * the first matching instance of substring in string.  If string doesn't
253  * contain substring, the return value is NULL.  Matching is done on an exact
254  * character-for-character basis with no wildcards or special characters.
255  *
256  * Side effects: None.
257  */
258 char *
259 Str_FindSubstring(string, substring)
260         register char *string;          /* String to search. */
261         char *substring;                /* Substring to find in string */
262 {
263         register char *a, *b;
264
265         /*
266          * First scan quickly through the two strings looking for a single-
267          * character match.  When it's found, then compare the rest of the
268          * substring.
269          */
270
271         for (b = substring; *string != 0; string += 1) {
272                 if (*string != *b)
273                         continue;
274                 a = string;
275                 for (;;) {
276                         if (*b == 0)
277                                 return(string);
278                         if (*a++ != *b++)
279                                 break;
280                 }
281                 b = substring;
282         }
283         return((char *) NULL);
284 }
285
286 /*
287  * Str_Match --
288  *
289  * See if a particular string matches a particular pattern.
290  *
291  * Results: Non-zero is returned if string matches pattern, 0 otherwise. The
292  * matching operation permits the following special characters in the
293  * pattern: *?\[] (see the man page for details on what these mean).
294  *
295  * Side effects: None.
296  */
297 int
298 Str_Match(string, pattern)
299         register char *string;          /* String */
300         register char *pattern;         /* Pattern */
301 {
302         char c2;
303
304         for (;;) {
305                 /*
306                  * See if we're at the end of both the pattern and the
307                  * string. If, we succeeded.  If we're at the end of the
308                  * pattern but not at the end of the string, we failed.
309                  */
310                 if (*pattern == 0)
311                         return(!*string);
312                 if (*string == 0 && *pattern != '*')
313                         return(0);
314                 /*
315                  * Check for a "*" as the next pattern character.  It matches
316                  * any substring.  We handle this by calling ourselves
317                  * recursively for each postfix of string, until either we
318                  * match or we reach the end of the string.
319                  */
320                 if (*pattern == '*') {
321                         pattern += 1;
322                         if (*pattern == 0)
323                                 return(1);
324                         while (*string != 0) {
325                                 if (Str_Match(string, pattern))
326                                         return(1);
327                                 ++string;
328                         }
329                         return(0);
330                 }
331                 /*
332                  * Check for a "?" as the next pattern character.  It matches
333                  * any single character.
334                  */
335                 if (*pattern == '?')
336                         goto thisCharOK;
337                 /*
338                  * Check for a "[" as the next pattern character.  It is
339                  * followed by a list of characters that are acceptable, or
340                  * by a range (two characters separated by "-").
341                  */
342                 if (*pattern == '[') {
343                         ++pattern;
344                         for (;;) {
345                                 if ((*pattern == ']') || (*pattern == 0))
346                                         return(0);
347                                 if (*pattern == *string)
348                                         break;
349                                 if (pattern[1] == '-') {
350                                         c2 = pattern[2];
351                                         if (c2 == 0)
352                                                 return(0);
353                                         if ((*pattern <= *string) &&
354                                             (c2 >= *string))
355                                                 break;
356                                         if ((*pattern >= *string) &&
357                                             (c2 <= *string))
358                                                 break;
359                                         pattern += 2;
360                                 }
361                                 ++pattern;
362                         }
363                         while ((*pattern != ']') && (*pattern != 0))
364                                 ++pattern;
365                         goto thisCharOK;
366                 }
367                 /*
368                  * If the next pattern character is '/', just strip off the
369                  * '/' so we do exact matching on the character that follows.
370                  */
371                 if (*pattern == '\\') {
372                         ++pattern;
373                         if (*pattern == 0)
374                                 return(0);
375                 }
376                 /*
377                  * There's no special character.  Just make sure that the
378                  * next characters of each string match.
379                  */
380                 if (*pattern != *string)
381                         return(0);
382 thisCharOK:     ++pattern;
383                 ++string;
384         }
385 }
386
387
388 /*-
389  *-----------------------------------------------------------------------
390  * Str_SYSVMatch --
391  *      Check word against pattern for a match (% is wild),
392  *
393  * Results:
394  *      Returns the beginning position of a match or null. The number
395  *      of characters matched is returned in len.
396  *
397  * Side Effects:
398  *      None
399  *
400  *-----------------------------------------------------------------------
401  */
402 char *
403 Str_SYSVMatch(word, pattern, len)
404     char        *word;          /* Word to examine */
405     char        *pattern;       /* Pattern to examine against */
406     int         *len;           /* Number of characters to substitute */
407 {
408     char *p = pattern;
409     char *w = word;
410     char *m;
411
412     if (*w == '\0') {
413         /* Zero-length word cannot be matched against */
414         *len = 0;
415         return NULL;
416     }
417
418     if (*p == '\0') {
419         /* Null pattern is the whole string */
420         *len = strlen(w);
421         return w;
422     }
423
424     if ((m = strchr(p, '%')) != NULL) {
425         /* check that the prefix matches */
426         for (; p != m && *w && *w == *p; w++, p++)
427              continue;
428
429         if (p != m)
430             return NULL;        /* No match */
431
432         if (*++p == '\0') {
433             /* No more pattern, return the rest of the string */
434             *len = strlen(w);
435             return w;
436         }
437     }
438
439     m = w;
440
441     /* Find a matching tail */
442     do
443         if (strcmp(p, w) == 0) {
444             *len = w - m;
445             return m;
446         }
447     while (*w++ != '\0');
448
449     return NULL;
450 }
451
452
453 /*-
454  *-----------------------------------------------------------------------
455  * Str_SYSVSubst --
456  *      Substitute '%' on the pattern with len characters from src.
457  *      If the pattern does not contain a '%' prepend len characters
458  *      from src.
459  *
460  * Results:
461  *      None
462  *
463  * Side Effects:
464  *      Places result on buf
465  *
466  *-----------------------------------------------------------------------
467  */
468 void
469 Str_SYSVSubst(buf, pat, src, len)
470     Buffer buf;
471     char *pat;
472     char *src;
473     int   len;
474 {
475     char *m;
476
477     if ((m = strchr(pat, '%')) != NULL) {
478         /* Copy the prefix */
479         Buf_AddBytes(buf, m - pat, (Byte *) pat);
480         /* skip the % */
481         pat = m + 1;
482     }
483
484     /* Copy the pattern */
485     Buf_AddBytes(buf, len, (Byte *) src);
486
487     /* append the rest */
488     Buf_AddBytes(buf, strlen(pat), (Byte *) pat);
489 }