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