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

Annotation of src/usr.bin/make/varmodifiers.c, Revision 1.22

1.7       espie       1: /*     $OpenPackages$ */
1.22    ! espie       2: /*     $OpenBSD: varmodifiers.c,v 1.14 2005/07/15 20:43:23 espie Exp $ */
1.1       espie       3: /*     $NetBSD: var.c,v 1.18 1997/03/18 19:24:46 christos Exp $        */
                      4:
                      5: /*
                      6:  * Copyright (c) 1999 Marc Espie.
                      7:  *
                      8:  * Extensive code changes for the OpenBSD project.
                      9:  *
                     10:  * Redistribution and use in source and binary forms, with or without
                     11:  * modification, are permitted provided that the following conditions
                     12:  * are met:
                     13:  * 1. Redistributions of source code must retain the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer.
                     15:  * 2. Redistributions in binary form must reproduce the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer in the
                     17:  *    documentation and/or other materials provided with the distribution.
                     18:  *
                     19:  * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS
                     20:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
                     21:  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
                     22:  * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OPENBSD
                     23:  * PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
                     24:  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
                     25:  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     26:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                     27:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     28:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
                     29:  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     30:  */
                     31: /*
                     32:  * Copyright (c) 1988, 1989, 1990, 1993
                     33:  *     The Regents of the University of California.  All rights reserved.
                     34:  * Copyright (c) 1989 by Berkeley Softworks
                     35:  * All rights reserved.
                     36:  *
                     37:  * This code is derived from software contributed to Berkeley by
                     38:  * Adam de Boor.
                     39:  *
                     40:  * Redistribution and use in source and binary forms, with or without
                     41:  * modification, are permitted provided that the following conditions
                     42:  * are met:
                     43:  * 1. Redistributions of source code must retain the above copyright
                     44:  *    notice, this list of conditions and the following disclaimer.
                     45:  * 2. Redistributions in binary form must reproduce the above copyright
                     46:  *    notice, this list of conditions and the following disclaimer in the
                     47:  *    documentation and/or other materials provided with the distribution.
1.11      millert    48:  * 3. Neither the name of the University nor the names of its contributors
1.1       espie      49:  *    may be used to endorse or promote products derived from this software
                     50:  *    without specific prior written permission.
                     51:  *
                     52:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     53:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     54:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     55:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     56:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     57:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     58:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     59:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     60:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     61:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     62:  * SUCH DAMAGE.
                     63:  */
                     64:
1.7       espie      65: /* VarModifiers_Apply is mostly a constituent function of Var_Parse, it
                     66:  * is also called directly by Var_SubstVar.  */
                     67:
                     68:
1.9       espie      69: #include <ctype.h>
                     70: #include <sys/types.h>
1.1       espie      71: #ifndef MAKE_BOOTSTRAP
1.9       espie      72: #include <regex.h>
1.1       espie      73: #endif
1.9       espie      74: #include <stddef.h>
                     75: #include <stdio.h>
                     76: #include <stdlib.h>
                     77: #include <string.h>
                     78: #include "config.h"
                     79: #include "defines.h"
1.1       espie      80: #include "buf.h"
1.9       espie      81: #include "var.h"
1.1       espie      82: #include "varmodifiers.h"
1.9       espie      83: #include "varname.h"
                     84: #include "targ.h"
                     85: #include "error.h"
                     86: #include "str.h"
                     87: #include "cmd_exec.h"
                     88: #include "memory.h"
                     89: #include "gnode.h"
                     90:
1.1       espie      91:
                     92: /* Var*Pattern flags */
                     93: #define VAR_SUB_GLOBAL 0x01    /* Apply substitution globally */
                     94: #define VAR_SUB_ONE    0x02    /* Apply substitution to one word */
1.7       espie      95: #define VAR_SUB_MATCHED 0x04   /* There was a match */
                     96: #define VAR_MATCH_START 0x08   /* Match at start of word */
1.1       espie      97: #define VAR_MATCH_END  0x10    /* Match at end of word */
                     98:
1.7       espie      99: /* Modifiers flags */
                    100: #define VAR_EQUAL      0x20
                    101: #define VAR_MAY_EQUAL  0x40
                    102: #define VAR_ADD_EQUAL  0x80
                    103: #define VAR_BANG_EQUAL 0x100
                    104:
1.1       espie     105: typedef struct {
1.22    ! espie     106:        char      *lbuffer; /* left string to free */
        !           107:        char      *lhs;     /* String to match */
        !           108:        size_t    leftLen;  /* Length of string */
        !           109:        char      *rhs;     /* Replacement string (w/ &'s removed) */
        !           110:        size_t    rightLen; /* Length of replacement */
        !           111:        int       flags;
1.1       espie     112: } VarPattern;
                    113:
1.7       espie     114: struct LoopStuff {
1.22    ! espie     115:        struct LoopVar  *var;
        !           116:        char    *expand;
        !           117:        bool    err;
1.7       espie     118: };
                    119:
1.9       espie     120: static bool VarHead(struct Name *, bool, Buffer, void *);
                    121: static bool VarTail(struct Name *, bool, Buffer, void *);
                    122: static bool VarSuffix(struct Name *, bool, Buffer, void *);
                    123: static bool VarRoot(struct Name *, bool, Buffer, void *);
                    124: static bool VarMatch(struct Name *, bool, Buffer, void *);
                    125: static bool VarSYSVMatch(struct Name *, bool, Buffer, void *);
                    126: static bool VarNoMatch(struct Name *, bool, Buffer, void *);
                    127: static bool VarUniq(struct Name *, bool, Buffer, void *);
                    128: static bool VarLoop(struct Name *, bool, Buffer, void *);
1.7       espie     129:
                    130:
1.1       espie     131: #ifndef MAKE_BOOTSTRAP
1.7       espie     132: static void VarREError(int, regex_t *, const char *);
1.9       espie     133: static bool VarRESubstitute(struct Name *, bool, Buffer, void *);
1.7       espie     134: static char *do_regex(const char *, const struct Name *, void *);
                    135:
1.1       espie     136: typedef struct {
1.22    ! espie     137:        regex_t   re;
        !           138:        int       nsub;
        !           139:        regmatch_t       *matches;
        !           140:        char     *replace;
        !           141:        int       flags;
1.1       espie     142: } VarREPattern;
                    143: #endif
                    144:
1.9       espie     145: static bool VarSubstitute(struct Name *, bool, Buffer, void *);
1.7       espie     146: static char *VarGetPattern(SymTable *, int, const char **, int, int,
                    147:     size_t *, VarPattern *);
                    148: static char *VarQuote(const char *, const struct Name *, void *);
1.9       espie     149: static char *VarModify(char *, bool (*)(struct Name *, bool, Buffer, void *), void *);
1.7       espie     150:
1.9       espie     151: static void *check_empty(const char **, SymTable *, bool, int);
1.7       espie     152: static char *do_upper(const char *, const struct Name *, void *);
                    153: static char *do_lower(const char *, const struct Name *, void *);
1.9       espie     154: static void *check_shcmd(const char **, SymTable *, bool, int);
1.7       espie     155: static char *do_shcmd(const char *, const struct Name *, void *);
                    156: static char *do_sort(const char *, const struct Name *, void *);
                    157: static char *finish_loop(const char *, const struct Name *, void *);
                    158: static int NameCompare(const void *, const void *);
                    159: static char *do_label(const char *, const struct Name *, void *);
                    160: static char *do_path(const char *, const struct Name *, void *);
                    161: static char *do_def(const char *, const struct Name *, void *);
                    162: static char *do_undef(const char *, const struct Name *, void *);
                    163: static char *do_assign(const char *, const struct Name *, void *);
                    164: static char *do_exec(const char *, const struct Name *, void *);
                    165:
1.9       espie     166: static void *assign_get_value(const char **, SymTable *, bool, int);
                    167: static void *get_cmd(const char **, SymTable *, bool, int);
                    168: static void *get_value(const char **, SymTable *, bool, int);
                    169: static void *get_stringarg(const char **, SymTable *, bool, int);
1.7       espie     170: static void free_stringarg(void *);
1.9       espie     171: static void *get_patternarg(const char **, SymTable *, bool, int);
                    172: static void *get_spatternarg(const char **, SymTable *, bool, int);
1.10      espie     173: static void *common_get_patternarg(const char **, SymTable *, bool, int, bool);
1.7       espie     174: static void free_patternarg(void *);
                    175: static void free_looparg(void *);
1.9       espie     176: static void *get_sysvpattern(const char **, SymTable *, bool, int);
                    177: static void *get_loop(const char **, SymTable *, bool, int);
