[BACK]Return to str.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / make

Annotation of src/usr.bin/make/str.c, Revision 1.18

1.17      espie       1: /*     $OpenPackages$ */
1.18    ! espie       2: /*     $OpenBSD: str.c,v 1.17 2001/05/03 13:41:11 espie Exp $  */
1.5       millert     3: /*     $NetBSD: str.c,v 1.13 1996/11/06 17:59:23 christos Exp $        */
1.1       deraadt     4:
                      5: /*-
1.5       millert     6:  * Copyright (c) 1988, 1989, 1990, 1993
                      7:  *     The Regents of the University of California.  All rights reserved.
1.1       deraadt     8:  * Copyright (c) 1989 by Berkeley Softworks
                      9:  * All rights reserved.
                     10:  *
                     11:  * This code is derived from software contributed to Berkeley by
                     12:  * Adam de Boor.
                     13:  *
                     14:  * Redistribution and use in source and binary forms, with or without
                     15:  * modification, are permitted provided that the following conditions
                     16:  * are met:
                     17:  * 1. Redistributions of source code must retain the above copyright
                     18:  *    notice, this list of conditions and the following disclaimer.
                     19:  * 2. Redistributions in binary form must reproduce the above copyright
                     20:  *    notice, this list of conditions and the following disclaimer in the
                     21:  *    documentation and/or other materials provided with the distribution.
                     22:  * 3. All advertising materials mentioning features or use of this software
                     23:  *    must display the following acknowledgement:
                     24:  *     This product includes software developed by the University of
                     25:  *     California, Berkeley and its contributors.
                     26:  * 4. Neither the name of the University nor the names of its contributors
                     27:  *    may be used to endorse or promote products derived from this software
                     28:  *    without specific prior written permission.
                     29:  *
                     30:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     31:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     32:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     33:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     34:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     35:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     36:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     37:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     38:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     39:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     40:  * SUCH DAMAGE.
                     41:  */
                     42:
1.15      espie      43: #include "make.h"
                     44:
1.1       deraadt    45: #ifndef lint
                     46: #if 0
1.17      espie      47: static char    sccsid[] = "@(#)str.c   5.8 (Berkeley) 6/1/90";
1.1       deraadt    48: #else
1.15      espie      49: UNUSED
1.18    ! espie      50: static char rcsid[] = "$OpenBSD: str.c,v 1.17 2001/05/03 13:41:11 espie Exp $";
1.1       deraadt    51: #endif
                     52: #endif                         /* not lint */
                     53:
                     54: /*-
1.17      espie      55:  * str_concati --
1.12      espie      56:  *     concatenate the two strings, possibly inserting a separator
1.1       deraadt    57:  *
                     58:  * returns --
                     59:  *     the resulting string in allocated space.
                     60:  */
                     61: char *
1.17      espie      62: str_concati(s1, s2, e2, sep)
                     63:     const char *s1, *s2, *e2;
                     64:     int sep;
1.1       deraadt    65: {
1.12      espie      66:     size_t len1, len2;
                     67:     char *result;
1.1       deraadt    68:
1.12      espie      69:     /* get the length of both strings */
                     70:     len1 = strlen(s1);
1.17      espie      71:     len2 = e2 - s2;
1.12      espie      72:
                     73:     /* space for separator */
                     74:     if (sep)
                     75:        len1++;
                     76:     result = emalloc(len1 + len2 + 1);
                     77:
                     78:     /* copy first string into place */
                     79:     memcpy(result, s1, len1);
                     80:
                     81:     /* add separator character */
1.17      espie      82:     if (sep)
1.12      espie      83:        result[len1-1] = sep;
                     84:
                     85:     /* copy second string plus EOS into place */
1.18    ! espie      86:     memcpy(result + len1, s2, len2);
        !            87:     result[len1+len2] = '\0';
1.12      espie      88:     return result;
1.1       deraadt    89: }
                     90:
                     91: /*-
                     92:  * brk_string --
                     93:  *     Fracture a string into an array of words (as delineated by tabs or
                     94:  *     spaces) taking quotation marks into account.  Leading tabs/spaces
                     95:  *     are ignored.
                     96:  *
                     97:  * returns --
1.17      espie      98:  *     Pointer to the array of pointers to the words.  To make life easier,
1.1       deraadt    99:  *     the first word is always the value of the .MAKE variable.
                    100:  */
                    101: char **
