[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.19

1.17      espie       1: /*     $OpenPackages$ */
1.19    ! espie       2: /*     $OpenBSD: str.c,v 1.18 2001/05/07 22:54:53 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.19    ! espie      43: #include <ctype.h>
        !            44: #include <string.h>
        !            45: #include "config.h"
        !            46: #include "defines.h"
        !            47: #include "str.h"
        !            48: #include "memory.h"
        !            49: #include "buf.h"
1.15      espie      50:
1.1       deraadt    51: char *
1.19    ! espie      52: Str_concati(s1, e1, s2, e2, sep)
        !            53:     const char *s1, *e1, *s2, *e2;
1.17      espie      54:     int sep;
1.1       deraadt    55: {
1.12      espie      56:     size_t len1, len2;
                     57:     char *result;
1.1       deraadt    58:
1.12      espie      59:     /* get the length of both strings */
1.19    ! espie      60:     len1 = e1 - s1;
1.17      espie      61:     len2 = e2 - s2;
1.12      espie      62:
                     63:     /* space for separator */
                     64:     if (sep)
                     65:        len1++;
                     66:     result = emalloc(len1 + len2 + 1);
                     67:
                     68:     /* copy first string into place */
                     69:     memcpy(result, s1, len1);
                     70:
                     71:     /* add separator character */
1.17      espie      72:     if (sep)
1.12      espie      73:        result[len1-1] = sep;
                     74:
                     75:     /* copy second string plus EOS into place */
1.18      espie      76:     memcpy(result + len1, s2, len2);
                     77:     result[len1+len2] = '\0';
1.12      espie      78:     return result;
1.1       deraadt    79: }
                     80:
                     81: /*-
                     82:  * brk_string --
                     83:  *     Fracture a string into an array of words (as delineated by tabs or
                     84:  *     spaces) taking quotation marks into account.  Leading tabs/spaces
                     85:  *     are ignored.
                     86:  *
                     87:  * returns --
1.17      espie      88:  *     Pointer to the array of pointers to the words.  To make life easier,
1.1       deraadt    89:  *     the first word is always the value of the .MAKE variable.
                     90:  */
                     91: char **
1.17      espie      92: brk_string(str, store_argc, buffer)
                     93:     const char *str;
                     94:     int *store_argc;
                     95:     char **buffer;
1.1       deraadt    96: {
1.17      espie      97:     int argc;
                     98:     char ch;
                     99:     char inquote;
                    100:     const char *p;
                    101:     char *start, *t;
                    102:     size_t len;
                    103:     int argmax = 50;
                    104:     size_t curlen = 0;
                    105:     char **argv = emalloc((argmax + 1) * sizeof(char *));
                    106:
                    107:     /* skip leading space chars. */
                    108:     for (; *str == ' ' || *str == '\t'; ++str)
                    109:        continue;
                    110:
                    111:     /* allocate room for a copy of the string */
                    112:     if ((len = strlen(str) + 1) > curlen)
                    113:        *buffer = emalloc(curlen = len);
                    114:
                    115:     /*
                    116:      * copy the string; at the same time, parse backslashes,
                    117:      * quotes and build the argument list.
                    118:      */
                    119:     argc = 0;
                    120:     inquote = '\0';
                    121:     for (p = str, start = t = *buffer;; ++p) {
                    122:        switch (ch = *p) {
                    123:        case '"':
                    124:        case '\'':
                    125:            if (inquote) {
                    126:                if (inquote == ch)
                    127:                    inquote = '\0';
                    128:                else
                    129:                    break;
                    130:            } else {
                    131:                inquote = ch;
                    132:                /* Don't miss "" or '' */
                    133:                if (start == NULL && p[1] == inquote) {
                    134:                    start = t + 1;
                    135:                    break;
                    136:                }
                    137:            }
                    138:            continue;
                    139:        case ' ':
                    140:        case '\t':
                    141:        case '\n':
                    142:            if (inquote)
                    143:                break;
                    144:            if (!start)
1.1       deraadt   145:                continue;
1.17      espie     146:            /* FALLTHROUGH */
                    147:        case '\0':
                    148:            /*
                    149:             * end of a token -- make sure there's enough argv
                    150:             * space and save off a pointer.
                    151:             */
                    152:            if (!start)
                    153:                goto done;
                    154:
                    155:            *t++ = '\0';
                    156:            if (argc == argmax) {
                    157:                argmax *= 2;            /* ramp up fast */
                    158:                argv = erealloc(argv, (argmax + 1) * sizeof(char *));
                    159:            }
                    160:            argv[argc++] = start;
                    161:            start = NULL;
                    162:            if (ch == '\n' || ch == '\0')
                    163:                goto done;
                    164:            continue;
                    165:        case '\\':
                    166:            switch (ch = *++p) {
                    167:            case '\0':
                    168:            case '\n':
                    169:                /* hmmm; fix it up as best we can */
                    170:                ch = '\\';
                    171:                --p;
                    172:                break;
                    173:            case 'b':
                    174:                ch = '\b';
                    175:                break;
                    176:            case 'f':
                    177:                ch = '\f';
                    178:                break;
                    179:            case 'n':
                    180:                ch = '\n';
                    181:                break;
                    182:            case 'r':
                    183:                ch = '\r';
                    184:                break;
                    185:            case 't':
                    186:                ch = '\t';
                    187:                break;
                    188:            }
                    189:                break;
1.1       deraadt   190:        }
1.17      espie     191:        if (!start)
                    192:            start = t;
                    193:        *t++ = ch;
                    194:     }
                    195: done:
                    196:     argv[argc] = NULL;
                    197:     *store_argc = argc;
                    198:     return argv;
1.1       deraadt   199: }
                    200:
