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

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