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

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