1.17      espie     102: brk_string(str, store_argc, buffer)
                    103:     const char *str;
                    104:     int *store_argc;
                    105:     char **buffer;
1.1       deraadt   106: {
1.17      espie     107:     int argc;
                    108:     char ch;
                    109:     char inquote;
                    110:     const char *p;
                    111:     char *start, *t;
                    112:     size_t len;
                    113:     int argmax = 50;
                    114:     size_t curlen = 0;
                    115:     char **argv = emalloc((argmax + 1) * sizeof(char *));
                    116:
                    117:     /* skip leading space chars. */
                    118:     for (; *str == ' ' || *str == '\t'; ++str)
                    119:        continue;
                    120:
                    121:     /* allocate room for a copy of the string */
                    122:     if ((len = strlen(str) + 1) > curlen)
                    123:        *buffer = emalloc(curlen = len);
                    124:
                    125:     /*
                    126:      * copy the string; at the same time, parse backslashes,
                    127:      * quotes and build the argument list.
                    128:      */
                    129:     argc = 0;
                    130:     inquote = '\0';
                    131:     for (p = str, start = t = *buffer;; ++p) {
                    132:        switch (ch = *p) {
                    133:        case '"':
                    134:        case '\'':
                    135:            if (inquote) {
                    136:                if (inquote == ch)
                    137:                    inquote = '\0';
                    138:                else
                    139:                    break;
                    140:            } else {
                    141:                inquote = ch;
                    142:                /* Don't miss "" or '' */
                    143:                if (start == NULL && p[1] == inquote) {
                    144:                    start = t + 1;
                    145:                    break;
                    146:                }
                    147:            }
                    148:            continue;
                    149:        case ' ':
                    150:        case '\t':
                    151:        case '\n':
                    152:            if (inquote)
                    153:                break;
                    154:            if (!start)
1.1       deraadt   155:                continue;
1.17      espie     156:            /* FALLTHROUGH */
                    157:        case '\0':
                    158:            /*
                    159:             * end of a token -- make sure there's enough argv
                    160:             * space and save off a pointer.
                    161:             */
                    162:            if (!start)
                    163:                goto done;
                    164:
                    165:            *t++ = '\0';
                    166:            if (argc == argmax) {
                    167:                argmax *= 2;            /* ramp up fast */
                    168:                argv = erealloc(argv, (argmax + 1) * sizeof(char *));
                    169:            }
                    170:            argv[argc++] = start;
                    171:            start = NULL;
                    172:            if (ch == '\n' || ch == '\0')
                    173:                goto done;
                    174:            continue;
                    175:        case '\\':
                    176:            switch (ch = *++p) {
                    177:            case '\0':
                    178:            case '\n':
                    179:                /* hmmm; fix it up as best we can */
                    180:                ch = '\\';
                    181:                --p;
                    182:                break;
                    183:            case 'b':
                    184:                ch = '\b';
                    185:                break;
                    186:            case 'f':
                    187:                ch = '\f';
                    188:                break;
                    189:            case 'n':
                    190:                ch = '\n';
                    191:                break;
                    192:            case 'r':
                    193:                ch = '\r';
                    194:                break;
                    195:            case 't':
                    196:                ch = '\t';
                    197:                break;
                    198:            }
                    199:                break;
1.1       deraadt   200:        }
1.17      espie     201:        if (!start)
                    202:            start = t;
                    203:        *t++ = ch;
                    204:     }
                    205: done:
                    206:     argv[argc] = NULL;
                    207:     *store_argc = argc;
                    208:     return argv;
1.1       deraadt   209: }
                    210:
1.16      espie     211: /* Iterate through a string word by word,
                    212:  * without needing to copy anything.
                    213:  * More light-weight than brk_string, handles \ ' " as well.
                    214:  *
                    215:  * position = s;
                    216:  * while ((begin = iterate_words(&position)) != NULL) {
                    217:  *   do_something_with_word_interval(begin, position);
                    218:  * }
                    219:  */
                    220: const char *
                    221: iterate_words(end)