1.7       espie     178: static char *LoopGrab(const char **);
                    179:
                    180: static struct Name dummy;
                    181: static struct Name *dummy_arg = &dummy;
                    182:
                    183: static struct modifier {
1.22    ! espie     184:            bool atstart;
        !           185:            void * (*getarg)(const char **, SymTable *, bool, int);
        !           186:            char * (*apply)(const char *, const struct Name *, void *);
        !           187:            bool (*word_apply)(struct Name *, bool, Buffer, void *);
        !           188:            void   (*freearg)(void *);
1.7       espie     189: } *choose_mod[256],
1.22    ! espie     190:        match_mod = {false, get_stringarg, NULL, VarMatch, free_stringarg},
        !           191:        nomatch_mod = {false, get_stringarg, NULL, VarNoMatch, free_stringarg},
        !           192:        subst_mod = {false, get_spatternarg, NULL, VarSubstitute, free_patternarg},
1.1       espie     193: #ifndef MAKE_BOOTSTRAP
1.22    ! espie     194:        resubst_mod = {false, get_patternarg, do_regex, NULL, free_patternarg},
1.1       espie     195: #endif
1.22    ! espie     196:        quote_mod = {false, check_empty, VarQuote, NULL , NULL},
        !           197:        tail_mod = {false, check_empty, NULL, VarTail, NULL},
        !           198:        head_mod = {false, check_empty, NULL, VarHead, NULL},
        !           199:        suffix_mod = {false, check_empty, NULL, VarSuffix, NULL},
        !           200:        root_mod = {false, check_empty, NULL, VarRoot, NULL},
        !           201:        upper_mod = {false, check_empty, do_upper, NULL, NULL},
        !           202:        lower_mod = {false, check_empty, do_lower, NULL, NULL},
        !           203:        shcmd_mod = {false, check_shcmd, do_shcmd, NULL, NULL},
        !           204:        sysv_mod = {false, get_sysvpattern, NULL, VarSYSVMatch, free_patternarg},
        !           205:        uniq_mod = {false, check_empty, NULL, VarUniq, NULL},
        !           206:        sort_mod = {false, check_empty, do_sort, NULL, NULL},
        !           207:        loop_mod = {false, get_loop, finish_loop, VarLoop, free_looparg},
        !           208:        undef_mod = {true, get_value, do_undef, NULL, NULL},
        !           209:        def_mod = {true, get_value, do_def, NULL, NULL},
        !           210:        label_mod = {true, check_empty, do_label, NULL, NULL},
        !           211:        path_mod = {true, check_empty, do_path, NULL, NULL},
        !           212:        assign_mod = {true, assign_get_value, do_assign, NULL, free_patternarg},
        !           213:        exec_mod = {true, get_cmd, do_exec, NULL, free_patternarg}
1.7       espie     214: ;
1.1       espie     215:
1.7       espie     216: void
                    217: VarModifiers_Init()
1.1       espie     218: {
1.22    ! espie     219:        choose_mod['M'] = &match_mod;
        !           220:        choose_mod['N'] = &nomatch_mod;
        !           221:        choose_mod['S'] = &subst_mod;
1.7       espie     222: #ifndef MAKE_BOOTSTRAP
1.22    ! espie     223:        choose_mod['C'] = &resubst_mod;
1.7       espie     224: #endif
1.22    ! espie     225:        choose_mod['Q'] = &quote_mod;
        !           226:        choose_mod['T'] = &tail_mod;
        !           227:        choose_mod['H'] = &head_mod;
        !           228:        choose_mod['E'] = &suffix_mod;
        !           229:        choose_mod['R'] = &root_mod;
        !           230:        if (FEATURES(FEATURE_UPPERLOWER)) {
        !           231:                choose_mod['U'] = &upper_mod;
        !           232:                choose_mod['L'] = &lower_mod;
        !           233:        }
        !           234:        if (FEATURES(FEATURE_SUNSHCMD))
        !           235:                choose_mod['s'] = &shcmd_mod;
        !           236:        if (FEATURES(FEATURE_UNIQ))
        !           237:                choose_mod['u'] = &uniq_mod;
        !           238:        if (FEATURES(FEATURE_SORT))
        !           239:                choose_mod['O'] = &sort_mod;
        !           240:        if (FEATURES(FEATURE_ODE)) {
        !           241:                choose_mod['@'] = &loop_mod;
        !           242:                choose_mod['D'] = &def_mod;
        !           243:                choose_mod['U'] = &undef_mod;
        !           244:                choose_mod['L'] = &label_mod;
        !           245:                choose_mod['P'] = &path_mod;
        !           246:        }
        !           247:        if (FEATURES(FEATURE_ASSIGN))
        !           248:                choose_mod[':'] = &assign_mod;
        !           249:        if (FEATURES(FEATURE_EXECMOD))
        !           250:                choose_mod['!'] = &exec_mod;
1.1       espie     251: }
                    252:
1.7       espie     253: /* All modifiers handle addSpace (need to add a space before placing the
                    254:  * next word into the buffer) and propagate it when necessary.
1.1       espie     255:  */
                    256:
                    257: /*-
                    258:  *-----------------------------------------------------------------------
                    259:  * VarHead --
1.7       espie     260:  *     Remove the tail of the given word and add the result to the given
1.1       espie     261:  *     buffer.
                    262:  *-----------------------------------------------------------------------
                    263:  */
1.9       espie     264: static bool
1.13      espie     265: VarHead(struct Name *word, bool addSpace, Buffer buf, void *dummy UNUSED)
1.1       espie     266: {
1.22    ! espie     267:        const char      *slash;
1.1       espie     268:
1.22    ! espie     269:        slash = Str_rchri(word->s, word->e, '/');
        !           270:        if (slash != NULL) {
        !           271:                if (addSpace)
        !           272:                        Buf_AddSpace(buf);
        !           273:                Buf_Addi(buf, word->s, slash);
        !           274:        } else {
        !           275:                /* If no directory part, give . (q.v. the POSIX standard).  */
        !           276:                if (addSpace)
        !           277:                        Buf_AddString(buf, " .");
        !           278:                else
        !           279:                        Buf_AddChar(buf, '.');
        !           280:        }
        !           281:        return true;
1.1       espie     282: }
                    283:
                    284: /*-
                    285:  *-----------------------------------------------------------------------
                    286:  * VarTail --
1.7       espie     287:  *     Remove the head of the given word add the result to the given
1.1       espie     288:  *     buffer.
                    289:  *-----------------------------------------------------------------------
                    290:  */
1.9       espie     291: static bool
1.13      espie     292: VarTail(struct Name *word, bool addSpace, Buffer buf, void *dummy UNUSED)
1.1       espie     293: {
1.22    ! espie     294:        const char      *slash;
1.1       espie     295:
1.22    ! espie     296:        if (addSpace)
        !           297:                Buf_AddSpace(buf);
        !           298:        slash = Str_rchri(word->s, word->e, '/');
        !           299:        if (slash != NULL)
        !           300:                Buf_Addi(buf, slash+1, word->e);
        !           301:        else
        !           302:                Buf_Addi(buf, word->s, word->e);
        !           303:        return true;
1.1       espie     304: }
                    305:
                    306: /*-
                    307:  *-----------------------------------------------------------------------
                    308:  * VarSuffix --
1.7       espie     309:  *     Add the suffix of the given word to the given buffer.
1.1       espie     310:  *-----------------------------------------------------------------------
                    311:  */
1.9       espie     312: static bool
1.13      espie     313: VarSuffix(struct Name *word, bool addSpace, Buffer buf, void *dummy UNUSED)
1.1       espie     314: {
1.22    ! espie     315:        const char      *dot;
1.1       espie     316:
1.22    ! espie     317:        dot = Str_rchri(word->s, word->e, '.');
        !           318:        if (dot != NULL) {
        !           319:                if (addSpace)
        !           320:                        Buf_AddSpace(buf);
        !           321:                Buf_Addi(buf, dot+1, word->e);
        !           322:                addSpace = true;
        !           323:        }
        !           324:        return addSpace;
1.1       espie     325: }
                    326:
                    327: /*-
                    328:  *-----------------------------------------------------------------------
                    329:  * VarRoot --
1.7       espie     330:  *     Remove the suffix of the given word and add the result to the
1.1       espie     331:  *     buffer.
                    332:  *-----------------------------------------------------------------------
                    333:  */
1.9       espie     334: static bool
1.13      espie     335: VarRoot(struct Name *word, bool addSpace, Buffer buf, void *dummy UNUSED)
1.1       espie     336: {
1.22    ! espie     337:        const char      *dot;
1.1       espie     338:
1.22    ! espie     339:        if (addSpace)
        !           340:                Buf_AddSpace(buf);
        !           341:        dot = Str_rchri(word->s, word->e, '.');
        !           342:        if (dot != NULL)
        !           343:                Buf_Addi(buf, word->s, dot);
        !           344:        else
        !           345:                Buf_Addi(buf, word->s, word->e);
        !           346:        return true;
1.1       espie     347: }
                    348:
                    349: /*-
                    350:  *-----------------------------------------------------------------------
                    351:  * VarMatch --
1.7       espie     352:  *     Add the word to the buffer if it matches the given pattern.
1.1       espie     353:  *-----------------------------------------------------------------------
                    354:  */
