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

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