1.19    ! espie     201:
1.16      espie     202: const char *
                    203: iterate_words(end)
1.17      espie     204:     const char **end;
1.16      espie     205: {
1.17      espie     206:     const char *start, *p;
1.16      espie     207:     char       state = 0;
                    208:     start = *end;
                    209:
                    210:     while (isspace(*start))
1.17      espie     211:        start++;
1.16      espie     212:     if (*start == '\0')
1.17      espie     213:        return NULL;
1.16      espie     214:
                    215:     for (p = start;; p++)
1.17      espie     216:        switch(*p) {
1.16      espie     217:            case '\\':
1.17      espie     218:                if (p[1] != '\0')
1.16      espie     219:                    p++;
                    220:                break;
                    221:            case '\'':
                    222:            case '"':
1.17      espie     223:                if (state == *p)
1.16      espie     224:                    state = 0;
                    225:                else if (state == 0)
                    226:                    state = *p;
                    227:                break;
                    228:            case ' ':
                    229:            case '\t':
1.17      espie     230:                if (state != 0)
1.16      espie     231:                    break;
1.17      espie     232:                /* FALLTHROUGH */
1.16      espie     233:            case '\0':
1.17      espie     234:                *end = p;
1.16      espie     235:                return start;
                    236:            default:
1.17      espie     237:                break;
1.16      espie     238:            }
                    239: }
1.17      espie     240:
1.19    ! espie     241: bool
        !           242: Str_Matchi(string, estring, pattern, end)