1.9       espie     355: static bool
1.13      espie     356: VarMatch(struct Name *word, bool addSpace, Buffer buf,
                    357:     void *pattern) /* Pattern the word must match */
1.7       espie     358: {
1.22    ! espie     359:        const char *pat = (const char *)pattern;
1.9       espie     360:
1.22    ! espie     361:        if (Str_Matchi(word->s, word->e, pat, strchr(pat, '\0'))) {
        !           362:                if (addSpace)
        !           363:                        Buf_AddSpace(buf);
        !           364:                Buf_Addi(buf, word->s, word->e);
        !           365:                return true;
        !           366:        } else
        !           367:                return addSpace;
1.7       espie     368: }
                    369:
                    370: /*-
                    371:  *-----------------------------------------------------------------------
                    372:  * VarNoMatch --
                    373:  *     Add the word to the buffer if it doesn't match the given pattern.
                    374:  *-----------------------------------------------------------------------
                    375:  */
1.9       espie     376: static bool
1.13      espie     377: VarNoMatch(struct Name *word, bool addSpace, Buffer buf,
                    378:     void *pattern) /* Pattern the word must not match */
1.7       espie     379: {
1.22    ! espie     380:        const char *pat = (const char *)pattern;
1.9       espie     381:
1.22    ! espie     382:        if (!Str_Matchi(word->s, word->e, pat, strchr(pat, '\0'))) {
        !           383:                if (addSpace)
        !           384:                        Buf_AddSpace(buf);
        !           385:                Buf_Addi(buf, word->s, word->e);
        !           386:                return true;
        !           387:        } else
        !           388:                return addSpace;
1.7       espie     389: }
                    390:
1.9       espie     391: static bool
1.13      espie     392: VarUniq(struct Name *word, bool addSpace, Buffer buf, void *lastp)
1.1       espie     393: {
1.22    ! espie     394:        struct Name *last = (struct Name *)lastp;
1.7       espie     395:
1.22    ! espie     396:        /* does not match */
        !           397:        if (last->s == NULL || last->e - last->s != word->e - word->s ||
        !           398:            strncmp(word->s, last->s, word->e - word->s) != 0) {
        !           399:                if (addSpace)
        !           400:                        Buf_AddSpace(buf);
        !           401:                Buf_Addi(buf, word->s, word->e);
        !           402:                addSpace = true;
        !           403:        }
        !           404:        last->s = word->s;
        !           405:        last->e = word->e;
        !           406:        return addSpace;
1.1       espie     407: }
                    408:
1.9       espie     409: static bool
1.13      espie     410: VarLoop(struct Name *word, bool addSpace, Buffer buf, void *vp)
1.7       espie     411: {
1.22    ! espie     412:        struct LoopStuff *v = (struct LoopStuff *)vp;
1.7       espie     413:
1.22    ! espie     414:        if (addSpace)
        !           415:                Buf_AddSpace(buf);
        !           416:        Var_SubstVar(buf, v->expand, v->var, word->s);
        !           417:        return true;
1.7       espie     418: }
                    419:
                    420: static char *
1.13      espie     421: finish_loop(const char *s, const struct Name *n UNUSED , void *p)
1.7       espie     422: {
                    423:        struct LoopStuff *l = (struct LoopStuff *)p;
                    424:
1.15      espie     425:        return Var_Subst(s, NULL,  l->err);
1.7       espie     426: }
                    427:
                    428: static int
1.13      espie     429: NameCompare(const void *ap, const void *bp)
1.7       espie     430: {
                    431:        struct Name *a, *b;
                    432:        size_t n, m;
                    433:        int c;
                    434:
                    435:        a = (struct Name *)ap;
                    436:        b = (struct Name *)bp;
                    437:        n = a->e - a->s;
                    438:        m = b->e - b->s;
                    439:        if (n < m) {
                    440:                c = strncmp(a->s, b->s, n);
                    441:                if (c != 0)
                    442:                    return c;
                    443:                else
                    444:                    return -1;
                    445:        } else if (m < n) {
                    446:                c = strncmp(a->s, b->s, m);
                    447:                if (c != 0)
                    448:                    return c;
                    449:                else
                    450:                    return 1;
                    451:        } else
                    452:            return strncmp(a->s, b->s, n);
                    453: }
                    454:
                    455: static char *
1.13      espie     456: do_sort(const char *s, const struct Name *dummy UNUSED, void *arg UNUSED)
1.7       espie     457: {
1.22    ! espie     458:        struct Name *t;
        !           459:        unsigned long n, i, j;
        !           460:        const char *start, *end;
        !           461:
        !           462:        n = 1024;       /* start at 1024 words */
        !           463:        t = (struct Name *)emalloc(sizeof(struct Name) * n);
        !           464:        start = s;
        !           465:        end = start;
        !           466:
        !           467:        for (i = 0;; i++) {
        !           468:                if (i == n) {
        !           469:                        n *= 2;
        !           470:                        t = (struct Name *)erealloc(t, sizeof(struct Name) * n);
        !           471:                }
        !           472:                start = iterate_words(&end);
        !           473:                if (start == NULL)
        !           474:                        break;
        !           475:                t[i].s = start;
        !           476:                t[i].e = end;
        !           477:        }
        !           478:        if (i > 0) {
        !           479:                BUFFER buf;
1.7       espie     480:
1.22    ! espie     481:                Buf_Init(&buf, end - s);
        !           482:                qsort(t, i, sizeof(struct Name), NameCompare);
        !           483:                Buf_Addi(&buf, t[0].s, t[0].e);
        !           484:                for (j = 1; j < i; j++) {
        !           485:                        Buf_AddSpace(&buf);
        !           486:                        Buf_Addi(&buf, t[j].s, t[j].e);
        !           487:                }
        !           488:                free(t);
        !           489:                return Buf_Retrieve(&buf);
        !           490:        } else {
        !           491:                free(t);
        !           492:                return "";
1.7       espie     493:        }
                    494: }
                    495:
                    496: static char *
1.13      espie     497: do_label(const char *s UNUSED, const struct Name *n, void *arg UNUSED)
1.7       espie     498: {
1.22    ! espie     499:        return Str_dupi(n->s, n->e);
1.7       espie     500: }
                    501:
                    502: static char *
1.13      espie     503: do_path(const char *s UNUSED, const struct Name *n, void *arg UNUSED)
1.7       espie     504: {
1.22    ! espie     505:        GNode *gn;
1.7       espie     506:
1.22    ! espie     507:        gn = Targ_FindNodei(n->s, n->e, TARG_NOCREATE);
        !           508:        if (gn == NULL)
        !           509:                return Str_dupi(n->s, n->e);
        !           510:        else
        !           511:                return strdup(gn->path);
1.7       espie     512: }
                    513:
                    514: static char *
1.13      espie     515: do_def(const char *s, const struct Name *n UNUSED, void *arg)
1.7       espie     516: {
1.22    ! espie     517:        VarPattern *v = (VarPattern *)arg;
        !           518:        if (s == NULL) {
        !           519:                free_patternarg(v);
        !           520:                return NULL;
        !           521:        } else
        !           522:                return v->lbuffer;
1.7       espie     523: }
                    524:
                    525: static char *
1.13      espie     526: do_undef(const char *s, const struct Name *n UNUSED, void *arg)
1.7       espie     527: {
1.22    ! espie     528:        VarPattern *v = (VarPattern *)arg;
        !           529:        if (s != NULL) {
        !           530:                free_patternarg(v);
        !           531:                return NULL;
        !           532:        } else
        !           533:                return v->lbuffer;
1.7       espie     534: }
                    535:
                    536: static char *
1.13      espie     537: do_assign(const char *s, const struct Name *n, void *arg)
1.7       espie     538: {
1.22    ! espie     539:        VarPattern *v = (VarPattern *)arg;
        !           540:        char *msg;
        !           541:        char *result;
        !           542:
        !           543:        switch (v->flags) {
        !           544:        case VAR_EQUAL:
        !           545:                Var_Seti(n->s, n->e, v->lbuffer);
        !           546:                break;
        !           547:        case VAR_MAY_EQUAL:
        !           548:                if (s == NULL)
        !           549:                        Var_Seti(n->s, n->e, v->lbuffer);
        !           550:                break;
        !           551:        case VAR_ADD_EQUAL:
        !           552:                if (s == NULL)
        !           553:                        Var_Seti(n->s, n->e, v->lbuffer);
        !           554:                else
        !           555:                        Var_Appendi(n->s, n->e, v->lbuffer);
        !           556:                break;
        !           557:        case VAR_BANG_EQUAL:
        !           558:                result = Cmd_Exec(v->lbuffer, &msg);
        !           559:                if (result != NULL) {
        !           560:                        Var_Seti(n->s, n->e, result);
        !           561:                        free(result);
        !           562:                } else
        !           563:                        Error(msg, v->lbuffer);
        !           564:                break;
1.7       espie     565:
1.22    ! espie     566:        }
        !           567:        return NULL;
1.7       espie     568: }
                    569:
                    570: static char *
