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