1.17      espie     243:     const char *string;                /* String */
1.19    ! espie     244:     const char *estring;               /* End of string */
1.14      espie     245:     const char *pattern;               /* Pattern */
1.17      espie     246:     const char *end;                   /* End of Pattern */
1.1       deraadt   247: {
1.17      espie     248:     while (pattern != end) {
1.14      espie     249:        /* Check for a "*" as the next pattern character.  It matches
                    250:         * any substring.  We handle this by calling ourselves
                    251:         * recursively for each postfix of string, until either we
                    252:         * match or we reach the end of the string.  */
                    253:        if (*pattern == '*') {
                    254:            pattern++;
                    255:            /* Skip over contiguous  sequences of `?*', so that recursive
                    256:             * calls only occur on `real' characters.  */
1.17      espie     257:            while (pattern != end && (*pattern == '?' || *pattern == '*')) {
1.14      espie     258:                if (*pattern == '?') {
1.19    ! espie     259:                    if (string == estring)
        !           260:                        return false;
1.14      espie     261:                    else
                    262:                        string++;
                    263:                }
                    264:                pattern++;
                    265:            }
1.17      espie     266:            if (pattern == end)
1.19    ! espie     267:                return true;
        !           268:            for (; string != estring; string++)
        !           269:                if (Str_Matchi(string, estring, pattern, end))
        !           270:                    return true;
        !           271:            return false;
        !           272:        } else if (string == estring)
        !           273:            return false;
1.14      espie     274:        /* Check for a "[" as the next pattern character.  It is
                    275:         * followed by a list of characters that are acceptable, or
                    276:         * by a range (two characters separated by "-").  */
                    277:        else if (*pattern == '[') {
                    278:            pattern++;
1.17      espie     279:            if (pattern == end)
1.19    ! espie     280:                return false;
1.14      espie     281:            if (*pattern == '!' || *pattern == '^') {
                    282:                pattern++;
1.17      espie     283:                if (pattern == end)
1.19    ! espie     284:                        return false;
1.14      espie     285:                /* Negative match */
                    286:                for (;;) {
                    287:                    if (*pattern == '\\') {
1.17      espie     288:                        if (++pattern == end)
1.19    ! espie     289:                            return false;
1.14      espie     290:                    }
                    291:                    if (*pattern == *string)
1.19    ! espie     292:                        return false;
1.14      espie     293:                    if (pattern[1] == '-') {
1.17      espie     294:                        if (pattern + 2 == end)
1.19    ! espie     295:                            return false;
1.14      espie     296:                        if (*pattern < *string && *string <= pattern[2])
1.19    ! espie     297:                            return false;
1.14      espie     298:                        if (pattern[2] <= *string && *string < *pattern)
1.19    ! espie     299:                            return false;
1.14      espie     300:                        pattern += 3;
                    301:                    } else
                    302:                        pattern++;
1.17      espie     303:                    if (pattern == end)
1.19    ! espie     304:                        return false;
1.14      espie     305:                    /* The test for ']' is done at the end so that ']'
                    306:                     * can be used at the start of the range without '\' */
                    307:                    if (*pattern == ']')
1.17      espie     308:                        break;
1.1       deraadt   309:                }
1.14      espie     310:            } else {
                    311:                for (;;) {
                    312:                    if (*pattern == '\\') {
1.17      espie     313:                        if (++pattern == end)
1.19    ! espie     314:                            return false;
1.14      espie     315:                    }
                    316:                    if (*pattern == *string)
                    317:                        break;
                    318:                    if (pattern[1] == '-') {
1.17      espie     319:                        if (pattern + 2 == end)
1.19    ! espie     320:                            return false;
1.14      espie     321:                        if (*pattern < *string && *string <= pattern[2])
                    322:                            break;
                    323:                        if (pattern[2] <= *string && *string < *pattern)
                    324:                            break;
                    325:                        pattern += 3;
                    326:                    } else
                    327:                        pattern++;
                    328:                    /* The test for ']' is done at the end so that ']'
                    329:                     * can be used at the start of the range without '\' */
1.17      espie     330:                    if (pattern == end || *pattern == ']')
1.19    ! espie     331:                        return false;
1.1       deraadt   332:                }
1.14      espie     333:                /* Found matching character, skip over rest of class.  */
                    334:                while (*pattern != ']') {
                    335:                    if (*pattern == '\\')
                    336:                        pattern++;
1.17      espie     337:                    /* A non-terminated character class is ok.  */
                    338:                    if (pattern == end)
1.14      espie     339:                        break;
                    340:                    pattern++;
1.1       deraadt   341:                }
1.14      espie     342:            }
1.1       deraadt   343:        }
1.14      espie     344:        /* '?' matches any single character, so shunt test.  */
                    345:        else if (*pattern != '?') {
                    346:            /* If the next pattern character is '\', just strip off the
                    347:             * '\' so we do exact matching on the character that follows.  */
                    348:            if (*pattern == '\\') {
1.17      espie     349:                if (++pattern == end)
1.19    ! espie     350:                    return false;
1.14      espie     351:            }
1.17      espie     352:            /* There's no special character.  Just make sure that
1.14      espie     353:             * the next characters of each string match.  */
                    354:            if (*pattern != *string)
1.19    ! espie     355:                return false;
1.14      espie     356:        }
                    357:        pattern++;
                    358:        string++;
                    359:     }
1.19    ! espie     360:     if (string == estring)
        !           361:        return true;
1.14      espie     362:     else
1.19    ! espie     363:        return false;
1.1       deraadt   364: }
                    365:
1.17      espie     366:
1.1       deraadt   367: /*-
                    368:  *-----------------------------------------------------------------------
                    369:  * Str_SYSVMatch --
1.5       millert   370:  *     Check word against pattern for a match (% is wild),
                    371:  *
1.1       deraadt   372:  * Results:
                    373:  *     Returns the beginning position of a match or null. The number
                    374:  *     of characters matched is returned in len.
                    375:  *-----------------------------------------------------------------------
                    376:  */
1.13      espie     377: const char *
1.1       deraadt   378: Str_SYSVMatch(word, pattern, len)
1.13      espie     379:     const char *word;          /* Word to examine */
                    380:     const char *pattern;       /* Pattern to examine against */
                    381:     size_t     *len;           /* Number of characters to substitute */