1.13      espie     571: do_exec(const char *s UNUSED, const struct Name *n UNUSED, void *arg)
1.7       espie     572: {
1.22    ! espie     573:        VarPattern *v = (VarPattern *)arg;
        !           574:        char *msg;
        !           575:        char *result;
        !           576:
        !           577:        result = Cmd_Exec(v->lbuffer, &msg);
        !           578:        if (result == NULL)
        !           579:                Error(msg, v->lbuffer);
        !           580:        return result;
1.7       espie     581: }
                    582:
1.1       espie     583: /*-
                    584:  *-----------------------------------------------------------------------
                    585:  * VarSYSVMatch --
1.7       espie     586:  *     Add the word to the buffer if it matches the given pattern.
                    587:  *     Used to implement the System V % modifiers.
1.1       espie     588:  *-----------------------------------------------------------------------
                    589:  */
1.9       espie     590: static bool
1.22    ! espie     591: VarSYSVMatch(struct Name *word, bool addSpace, Buffer buf, void *patp)
1.7       espie     592: {
1.22    ! espie     593:        size_t  len;
        !           594:        const char      *ptr;
        !           595:        VarPattern      *pat = (VarPattern *)patp;
1.1       espie     596:
1.22    ! espie     597:        if (*word->s != '\0') {
        !           598:                if (addSpace)
        !           599:                        Buf_AddSpace(buf);
        !           600:                if ((ptr = Str_SYSVMatch(word->s, pat->lhs, &len)) != NULL)
        !           601:                        Str_SYSVSubst(buf, pat->rhs, ptr, len);
        !           602:                else
        !           603:                        Buf_Addi(buf, word->s, word->e);
        !           604:                return true;
        !           605:        } else
        !           606:                return addSpace;
1.1       espie     607: }
                    608:
1.7       espie     609: void *
1.13      espie     610: get_sysvpattern(const char **p, SymTable *ctxt UNUSED, bool err UNUSED,
                    611:     int endc)
1.1       espie     612: {
1.22    ! espie     613:        VarPattern              *pattern;
        !           614:        const char              *cp, *cp2;
        !           615:        int cnt = 0;
        !           616:        char startc = endc == ')' ? '(' : '{';
        !           617:
        !           618:        for (cp = *p;; cp++) {
        !           619:                if (*cp == '=' && cnt == 0)
        !           620:                        break;
        !           621:                if (*cp == '\0')
        !           622:                        return NULL;
        !           623:                if (*cp == startc)
        !           624:                        cnt++;
        !           625:                else if (*cp == endc) {
        !           626:                        cnt--;
        !           627:                        if (cnt < 0)
        !           628:                                return NULL;
        !           629:                }
1.7       espie     630:        }
1.22    ! espie     631:        for (cp2 = cp+1;; cp2++) {
        !           632:                if ((*cp2 == ':' || *cp2 == endc) && cnt == 0)
        !           633:                        break;
        !           634:                if (*cp2 == '\0')
        !           635:                        return NULL;
        !           636:                if (*cp2 == startc)
        !           637:                        cnt++;
        !           638:                else if (*cp2 == endc) {
        !           639:                        cnt--;
        !           640:                        if (cnt < 0)
        !           641:                                return NULL;
        !           642:                }
1.7       espie     643:        }
1.22    ! espie     644:
        !           645:        pattern = (VarPattern *)emalloc(sizeof(VarPattern));
        !           646:        pattern->lbuffer = pattern->lhs = Str_dupi(*p, cp);
        !           647:        pattern->leftLen = cp - *p;
        !           648:        pattern->rhs = Str_dupi(cp+1, cp2);
        !           649:        pattern->rightLen = cp2 - (cp+1);
        !           650:        pattern->flags = 0;
        !           651:        *p = cp2;
        !           652:        return pattern;
1.1       espie     653: }
                    654:
                    655:
                    656: /*-
                    657:  *-----------------------------------------------------------------------
                    658:  * VarSubstitute --
1.7       espie     659:  *     Perform a string-substitution on the given word, Adding the
                    660:  *     result to the given buffer.
1.1       espie     661:  *-----------------------------------------------------------------------
                    662:  */
1.9       espie     663: static bool
1.13      espie     664: VarSubstitute(struct Name *word, bool addSpace, Buffer buf,
                    665:     void *patternp) /* Pattern for substitution */
1.7       espie     666: {
                    667:     size_t     wordLen;    /* Length of word */
                    668:     const char *cp;        /* General pointer */
                    669:     VarPattern *pattern = (VarPattern *)patternp;
1.1       espie     670:
1.7       espie     671:     wordLen = word->e - word->s;
1.1       espie     672:     if ((pattern->flags & (VAR_SUB_ONE|VAR_SUB_MATCHED)) !=
                    673:        (VAR_SUB_ONE|VAR_SUB_MATCHED)) {
1.7       espie     674:        /* Still substituting -- break it down into simple anchored cases
                    675:         * and if none of them fits, perform the general substitution case.  */
1.1       espie     676:        if ((pattern->flags & VAR_MATCH_START) &&
1.7       espie     677:            (strncmp(word->s, pattern->lhs, pattern->leftLen) == 0)) {
                    678:                /* Anchored at start and beginning of word matches pattern.  */
1.1       espie     679:                if ((pattern->flags & VAR_MATCH_END) &&
                    680:                    (wordLen == pattern->leftLen)) {
1.7       espie     681:                        /* Also anchored at end and matches to the end (word
1.1       espie     682:                         * is same length as pattern) add space and rhs only
1.7       espie     683:                         * if rhs is non-null.  */
1.1       espie     684:                        if (pattern->rightLen != 0) {
                    685:                            if (addSpace)
                    686:                                Buf_AddSpace(buf);
1.9       espie     687:                            addSpace = true;
1.7       espie     688:                            Buf_AddChars(buf, pattern->rightLen,
                    689:                                         pattern->rhs);
1.1       espie     690:                        }
                    691:                        pattern->flags |= VAR_SUB_MATCHED;
                    692:                } else if (pattern->flags & VAR_MATCH_END) {
1.7       espie     693:                    /* Doesn't match to end -- copy word wholesale.  */
1.1       espie     694:                    goto nosub;
                    695:                } else {
1.7       espie     696:                    /* Matches at start but need to copy in
                    697:                     * trailing characters.  */
1.1       espie     698:                    if ((pattern->rightLen + wordLen - pattern->leftLen) != 0){
                    699:                        if (addSpace)
                    700:                            Buf_AddSpace(buf);
1.9       espie     701:                        addSpace = true;
1.1       espie     702:                    }
                    703:                    Buf_AddChars(buf, pattern->rightLen, pattern->rhs);
                    704:                    Buf_AddChars(buf, wordLen - pattern->leftLen,
1.7       espie     705:                                 word->s + pattern->leftLen);
1.1       espie     706:                    pattern->flags |= VAR_SUB_MATCHED;
                    707:                }
                    708:        } else if (pattern->flags & VAR_MATCH_START) {
1.7       espie     709:            /* Had to match at start of word and didn't -- copy whole word.  */
1.1       espie     710:            goto nosub;
                    711:        } else if (pattern->flags & VAR_MATCH_END) {
1.7       espie     712:            /* Anchored at end, Find only place match could occur (leftLen
1.1       espie     713:             * characters from the end of the word) and see if it does. Note
                    714:             * that because the $ will be left at the end of the lhs, we have
1.7       espie     715:             * to use strncmp.  */
                    716:            cp = word->s + (wordLen - pattern->leftLen);
                    717:            if (cp >= word->s &&
                    718:                strncmp(cp, pattern->lhs, pattern->leftLen) == 0) {
                    719:                /* Match found. If we will place characters in the buffer,
1.1       espie     720:                 * add a space before hand as indicated by addSpace, then
                    721:                 * stuff in the initial, unmatched part of the word followed
1.7       espie     722:                 * by the right-hand-side.  */
                    723:                if (((cp - word->s) + pattern->rightLen) != 0) {
1.1       espie     724:                    if (addSpace)
                    725:                        Buf_AddSpace(buf);
1.9       espie     726:                    addSpace = true;
1.1       espie     727:                }
1.9       espie     728:                Buf_Addi(buf, word->s, cp);
1.1       espie     729:                Buf_AddChars(buf, pattern->rightLen, pattern->rhs);
                    730:                pattern->flags |= VAR_SUB_MATCHED;
                    731:            } else {
1.7       espie     732:                /* Had to match at end and didn't. Copy entire word.  */
1.1       espie     733:                goto nosub;
                    734:            }
                    735:        } else {
1.7       espie     736:            /* Pattern is unanchored: search for the pattern in the word using
                    737:             * strstr, copying unmatched portions and the
1.1       espie     738:             * right-hand-side for each match found, handling non-global
                    739:             * substitutions correctly, etc. When the loop is done, any
                    740:             * remaining part of the word (word and wordLen are adjusted
                    741:             * accordingly through the loop) is copied straight into the
                    742:             * buffer.
1.9       espie     743:             * addSpace is set to false as soon as a space is added to the
1.7       espie     744:             * buffer.  */
1.9       espie     745:            bool done;
1.1       espie     746:            size_t origSize;
                    747:
1.9       espie     748:            done = false;
1.1       espie     749:            origSize = Buf_Size(buf);
                    750:            while (!done) {
1.7       espie     751:                cp = strstr(word->s, pattern->lhs);
                    752:                if (cp != NULL) {
                    753:                    if (addSpace && (cp - word->s) + pattern->rightLen != 0){
1.1       espie     754:                        Buf_AddSpace(buf);
1.9       espie     755:                        addSpace = false;
1.1       espie     756:                    }
1.9       espie     757:                    Buf_Addi(buf, word->s, cp);
1.1       espie     758:                    Buf_AddChars(buf, pattern->rightLen, pattern->rhs);
1.7       espie     759:                    wordLen -= (cp - word->s) + pattern->leftLen;
                    760:                    word->s = cp + pattern->leftLen;
                    761:                    if (wordLen == 0 || (pattern->flags & VAR_SUB_GLOBAL) == 0)
1.9       espie     762:                        done = true;
1.1       espie     763:                    pattern->flags |= VAR_SUB_MATCHED;
1.7       espie     764:                } else
1.9       espie     765:                    done = true;
1.1       espie     766:            }
                    767:            if (wordLen != 0) {
                    768:                if (addSpace)
                    769:                    Buf_AddSpace(buf);
1.7       espie     770:                Buf_AddChars(buf, wordLen, word->s);
1.1       espie     771:            }
1.7       espie     772:            /* If added characters to the buffer, need to add a space
1.1       espie     773:             * before we add any more. If we didn't add any, just return
1.7       espie     774:             * the previous value of addSpace.  */
                    775:            return Buf_Size(buf) != origSize || addSpace;
1.1       espie     776:        }
1.7       espie     777:        return addSpace;
1.1       espie     778:     }
                    779:  nosub:
                    780:     if (addSpace)
                    781:        Buf_AddSpace(buf);
1.7       espie     782:     Buf_AddChars(buf, wordLen, word->s);
1.9       espie     783:     return true;
1.1       espie     784: }
                    785:
                    786: #ifndef MAKE_BOOTSTRAP
                    787: /*-
                    788:  *-----------------------------------------------------------------------
                    789:  * VarREError --
                    790:  *     Print the error caused by a regcomp or regexec call.
                    791:  *-----------------------------------------------------------------------
                    792:  */
                    793: static void