1.17      espie     222:     const char **end;
1.16      espie     223: {
1.17      espie     224:     const char *start, *p;
1.16      espie     225:     char       state = 0;
                    226:     start = *end;
                    227:
                    228:     while (isspace(*start))
1.17      espie     229:        start++;
1.16      espie     230:     if (*start == '\0')
1.17      espie     231:        return NULL;
1.16      espie     232:
                    233:     for (p = start;; p++)
1.17      espie     234:        switch(*p) {
1.16      espie     235:            case '\\':
1.17      espie     236:                if (p[1] != '\0')
1.16      espie     237:                    p++;
                    238:                break;
                    239:            case '\'':
                    240:            case '"':
1.17      espie     241:                if (state == *p)
1.16      espie     242:                    state = 0;
                    243:                else if (state == 0)
                    244:                    state = *p;
                    245:                break;
                    246:            case ' ':
                    247:            case '\t':
1.17      espie     248:                if (state != 0)
1.16      espie     249:                    break;
1.17      espie     250:                /* FALLTHROUGH */
1.16      espie     251:            case '\0':
1.17      espie     252:                *end = p;
1.16      espie     253:                return start;
                    254:            default:
1.17      espie     255:                break;
1.16      espie     256:            }
                    257: }
1.17      espie     258:
1.1       deraadt   259: /*
1.17      espie     260:  * Str_Matchi --
1.5       millert   261:  *
1.1       deraadt   262:  * See if a particular string matches a particular pattern.
1.5       millert   263:  *
1.14      espie     264:  * Results: TRUE is returned if string matches pattern, FALSE otherwise. The
1.1       deraadt   265:  * matching operation permits the following special characters in the
                    266:  * pattern: *?\[] (see the man page for details on what these mean).
                    267:  */
1.14      espie     268: Boolean
1.17      espie     269: Str_Matchi(string, pattern, end)
                    270:     const char *string;                /* String */
