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

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