1.13      espie     794: VarREError(int err, regex_t *pat, const char *str)
1.1       espie     795: {
1.22    ! espie     796:        char    *errbuf;
        !           797:        int     errlen;
1.1       espie     798:
1.22    ! espie     799:        errlen = regerror(err, pat, 0, 0);
        !           800:        errbuf = emalloc(errlen);
        !           801:        regerror(err, pat, errbuf, errlen);
        !           802:        Error("%s: %s", str, errbuf);
        !           803:        free(errbuf);
1.1       espie     804: }
                    805:
                    806: /*-
                    807:  *-----------------------------------------------------------------------
                    808:  * VarRESubstitute --
                    809:  *     Perform a regex substitution on the given word, placing the
                    810:  *     result in the passed buffer.
                    811:  *-----------------------------------------------------------------------
                    812:  */
1.9       espie     813: static bool
1.13      espie     814: VarRESubstitute(struct Name *word, bool addSpace, Buffer buf, void *patternp)
1.7       espie     815: {
1.22    ! espie     816:        VarREPattern    *pat;
        !           817:        int             xrv;
        !           818:        const char              *wp;
        !           819:        char            *rp;
        !           820:        int             added;
1.1       espie     821:
                    822: #define MAYBE_ADD_SPACE()              \
1.7       espie     823:        if (addSpace && !added)         \
1.22    ! espie     824:                Buf_AddSpace(buf);      \
1.1       espie     825:        added = 1
                    826:
1.22    ! espie     827:        added = 0;
        !           828:        wp = word->s;
        !           829:        pat = patternp;
        !           830:
        !           831:        if ((pat->flags & (VAR_SUB_ONE|VAR_SUB_MATCHED)) ==
        !           832:            (VAR_SUB_ONE|VAR_SUB_MATCHED))
        !           833:                xrv = REG_NOMATCH;
        !           834:        else {
        !           835:        tryagain:
        !           836:                xrv = regexec(&pat->re, wp, pat->nsub, pat->matches, 0);
1.1       espie     837:        }
                    838:
1.22    ! espie     839:        switch (xrv) {
        !           840:        case 0:
        !           841:                pat->flags |= VAR_SUB_MATCHED;
        !           842:                if (pat->matches[0].rm_so > 0) {
        !           843:                        MAYBE_ADD_SPACE();
        !           844:                        Buf_AddChars(buf, pat->matches[0].rm_so, wp);
1.1       espie     845:                }
                    846:
1.22    ! espie     847:                for (rp = pat->replace; *rp; rp++) {
        !           848:                        if (*rp == '\\' && (rp[1] == '&' || rp[1] == '\\')) {
        !           849:                                MAYBE_ADD_SPACE();
        !           850:                                Buf_AddChar(buf,rp[1]);
        !           851:                                rp++;
        !           852:                        }
        !           853:                        else if (*rp == '&' ||
        !           854:                            (*rp == '\\' && isdigit(rp[1]))) {
        !           855:                                int n;
        !           856:                                const char *subbuf;
        !           857:                                int sublen;
        !           858:                                char errstr[3];
        !           859:
        !           860:                                if (*rp == '&') {
        !           861:                                        n = 0;
        !           862:                                        errstr[0] = '&';
        !           863:                                        errstr[1] = '\0';
        !           864:                                } else {
        !           865:                                        n = rp[1] - '0';
        !           866:                                        errstr[0] = '\\';
        !           867:                                        errstr[1] = rp[1];
        !           868:                                        errstr[2] = '\0';
        !           869:                                        rp++;
        !           870:                                }
        !           871:
        !           872:                                if (n > pat->nsub) {
        !           873:                                        Error("No subexpression %s",
        !           874:                                            &errstr[0]);
        !           875:                                        subbuf = "";
        !           876:                                        sublen = 0;
        !           877:                                } else if (pat->matches[n].rm_so == -1 &&
        !           878:                                    pat->matches[n].rm_eo == -1) {
        !           879:                                        Error("No match for subexpression %s",
        !           880:                                            &errstr[0]);
        !           881:                                        subbuf = "";
        !           882:                                        sublen = 0;
        !           883:                                } else {
        !           884:                                        subbuf = wp + pat->matches[n].rm_so;
        !           885:                                        sublen = pat->matches[n].rm_eo -
        !           886:                                            pat->matches[n].rm_so;
        !           887:                                }
        !           888:
        !           889:                                if (sublen > 0) {
        !           890:                                        MAYBE_ADD_SPACE();
        !           891:                                        Buf_AddChars(buf, sublen, subbuf);
        !           892:                                }
        !           893:                        } else {
        !           894:                                MAYBE_ADD_SPACE();
        !           895:                                Buf_AddChar(buf, *rp);
        !           896:                        }
        !           897:                }
        !           898:                wp += pat->matches[0].rm_eo;
        !           899:                if (pat->flags & VAR_SUB_GLOBAL)
        !           900:                        goto tryagain;
        !           901:                if (*wp) {
        !           902:                        MAYBE_ADD_SPACE();
        !           903:                        Buf_AddString(buf, wp);
1.1       espie     904:                }
1.22    ! espie     905:                break;
        !           906:        default:
        !           907:                VarREError(xrv, &pat->re, "Unexpected regex error");
        !           908:               /* fall through */
        !           909:        case REG_NOMATCH:
        !           910:                if (*wp) {
        !           911:                        MAYBE_ADD_SPACE();
        !           912:                        Buf_AddString(buf, wp);
1.1       espie     913:                }
1.22    ! espie     914:                break;
1.1       espie     915:        }
1.22    ! espie     916:        return addSpace||added;
1.1       espie     917: }
                    918: #endif
                    919:
                    920: /*-
                    921:  *-----------------------------------------------------------------------
                    922:  * VarModify --
                    923:  *     Modify each of the words of the passed string using the given
                    924:  *     function. Used to implement all modifiers.
                    925:  *
                    926:  * Results:
                    927:  *     A string of all the words modified appropriately.
                    928:  *-----------------------------------------------------------------------
                    929:  */
                    930: static char *