1.14      espie     271:     const char *pattern;               /* Pattern */
1.17      espie     272:     const char *end;                   /* End of Pattern */
1.1       deraadt   273: {
1.17      espie     274:     while (pattern != end) {
1.14      espie     275:        /* Check for a "*" as the next pattern character.  It matches
                    276:         * any substring.  We handle this by calling ourselves
                    277:         * recursively for each postfix of string, until either we
                    278:         * match or we reach the end of the string.  */
                    279:        if (*pattern == '*') {
                    280:            pattern++;
                    281:            /* Skip over contiguous  sequences of `?*', so that recursive
                    282:             * calls only occur on `real' characters.  */
1.17      espie     283:            while (pattern != end && (*pattern == '?' || *pattern == '*')) {
1.14      espie     284:                if (*pattern == '?') {
                    285:                    if (*string == '\0')
                    286:                        return FALSE;
                    287:                    else
                    288:                        string++;
                    289:                }
                    290:                pattern++;
                    291:            }
1.17      espie     292:            if (pattern == end)
1.14      espie     293:                return TRUE;
                    294:            for (; *string != '\0'; string++)
1.17      espie     295:                if (Str_Matchi(string, pattern, end))
1.14      espie     296:                    return TRUE;
                    297:            return FALSE;
1.17      espie     298:        } else if (*string == '\0')
1.14      espie     299:            return FALSE;
                    300:        /* Check for a "[" as the next pattern character.  It is
                    301:         * followed by a list of characters that are acceptable, or
                    302:         * by a range (two characters separated by "-").  */
                    303:        else if (*pattern == '[') {
                    304:            pattern++;
1.17      espie     305:            if (pattern == end)
                    306:                return FALSE;
1.14      espie     307:            if (*pattern == '!' || *pattern == '^') {
                    308:                pattern++;
1.17      espie     309:                if (pattern == end)
1.14      espie     310:                        return FALSE;
                    311:                /* Negative match */
                    312:                for (;;) {
                    313:                    if (*pattern == '\\') {
1.17      espie     314:                        if (++pattern == end)
1.14      espie     315:                            return FALSE;
                    316:                    }
                    317:                    if (*pattern == *string)
                    318:                        return FALSE;
                    319:                    if (pattern[1] == '-') {
1.17      espie     320:                        if (pattern + 2 == end)
1.14      espie     321:                            return FALSE;
                    322:                        if (*pattern < *string && *string <= pattern[2])
                    323:                            return FALSE;
                    324:                        if (pattern[2] <= *string && *string < *pattern)
                    325:                            return FALSE;
                    326:                        pattern += 3;
                    327:                    } else
                    328:                        pattern++;
1.17      espie     329:                    if (pattern == end)
                    330:                        return FALSE;
1.14      espie     331:                    /* The test for ']' is done at the end so that ']'
                    332:                     * can be used at the start of the range without '\' */
                    333:                    if (*pattern == ']')
1.17      espie     334:                        break;
1.1       deraadt   335:                }
1.14      espie     336:            } else {
                    337:                for (;;) {
                    338:                    if (*pattern == '\\') {
1.17      espie     339:                        if (++pattern == end)
1.14      espie     340:                            return FALSE;
                    341:                    }
                    342:                    if (*pattern == *string)
                    343:                        break;
                    344:                    if (pattern[1] == '-') {
1.17      espie     345:                        if (pattern + 2 == end)
1.14      espie     346:                            return FALSE;
                    347:                        if (*pattern < *string && *string <= pattern[2])
                    348:                            break;
                    349:                        if (pattern[2] <= *string && *string < *pattern)
                    350:                            break;
                    351:                        pattern += 3;
                    352:                    } else
                    353:                        pattern++;
                    354:                    /* The test for ']' is done at the end so that ']'
                    355:                     * can be used at the start of the range without '\' */
1.17      espie     356:                    if (pattern == end || *pattern == ']')
                    357:                        return FALSE;
1.1       deraadt   358:                }
1.14      espie     359:                /* Found matching character, skip over rest of class.  */
                    360:                while (*pattern != ']') {
                    361:                    if (*pattern == '\\')
                    362:                        pattern++;
1.17      espie     363:                    /* A non-terminated character class is ok.  */
                    364:                    if (pattern == end)
1.14      espie     365:                        break;
                    366:                    pattern++;
1.1       deraadt   367:                }
1.14      espie     368:            }
1.1       deraadt   369:        }
1.14      espie     370:        /* '?' matches any single character, so shunt test.  */
                    371:        else if (*pattern != '?') {
                    372:            /* If the next pattern character is '\', just strip off the
                    373:             * '\' so we do exact matching on the character that follows.  */
                    374:            if (*pattern == '\\') {
1.17      espie     375:                if (++pattern == end)
1.14      espie     376:                    return FALSE;
                    377:            }
1.17      espie     378:            /* There's no special character.  Just make sure that
1.14      espie     379:             * the next characters of each string match.  */
                    380:            if (*pattern != *string)
                    381:                return FALSE;
                    382:        }
                    383:        pattern++;
                    384:        string++;
                    385:     }
                    386:     if (*string == '\0')
                    387:        return TRUE;
                    388:     else
                    389:        return FALSE;
1.1       deraadt   390: }
                    391:
1.17      espie     392:
1.1       deraadt   393: /*-
                    394:  *-----------------------------------------------------------------------
                    395:  * Str_SYSVMatch --
1.5       millert   396:  *     Check word against pattern for a match (% is wild),
                    397:  *
1.1       deraadt   398:  * Results:
                    399:  *     Returns the beginning position of a match or null. The number
                    400:  *     of characters matched is returned in len.
                    401:  *-----------------------------------------------------------------------
                    402:  */
1.13      espie     403: const char *
1.1       deraadt   404: Str_SYSVMatch(word, pattern, len)
1.13      espie     405:     const char *word;          /* Word to examine */
                    406:     const char *pattern;       /* Pattern to examine against */
                    407:     size_t     *len;           /* Number of characters to substitute */