1.1       deraadt   382: {
1.13      espie     383:     const char *p = pattern;
                    384:     const char *w = word;
                    385:     const char *m;
1.1       deraadt   386:
                    387:     if (*p == '\0') {
1.17      espie     388:        /* Null pattern is the whole string.  */
1.1       deraadt   389:        *len = strlen(w);
                    390:        return w;
                    391:     }
                    392:
                    393:     if ((m = strchr(p, '%')) != NULL) {
1.17      espie     394:        /* Check that the prefix matches.  */
1.1       deraadt   395:        for (; p != m && *w && *w == *p; w++, p++)
                    396:             continue;
                    397:
                    398:        if (p != m)
1.17      espie     399:            return NULL;        /* No match.  */
1.1       deraadt   400:
                    401:        if (*++p == '\0') {
1.17      espie     402:            /* No more pattern, return the rest of the string.  */
1.1       deraadt   403:            *len = strlen(w);
                    404:            return w;
                    405:        }
                    406:     }
                    407:
                    408:     m = w;
                    409:
1.17      espie     410:     /* Find a matching tail.  */
                    411:     do {
1.1       deraadt   412:        if (strcmp(p, w) == 0) {
                    413:            *len = w - m;
                    414:            return m;
                    415:        }
1.17      espie     416:     } while (*w++ != '\0');
                    417:
1.5       millert   418:
1.1       deraadt   419:     return NULL;
                    420: }
                    421:
                    422:
                    423: /*-
                    424:  *-----------------------------------------------------------------------
                    425:  * Str_SYSVSubst --
                    426:  *     Substitute '%' on the pattern with len characters from src.
                    427:  *     If the pattern does not contain a '%' prepend len characters
                    428:  *     from src.
1.5       millert   429:  *
1.1       deraadt   430:  * Side Effects:
                    431:  *     Places result on buf
                    432:  *-----------------------------------------------------------------------
                    433:  */
                    434: void
                    435: Str_SYSVSubst(buf, pat, src, len)
                    436:     Buffer buf;
1.13      espie     437:     const char *pat;
                    438:     const char *src;
                    439:     size_t   len;
1.1       deraadt   440: {
1.13      espie     441:     const char *m;
1.1       deraadt   442:
                    443:     if ((m = strchr(pat, '%')) != NULL) {
1.17      espie     444:        /* Copy the prefix.  */
1.19    ! espie     445:        Buf_Addi(buf, pat, m);
1.17      espie     446:        /* Skip the %.  */
1.1       deraadt   447:        pat = m + 1;
                    448:     }
                    449:
1.17      espie     450:     /* Copy the pattern.  */
1.10      espie     451:     Buf_AddChars(buf, len, src);
1.1       deraadt   452:
1.17      espie     453:     /* Append the rest.  */
1.11      espie     454:     Buf_AddString(buf, pat);
1.9       espie     455: }
                    456:
                    457: char *
1.19    ! espie     458: Str_dupi(begin, end)
1.9       espie     459:     const char *begin;
                    460:     const char *end;
                    461: {
                    462:     char *s;
                    463:
                    464:     s = emalloc(end - begin + 1);
                    465:     memcpy(s, begin, end - begin);
                    466:     s[end-begin] = '\0';
                    467:     return s;
1.1       deraadt   468: }
1.16      espie     469:
                    470: char *
1.19    ! espie     471: escape_dupi(begin, end, set)
1.16      espie     472:     const char *begin;
                    473:     const char *end;
                    474:     const char *set;
                    475: {
                    476:     char *s, *t;
                    477:
                    478:     t = s = emalloc(end - begin + 1);
                    479:     while (begin != end) {
1.17      espie     480:        if (*begin == '\\') {
1.16      espie     481:            begin++;
                    482:            if (begin == end) {
1.17      espie     483:                *t++ = '\\';
1.16      espie     484:                break;
                    485:            }
1.17      espie     486:            if (strchr(set, *begin) == NULL)
                    487:                *t++ = '\\';
1.16      espie     488:        }
                    489:        *t++ = *begin++;
                    490:     }
                    491:     *t++ = '\0';
                    492:     return s;
                    493: }
                    494:
1.17      espie     495: char *
1.19    ! espie     496: Str_rchri(s, e, c)
1.17      espie     497:     const char *s;
                    498:     const char *e;
                    499:     int c;
                    500: {
                    501:     if (s != e)
                    502:        do {
                    503:            if (*--e == c)
                    504:                return (char *)e;
                    505:        } while (e != s);
                    506:     return NULL;
                    507: }