1.13      espie     931: VarModify(char *str,           /* String whose words should be trimmed */
1.7       espie     932:                                /* Function to use to modify them */
1.13      espie     933:     bool (*modProc)(struct Name *, bool, Buffer, void *),
                    934:     void *datum)               /* Datum to pass it */
1.1       espie     935: {
1.22    ! espie     936:        BUFFER    buf;          /* Buffer for the new string */
        !           937:        bool      addSpace;     /* true if need to add a space to the
        !           938:                                     * buffer before adding the trimmed
        !           939:                                     * word */
        !           940:        struct Name       word;
        !           941:
        !           942:        Buf_Init(&buf, 0);
        !           943:        addSpace = false;
        !           944:
        !           945:        word.e = str;
        !           946:
        !           947:        while ((word.s = iterate_words(&word.e)) != NULL) {
        !           948:                char termc;
        !           949:
        !           950:                termc = *word.e;
        !           951:                *((char *)(word.e)) = '\0';
        !           952:                addSpace = (*modProc)(&word, addSpace, &buf, datum);
        !           953:                *((char *)(word.e)) = termc;
        !           954:        }
        !           955:        return Buf_Retrieve(&buf);
1.1       espie     956: }
                    957:
                    958: /*-
                    959:  *-----------------------------------------------------------------------
                    960:  * VarGetPattern --
                    961:  *     Pass through the tstr looking for 1) escaped delimiters,
                    962:  *     '$'s and backslashes (place the escaped character in
                    963:  *     uninterpreted) and 2) unescaped $'s that aren't before
                    964:  *     the delimiter (expand the variable substitution).
                    965:  *     Return the expanded string or NULL if the delimiter was missing
                    966:  *     If pattern is specified, handle escaped ampersands, and replace
                    967:  *     unescaped ampersands with the lhs of the pattern.
                    968:  *
                    969:  * Results:
                    970:  *     A string of all the words modified appropriately.
                    971:  *     If length is specified, return the string length of the buffer
                    972:  *-----------------------------------------------------------------------
                    973:  */
                    974: static char *
1.13      espie     975: VarGetPattern(SymTable *ctxt, int err, const char **tstr, int delim1,
                    976:     int delim2, size_t *length, VarPattern *pattern)
1.1       espie     977: {
1.22    ! espie     978:        const char      *cp;
        !           979:        char    *result;
        !           980:        BUFFER  buf;
        !           981:        size_t  junk;
        !           982:
        !           983:        Buf_Init(&buf, 0);
        !           984:        if (length == NULL)
        !           985:                length = &junk;
1.1       espie     986:
1.7       espie     987: #define IS_A_MATCH(cp, delim1, delim2) \
1.22    ! espie     988:        (cp[0] == '\\' && (cp[1] == delim1 || cp[1] == delim2 || \
        !           989:         cp[1] == '\\' || cp[1] == '$' || (pattern && cp[1] == '&')))
1.1       espie     990:
1.22    ! espie     991:        /*
        !           992:         * Skim through until the matching delimiter is found;
        !           993:         * pick up variable substitutions on the way. Also allow
        !           994:         * backslashes to quote the delimiter, $, and \, but don't
        !           995:         * touch other backslashes.
        !           996:         */
        !           997:        for (cp = *tstr; *cp != '\0' && *cp != delim1 && *cp != delim2; cp++) {
        !           998:                if (IS_A_MATCH(cp, delim1, delim2)) {
        !           999:                        Buf_AddChar(&buf, cp[1]);
        !          1000:                        cp++;
        !          1001:                } else if (*cp == '$') {
        !          1002:                        /* Allowed at end of pattern */
        !          1003:                        if (cp[1] == delim1 || cp[1] == delim2)
        !          1004:                                Buf_AddChar(&buf, *cp);
        !          1005:                        else {
        !          1006:                                size_t len;
        !          1007:
        !          1008:                                /* If unescaped dollar sign not before the
        !          1009:                                 * delimiter, assume it's a variable
        !          1010:                                 * substitution and recurse.  */
        !          1011:                                (void)Var_ParseBuffer(&buf, cp, ctxt, err,
        !          1012:                                    &len);
        !          1013:                                cp += len - 1;
        !          1014:                        }
        !          1015:                } else if (pattern && *cp == '&')
        !          1016:                        Buf_AddChars(&buf, pattern->leftLen, pattern->lhs);
        !          1017:                else
        !          1018:                        Buf_AddChar(&buf, *cp);
        !          1019:        }
1.1       espie    1020:
1.22    ! espie    1021:        *length = Buf_Size(&buf);
        !          1022:        result = Buf_Retrieve(&buf);
1.7       espie    1023:
1.22    ! espie    1024:        if (*cp != delim1 && *cp != delim2) {
        !          1025:                *tstr = cp;
        !          1026:                *length = 0;
        !          1027:                free(result);
        !          1028:                return NULL;
        !          1029:        }
        !          1030:        else {
        !          1031:                *tstr = ++cp;
        !          1032:                return result;
        !          1033:        }
1.7       espie    1034: }
                   1035:
                   1036: /*-
                   1037:  *-----------------------------------------------------------------------
                   1038:  * VarQuote --
                   1039:  *     Quote shell meta-characters in the string
                   1040:  *
                   1041:  * Results:
                   1042:  *     The quoted string
                   1043:  *-----------------------------------------------------------------------
                   1044:  */
                   1045: static char *
1.13      espie    1046: VarQuote(const char *str, const struct Name *n UNUSED, void *dummy UNUSED)
1.7       espie    1047: {
                   1048:
1.22    ! espie    1049:        BUFFER    buf;
        !          1050:        /* This should cover most shells :-( */
        !          1051:        static char meta[] = "\n \t'`\";&<>()|*?{}[]\\$!#^~";
        !          1052:
        !          1053:        Buf_Init(&buf, MAKE_BSIZE);
        !          1054:        for (; *str; str++) {
        !          1055:                if (strchr(meta, *str) != NULL)
        !          1056:                        Buf_AddChar(&buf, '\\');
        !          1057:                Buf_AddChar(&buf, *str);
        !          1058:        }
        !          1059:        return Buf_Retrieve(&buf);
1.7       espie    1060: }
                   1061:
                   1062: static void *
1.13      espie    1063: check_empty(const char **p, SymTable *ctxt UNUSED, bool b UNUSED, int endc)
1.7       espie    1064: {
1.22    ! espie    1065:        dummy_arg->s = NULL;
        !          1066:        if ((*p)[1] == endc || (*p)[1] == ':') {
        !          1067:                (*p)++;
        !          1068:                return dummy_arg;
        !          1069:        } else
        !          1070:                return NULL;
1.7       espie    1071: }
                   1072:
                   1073: static void *
1.13      espie    1074: check_shcmd(const char **p, SymTable *ctxt UNUSED, bool b UNUSED, int endc)
1.7       espie    1075: {
1.22    ! espie    1076:        if ((*p)[1] == 'h' && ((*p)[2] == endc || (*p)[2] == ':')) {
        !          1077:                (*p)+=2;
        !          1078:                return dummy_arg;
        !          1079:        } else
        !          1080:                return NULL;
1.7       espie    1081: }
                   1082:
                   1083:
                   1084: static char *
1.13      espie    1085: do_shcmd(const char *s, const struct Name *n UNUSED, void *arg UNUSED)
1.7       espie    1086: {
1.22    ! espie    1087:        char *err;
        !          1088:        char *t;
1.7       espie    1089:
1.22    ! espie    1090:        t = Cmd_Exec(s, &err);
        !          1091:        if (err)
        !          1092:                Error(err, s);
        !          1093:        return t;
1.7       espie    1094: }
                   1095:
                   1096: static void *
1.13      espie    1097: get_stringarg(const char **p, SymTable *ctxt UNUSED, bool b UNUSED, int endc)
1.7       espie    1098: {
1.22    ! espie    1099:        const char *cp;
        !          1100:        char *s;
1.7       espie    1101:
1.22    ! espie    1102:        for (cp = *p + 1; *cp != ':' && *cp != endc; cp++) {
        !          1103:                if (*cp == '\\') {
        !          1104:                        if (cp[1] == ':' || cp[1] == endc || cp[1] == '\\')
        !          1105:                                cp++;
        !          1106:                } else if (*cp == '\0')
        !          1107:                        return NULL;
        !          1108:        }
        !          1109:        s = escape_dupi(*p+1, cp, ":)}");
        !          1110:        *p = cp;
        !          1111:        return s;
1.7       espie    1112: }
                   1113:
                   1114: static void