1.1       deraadt   408: {
1.13      espie     409:     const char *p = pattern;
                    410:     const char *w = word;
                    411:     const char *m;
1.1       deraadt   412:
                    413:     if (*p == '\0') {
1.17      espie     414:        /* Null pattern is the whole string.  */
1.1       deraadt   415:        *len = strlen(w);
                    416:        return w;
                    417:     }
                    418:
                    419:     if ((m = strchr(p, '%')) != NULL) {
1.17      espie     420:        /* Check that the prefix matches.  */
1.1       deraadt   421:        for (; p != m && *w && *w == *p; w++, p++)
                    422:             continue;
                    423:
                    424:        if (p != m)
1.17      espie     425:            return NULL;        /* No match.  */
1.1       deraadt   426:
                    427:        if (*++p == '\0') {
1.17      espie     428:            /* No more pattern, return the rest of the string.  */
1.1       deraadt   429:            *len = strlen(w);
                    430:            return w;
                    431:        }
                    432:     }
                    433:
                    434:     m = w;
                    435:
1.17      espie     436:     /* Find a matching tail.  */
                    437:     do {
1.1       deraadt   438:        if (strcmp(p, w) == 0) {
                    439:            *len = w - m;
                    440:            return m;
                    441:        }
1.17      espie     442:     } while (*w++ != '\0');
                    443:
1.5       millert   444:
1.1       deraadt   445:     return NULL;
                    446: }
                    447:
                    448:
                    449: /*-
                    450:  *-----------------------------------------------------------------------
                    451:  * Str_SYSVSubst --
                    452:  *     Substitute '%' on the pattern with len characters from src.
                    453:  *     If the pattern does not contain a '%' prepend len characters
                    454:  *     from src.
1.5       millert   455:  *
1.1       deraadt   456:  * Side Effects:
                    457:  *     Places result on buf
                    458:  *-----------------------------------------------------------------------
                    459:  */
                    460: void
                    461: Str_SYSVSubst(buf, pat, src, len)
                    462:     Buffer buf;
1.13      espie     463:     const char *pat;
                    464:     const char *src;
                    465:     size_t   len;
1.1       deraadt   466: {
1.13      espie     467:     const char *m;
1.1       deraadt   468:
                    469:     if ((m = strchr(pat, '%')) != NULL) {
1.17      espie     470:        /* Copy the prefix.  */
1.11      espie     471:        Buf_AddInterval(buf, pat, m);
1.17      espie     472:        /* Skip the %.  */
1.1       deraadt   473:        pat = m + 1;
                    474:     }
                    475:
1.17      espie     476:     /* Copy the pattern.  */
1.10      espie     477:     Buf_AddChars(buf, len, src);
1.1       deraadt   478:
1.17      espie     479:     /* Append the rest.  */
1.11      espie     480:     Buf_AddString(buf, pat);
1.9       espie     481: }
                    482:
                    483: char *
                    484: interval_dup(begin, end)
                    485:     const char *begin;
                    486:     const char *end;
                    487: {
                    488:     char *s;
                    489:
                    490:     s = emalloc(end - begin + 1);
                    491:     memcpy(s, begin, end - begin);
                    492:     s[end-begin] = '\0';
                    493:     return s;
1.1       deraadt   494: }
1.16      espie     495:
                    496: /* copy interval, skipping characters in the set.  */
                    497: char *
                    498: escape_dup(begin, end, set)
                    499:     const char *begin;
                    500:     const char *end;
                    501:     const char *set;
                    502: {
                    503:     char *s, *t;
                    504:
                    505:     t = s = emalloc(end - begin + 1);
                    506:     while (begin != end) {
1.17      espie     507:        if (*begin == '\\') {
1.16      espie     508:            begin++;
                    509:            if (begin == end) {
1.17      espie     510:                *t++ = '\\';
1.16      espie     511:                break;
                    512:            }
1.17      espie     513:            if (strchr(set, *begin) == NULL)
                    514:                *t++ = '\\';
1.16      espie     515:        }
                    516:        *t++ = *begin++;
                    517:     }
                    518:     *t++ = '\0';
                    519:     return s;
                    520: }
                    521:
1.17      espie     522: char *
                    523: lastchar(s, e, c)
                    524:     const char *s;
                    525:     const char *e;
                    526:     int c;
                    527: {
                    528:     if (s != e)
                    529:        do {
                    530:            if (*--e == c)
                    531:                return (char *)e;
                    532:        } while (e != s);
                    533:     return NULL;
                    534: }