1.13      espie    1115: free_stringarg(void *arg)
1.7       espie    1116: {
1.22    ! espie    1117:        free(arg);
1.7       espie    1118: }
                   1119:
                   1120: static char *
1.13      espie    1121: do_upper(const char *s, const struct Name *n UNUSED, void *arg UNUSED)
1.7       espie    1122: {
1.22    ! espie    1123:        size_t len, i;
        !          1124:        char *t;
1.7       espie    1125:
1.22    ! espie    1126:        len = strlen(s);
        !          1127:        t = emalloc(len+1);
        !          1128:        for (i = 0; i < len; i++)
        !          1129:                t[i] = toupper(s[i]);
        !          1130:        t[len] = '\0';
        !          1131:        return t;
1.7       espie    1132: }
                   1133:
                   1134: static char *
1.13      espie    1135: do_lower(const char *s, const struct Name *n UNUSED, void *arg UNUSED)
1.7       espie    1136: {
1.22    ! espie    1137:        size_t  len, i;
        !          1138:        char    *t;
1.7       espie    1139:
1.22    ! espie    1140:        len = strlen(s);
        !          1141:        t = emalloc(len+1);
        !          1142:        for (i = 0; i < len; i++)
        !          1143:                t[i] = tolower(s[i]);
        !          1144:        t[len] = '\0';
        !          1145:        return t;
1.1       espie    1146: }
                   1147:
1.10      espie    1148: static void *
1.13      espie    1149: get_patternarg(const char **p, SymTable *ctxt, bool err, int endc)
1.10      espie    1150: {
1.22    ! espie    1151:        return common_get_patternarg(p, ctxt, err, endc, false);
1.10      espie    1152: }
                   1153:
1.7       espie    1154: /* Extract anchors */
                   1155: static void *
1.13      espie    1156: get_spatternarg(const char **p, SymTable *ctxt, bool err, int endc)
1.7       espie    1157: {
1.22    ! espie    1158:        VarPattern *pattern;
1.7       espie    1159:
1.22    ! espie    1160:        pattern = common_get_patternarg(p, ctxt, err, endc, true);
        !          1161:        if (pattern != NULL && pattern->leftLen > 0) {
        !          1162:                if (pattern->lhs[pattern->leftLen-1] == '$') {
        !          1163:                            pattern->leftLen--;
        !          1164:                            pattern->flags |= VAR_MATCH_END;
1.7       espie    1165:                }
1.22    ! espie    1166:                if (pattern->lhs[0] == '^') {
        !          1167:                            pattern->lhs++;
        !          1168:                            pattern->leftLen--;
        !          1169:                            pattern->flags |= VAR_MATCH_START;
        !          1170:                }
        !          1171:        }
        !          1172:        return pattern;
1.7       espie    1173: }
                   1174:
                   1175: static void
1.13      espie    1176: free_looparg(void *arg)
1.1       espie    1177: {
1.22    ! espie    1178:        struct LoopStuff *l = (struct LoopStuff *)arg;
1.1       espie    1179:
1.22    ! espie    1180:        Var_DeleteLoopVar(l->var);
        !          1181:        free(l->expand);
1.7       espie    1182: }
1.1       espie    1183:
1.7       espie    1184: static char *
1.13      espie    1185: LoopGrab(const char **s)
1.7       espie    1186: {
1.22    ! espie    1187:        const char *p, *start;
1.1       espie    1188:
1.22    ! espie    1189:        start = *s;
        !          1190:        for (p = start; *p != '@'; p++) {
        !          1191:                if (*p == '\\')
        !          1192:                        p++;
        !          1193:                if (*p == 0)
        !          1194:                        return NULL;
        !          1195:        }
        !          1196:        *s = p+1;
        !          1197:        return escape_dupi(start, p, "@\\");
1.7       espie    1198: }
                   1199:
                   1200: static void *
1.21      espie    1201: get_loop(const char **p, SymTable *ctxt UNUSED, bool err, int endc)
1.7       espie    1202: {
1.22    ! espie    1203:        static struct LoopStuff loop;
        !          1204:        const char *s;
        !          1205:        const char *var;
        !          1206:
        !          1207:        s = *p +1;
        !          1208:
        !          1209:        loop.var = NULL;
        !          1210:        loop.expand = NULL;
        !          1211:        loop.err = err;
        !          1212:        var = LoopGrab(&s);
        !          1213:        if (var != NULL) {
        !          1214:                loop.expand = LoopGrab(&s);
        !          1215:                if (*s == endc || *s == ':') {
        !          1216:                        *p = s;
        !          1217:                        loop.var = Var_NewLoopVar(var, NULL);
        !          1218:                        return &loop;
        !          1219:                }
1.7       espie    1220:        }
1.22    ! espie    1221:        free_looparg(&loop);
        !          1222:        return NULL;
1.7       espie    1223: }
1.1       espie    1224:
1.7       espie    1225: static void *
1.13      espie    1226: common_get_patternarg(const char **p, SymTable *ctxt, bool err, int endc,
                   1227:     bool dosubst)
1.7       espie    1228: {
1.22    ! espie    1229:        VarPattern *pattern;
        !          1230:        char delim;
        !          1231:        const char *s;
        !          1232:
        !          1233:        pattern = (VarPattern *)emalloc(sizeof(VarPattern));
        !          1234:        pattern->flags = 0;
        !          1235:        s = *p;
1.1       espie    1236:
1.22    ! espie    1237:        delim = s[1];
        !          1238:        if (delim == '\0')
        !          1239:                return NULL;
        !          1240:        s += 2;
1.1       espie    1241:
1.22    ! espie    1242:        pattern->rhs = NULL;
        !          1243:        pattern->lhs = VarGetPattern(ctxt, err, &s, delim, delim,
        !          1244:            &pattern->leftLen, NULL);
        !          1245:        pattern->lbuffer = pattern->lhs;
        !          1246:        if (pattern->lhs != NULL) {
        !          1247:                pattern->rhs = VarGetPattern(ctxt, err, &s, delim, delim,
        !          1248:                    &pattern->rightLen, dosubst ? pattern: NULL);
        !          1249:                if (pattern->rhs != NULL) {
        !          1250:                        /* Check for global substitution. If 'g' after the
        !          1251:                         * final delimiter, substitution is global and is
        !          1252:                         * marked that way.  */
        !          1253:                        for (;; s++) {
        !          1254:                                switch (*s) {
        !          1255:                                case 'g':
        !          1256:                                        pattern->flags |= VAR_SUB_GLOBAL;
        !          1257:                                        continue;
        !          1258:                                case '1':
        !          1259:                                        pattern->flags |= VAR_SUB_ONE;
        !          1260:                                        continue;
        !          1261:                                }
        !          1262:                                break;
        !          1263:                        }
        !          1264:                        if (*s == endc || *s == ':') {
        !          1265:                                *p = s;
        !          1266:                                return pattern;
        !          1267:                        }
1.1       espie    1268:                }
1.7       espie    1269:        }
1.22    ! espie    1270:        free_patternarg(pattern);
        !          1271:        return NULL;
1.7       espie    1272: }
                   1273:
                   1274: static void *
1.13      espie    1275: assign_get_value(const char **p, SymTable *ctxt, bool err, int endc)
1.7       espie    1276: {
1.22    ! espie    1277:        const char *s;
        !          1278:        int flags;
        !          1279:        VarPattern *arg;
        !          1280:
        !          1281:        s = *p + 1;
        !          1282:        if (s[0] == '=')
        !          1283:                flags = VAR_EQUAL;
        !          1284:        else if (s[0] == '?' && s[1] == '=')
        !          1285:                flags = VAR_MAY_EQUAL;
        !          1286:        else if (s[0] == '+' && s[1] == '=')
        !          1287:                flags = VAR_ADD_EQUAL;
        !          1288:        else if (s[0] == '!' && s[1] == '=')
        !          1289:                flags = VAR_BANG_EQUAL;
        !          1290:        else
        !          1291:                return NULL;
        !          1292:
        !          1293:        arg = get_value(&s, ctxt, err, endc);
        !          1294:        if (arg != NULL) {
        !          1295:                *p = s;
        !          1296:                arg->flags = flags;
        !          1297:        }
        !          1298:        return arg;
1.7       espie    1299: }
1.1       espie    1300:
1.7       espie    1301: static void *
1.13      espie    1302: get_value(const char **p, SymTable *ctxt, bool err, int endc)
1.7       espie    1303: {
1.22    ! espie    1304:        VarPattern *pattern;
        !          1305:        const char *s;
1.1       espie    1306:
1.22    ! espie    1307:        pattern = (VarPattern *)emalloc(sizeof(VarPattern));
        !          1308:        s = *p + 1;
        !          1309:        pattern->rhs = NULL;
        !          1310:        pattern->lbuffer = VarGetPattern(ctxt, err, &s, ':', endc,
        !          1311:            &pattern->leftLen, NULL);
        !          1312:        if (s[-1] == endc || s[-1] == ':') {
        !          1313:                *p = s-1;
        !          1314:                return pattern;
        !          1315:        }
        !          1316:        free_patternarg(pattern);
        !          1317:        return NULL;
1.7       espie    1318: }
1.1       espie    1319:
1.7       espie    1320: static void *
1.13      espie    1321: get_cmd(const char **p, SymTable *ctxt, bool err, int endc UNUSED)
1.7       espie    1322: {
1.22    ! espie    1323:        VarPattern *pattern;
        !          1324:        const char *s;
1.1       espie    1325:
1.22    ! espie    1326:        pattern = (VarPattern *)emalloc(sizeof(VarPattern));
        !          1327:        s = *p + 1;
        !          1328:        pattern->rhs = NULL;
        !          1329:        pattern->lbuffer = VarGetPattern(ctxt, err, &s, '!', '!',
        !          1330:            &pattern->leftLen, NULL);
        !          1331:        if (s[-1] == '!') {
        !          1332:                *p = s-1;
        !          1333:                return pattern;
        !          1334:        }
        !          1335:        free_patternarg(pattern);
        !          1336:        return NULL;
1.7       espie    1337: }
1.1       espie    1338:
1.7       espie    1339: static void
1.13      espie    1340: free_patternarg(void *p)
1.7       espie    1341: {
1.22    ! espie    1342:        VarPattern *vp = (VarPattern *)p;
1.8       espie    1343:
1.22    ! espie    1344:        free(vp->lbuffer);
        !          1345:        free(vp->rhs);
        !          1346:        free(vp);
1.1       espie    1347: }
                   1348:
1.7       espie    1349: #ifndef MAKE_BOOTSTRAP
1.1       espie    1350: static char *
1.13      espie    1351: do_regex(const char *s, const struct Name *n UNUSED, void *arg)
1.7       espie    1352: {
1.22    ! espie    1353:        VarREPattern p2;
        !          1354:        VarPattern *p = (VarPattern *)arg;
        !          1355:        int error;
        !          1356:        char *result;
        !          1357:
        !          1358:        error = regcomp(&p2.re, p->lhs, REG_EXTENDED);
        !          1359:        if (error) {
        !          1360:                VarREError(error, &p2.re, "RE substitution error");
        !          1361:                return var_Error;
        !          1362:        }
        !          1363:        p2.nsub = p2.re.re_nsub + 1;
        !          1364:        p2.replace = p->rhs;
        !          1365:        p2.flags = p->flags;
        !          1366:        if (p2.nsub < 1)
        !          1367:                p2.nsub = 1;
        !          1368:        if (p2.nsub > 10)
        !          1369:                p2.nsub = 10;
        !          1370:        p2.matches = emalloc(p2.nsub * sizeof(regmatch_t));
        !          1371:        result = VarModify((char *)s, VarRESubstitute, &p2);
        !          1372:        regfree(&p2.re);
        !          1373:        free(p2.matches);
        !          1374:        return result;
1.7       espie    1375: }
                   1376: #endif
                   1377:
                   1378: char *
1.13      espie    1379: VarModifiers_Apply(char *str, const struct Name *name, SymTable *ctxt,
1.18      espie    1380:     bool err, bool *freePtr, const char **pscan, int paren)
1.1       espie    1381: {
1.22    ! espie    1382:        const char *tstr;
        !          1383:        bool atstart;    /* Some ODE modifiers only make sense at start */
        !          1384:        char endc = paren == '(' ? ')' : '}';
        !          1385:        const char *start = *pscan;
        !          1386:
        !          1387:        tstr = start;
        !          1388:        /*
        !          1389:         * Now we need to apply any modifiers the user wants applied.
        !          1390:         * These are:
        !          1391:         *                :M<pattern>   words which match the given <pattern>.
        !          1392:         *                              <pattern> is of the standard file
        !          1393:         *                              wildcarding form.
        !          1394:         *                :S<d><pat1><d><pat2><d>[g]
        !          1395:         *                              Substitute <pat2> for <pat1> in the
        !          1396:         *                              value
        !          1397:         *                :C<d><pat1><d><pat2><d>[g]
        !          1398:         *                              Substitute <pat2> for regex <pat1> in
        !          1399:         *                              the value
        !          1400:         *                :H            Substitute the head of each word
        !          1401:         *                :T            Substitute the tail of each word
        !          1402:         *                :E            Substitute the extension (minus '.') of
        !          1403:         *                              each word
        !          1404:         *                :R            Substitute the root of each word
        !          1405:         *                              (pathname minus the suffix).
        !          1406:         *                :lhs=rhs      Like :S, but the rhs goes to the end of
        !          1407:         *                              the invocation.
        !          1408:         */
        !          1409:
        !          1410:        atstart = true;
        !          1411:        while (*tstr != endc && *tstr != '\0') {
        !          1412:                struct modifier *mod;
        !          1413:                void *arg;
        !          1414:                char *newStr;
        !          1415:
        !          1416:                tstr++;
        !          1417:                if (DEBUG(VAR))
        !          1418:                        printf("Applying :%c to \"%s\"\n", *tstr, str);
        !          1419:
        !          1420:                mod = choose_mod[*tstr];
        !          1421:                arg = NULL;
        !          1422:
        !          1423:                if (mod != NULL && (!mod->atstart || atstart))
        !          1424:                        arg = mod->getarg(&tstr, ctxt, err, endc);
        !          1425:                if (FEATURES(FEATURE_SYSVVARSUB) && arg == NULL) {
        !          1426:                        mod = &sysv_mod;
        !          1427:                        arg = mod->getarg(&tstr, ctxt, err, endc);
        !          1428:                }
        !          1429:                atstart = false;
        !          1430:                if (arg != NULL) {
        !          1431:                        if (str != NULL || (mod->atstart && name != NULL)) {
        !          1432:                                if (mod->word_apply != NULL) {
        !          1433:                                        newStr = VarModify(str,
        !          1434:                                            mod->word_apply, arg);
        !          1435:                                        if (mod->apply != NULL) {
        !          1436:                                                char *newStr2;
        !          1437:
        !          1438:                                                newStr2 = mod->apply(newStr,
        !          1439:                                                    name, arg);
        !          1440:                                                free(newStr);
        !          1441:                                                newStr = newStr2;
        !          1442:                                        }
        !          1443:                                } else
        !          1444:                                        newStr = mod->apply(str, name, arg);
        !          1445:                                if (*freePtr)
        !          1446:                                        free(str);
        !          1447:                                str = newStr;
        !          1448:                                if (str != var_Error)
        !          1449:                                        *freePtr = true;
        !          1450:                                else
        !          1451:                                        *freePtr = false;
        !          1452:                        }
        !          1453:                        if (mod->freearg != NULL)
        !          1454:                                mod->freearg(arg);
        !          1455:                } else {
        !          1456:                        Error("Bad modifier: %s\n", tstr);
        !          1457:                        /* Try skipping to end of var... */
        !          1458:                        for (tstr++; *tstr != endc && *tstr != '\0';)
        !          1459:                                tstr++;
        !          1460:                        if (str != NULL && *freePtr)
        !          1461:                                free(str);
        !          1462:                        str = var_Error;
        !          1463:                        *freePtr = false;
        !          1464:                        break;
        !          1465:                }
        !          1466:                if (DEBUG(VAR))
        !          1467:                        printf("Result is \"%s\"\n", str);
1.7       espie    1468:        }
1.22    ! espie    1469:        if (*tstr == '\0')
        !          1470:                Error("Unclosed variable specification");
        !          1471:        else
1.7       espie    1472:                tstr++;
                   1473:
1.22    ! espie    1474:        *pscan = tstr;
        !          1475:        return str;
1.1       espie    1476: }
1.7       espie    1477:
1.1       espie    1478: char *
1.13      espie    1479: Var_GetHead(char *s)
1.1       espie    1480: {
1.22    ! espie    1481:        return VarModify(s, VarHead, NULL);
1.1       espie    1482: }
                   1483:
                   1484: char *
1.13      espie    1485: Var_GetTail(char *s)
1.1       espie    1486: {
1.22    ! espie    1487:        return VarModify(s, VarTail, NULL);
1.1       espie    1488: }