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

1.7       espie       1: /*     $OpenPackages$ */
1.15      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.7       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.15      espie     115:     struct LoopVar     *var;
1.7       espie     116:     char       *expand;
1.9       espie     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 {
                    137:     regex_t      re;
1.7       espie     138:     int          nsub;
1.1       espie     139:     regmatch_t  *matches;
                    140:     char        *replace;
1.7       espie     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.9       espie     184:        bool atstart;
                    185:        void * (*getarg)(const char **, SymTable *, bool, int);
1.7       espie     186:        char * (*apply)(const char *, const struct Name *, void *);
1.9       espie     187:        bool (*word_apply)(struct Name *, bool, Buffer, void *);
1.7       espie     188:        void   (*freearg)(void *);
                    189: } *choose_mod[256],
1.9       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.9       espie     194:     resubst_mod = {false, get_patternarg, do_regex, NULL, free_patternarg},
1.1       espie     195: #endif
1.9       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.7       espie     219:     choose_mod['M'] = &match_mod;
                    220:     choose_mod['N'] = &nomatch_mod;
                    221:     choose_mod['S'] = &subst_mod;
                    222: #ifndef MAKE_BOOTSTRAP
                    223:     choose_mod['C'] = &resubst_mod;
                    224: #endif
                    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.6       espie     267:     const char *slash;
1.1       espie     268:
1.9       espie     269:     slash = Str_rchri(word->s, word->e, '/');
1.1       espie     270:     if (slash != NULL) {
                    271:        if (addSpace)
                    272:            Buf_AddSpace(buf);
1.9       espie     273:        Buf_Addi(buf, word->s, slash);
1.1       espie     274:     } else {
1.7       espie     275:        /* If no directory part, give . (q.v. the POSIX standard).  */
1.1       espie     276:        if (addSpace)
                    277:            Buf_AddString(buf, " .");
                    278:        else
                    279:            Buf_AddChar(buf, '.');
                    280:     }
1.9       espie     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.6       espie     294:     const char *slash;
1.1       espie     295:
1.7       espie     296:     if (addSpace)
1.1       espie     297:        Buf_AddSpace(buf);
1.9       espie     298:     slash = Str_rchri(word->s, word->e, '/');
1.1       espie     299:     if (slash != NULL)
1.9       espie     300:        Buf_Addi(buf, slash+1, word->e);
1.1       espie     301:     else
1.9       espie     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.6       espie     315:     const char *dot;
1.1       espie     316:
1.9       espie     317:     dot = Str_rchri(word->s, word->e, '.');
1.1       espie     318:     if (dot != NULL) {
                    319:        if (addSpace)
                    320:            Buf_AddSpace(buf);
1.9       espie     321:        Buf_Addi(buf, dot+1, word->e);
                    322:        addSpace = true;
1.1       espie     323:     }
1.6       espie     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.6       espie     337:     const char *dot;
1.1       espie     338:
                    339:     if (addSpace)
                    340:        Buf_AddSpace(buf);
1.9       espie     341:     dot = Str_rchri(word->s, word->e, '.');
1.1       espie     342:     if (dot != NULL)
1.9       espie     343:        Buf_Addi(buf, word->s, dot);
1.1       espie     344:     else
1.9       espie     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.9       espie     359:     const char *pat = (const char *)pattern;
                    360:
                    361:     if (Str_Matchi(word->s, word->e, pat, strchr(pat, '\0'))) {
1.7       espie     362:        if (addSpace)
                    363:            Buf_AddSpace(buf);
1.9       espie     364:        Buf_Addi(buf, word->s, word->e);
                    365:        return true;
1.7       espie     366:     } else
                    367:        return addSpace;
                    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.9       espie     380:     const char *pat = (const char *)pattern;
                    381:
                    382:     if (!Str_Matchi(word->s, word->e, pat, strchr(pat, '\0'))) {
1.7       espie     383:        if (addSpace)
                    384:            Buf_AddSpace(buf);
1.9       espie     385:        Buf_Addi(buf, word->s, word->e);
                    386:        return true;
1.7       espie     387:     } else
                    388:        return addSpace;
                    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.7       espie     394:     struct Name *last = (struct Name *)lastp;
                    395:
                    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) {
1.1       espie     399:        if (addSpace)
                    400:            Buf_AddSpace(buf);
1.9       espie     401:        Buf_Addi(buf, word->s, word->e);
                    402:        addSpace = true;
1.1       espie     403:     }
1.7       espie     404:     last->s = word->s;
                    405:     last->e = word->e;
1.1       espie     406:     return addSpace;
                    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: {
                    412:     struct LoopStuff *v = (struct LoopStuff *)vp;
                    413:
                    414:     if (addSpace)
                    415:        Buf_AddSpace(buf);
                    416:     Var_SubstVar(buf, v->expand, v->var, word->s);
1.9       espie     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: {
                    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;
                    480:
                    481:        Buf_Init(&buf, end - s);
                    482:        qsort(t, i, sizeof(struct Name), NameCompare);
1.9       espie     483:        Buf_Addi(&buf, t[0].s, t[0].e);
1.7       espie     484:        for (j = 1; j < i; j++) {
                    485:                Buf_AddSpace(&buf);
1.9       espie     486:                Buf_Addi(&buf, t[j].s, t[j].e);
1.7       espie     487:        }
                    488:        free(t);
                    489:        return Buf_Retrieve(&buf);
                    490:     } else {
                    491:        free(t);
                    492:        return "";
                    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.9       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: {
                    505:     GNode *gn;
                    506:
1.9       espie     507:     gn = Targ_FindNodei(n->s, n->e, TARG_NOCREATE);
1.7       espie     508:     if (gn == NULL)
1.9       espie     509:        return Str_dupi(n->s, n->e);
1.7       espie     510:     else
                    511:        return strdup(gn->path);
                    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: {
                    517:     VarPattern *v = (VarPattern *)arg;
                    518:     if (s == NULL) {
                    519:        free_patternarg(v);
                    520:        return NULL;
                    521:     } else
                    522:        return v->lbuffer;
                    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: {
                    528:     VarPattern *v = (VarPattern *)arg;
                    529:     if (s != NULL) {
                    530:        free_patternarg(v);
                    531:        return NULL;
                    532:     } else
                    533:        return v->lbuffer;
                    534: }
                    535:
                    536: static char *
1.13      espie     537: do_assign(const char *s, const struct Name *n, void *arg)
1.7       espie     538: {
                    539:     VarPattern *v = (VarPattern *)arg;
                    540:     char *msg;
                    541:     char *result;
                    542:
                    543:     switch (v->flags) {
                    544:     case VAR_EQUAL:
1.9       espie     545:        Var_Seti(n->s, n->e, v->lbuffer, VAR_GLOBAL);
1.7       espie     546:        break;
                    547:     case VAR_MAY_EQUAL:
                    548:        if (s == NULL)
1.9       espie     549:            Var_Seti(n->s, n->e, v->lbuffer, VAR_GLOBAL);
1.7       espie     550:        break;
                    551:     case VAR_ADD_EQUAL:
                    552:        if (s == NULL)
1.9       espie     553:            Var_Seti(n->s, n->e, v->lbuffer, VAR_GLOBAL);
1.7       espie     554:        else
1.9       espie     555:            Var_Appendi(n->s, n->e, v->lbuffer, VAR_GLOBAL);
1.7       espie     556:        break;
                    557:     case VAR_BANG_EQUAL:
                    558:        result = Cmd_Exec(v->lbuffer, &msg);
                    559:        if (result != NULL) {
1.9       espie     560:                Var_Seti(n->s, n->e, result, VAR_GLOBAL);
1.7       espie     561:                free(result);
                    562:        } else
                    563:                Error(msg, v->lbuffer);
                    564:        break;
                    565:
                    566:     }
                    567:     return NULL;
                    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: {
                    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;
                    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.13      espie     591: VarSYSVMatch(struct Name *word, bool addSpace, Buffer buf,
                    592:     void *patp) /* Pattern the word must match */
1.7       espie     593: {
                    594:     size_t     len;
                    595:     const char *ptr;
                    596:     VarPattern *pat = (VarPattern *)patp;
1.1       espie     597:
1.7       espie     598:     if (*word->s != '\0') {
1.1       espie     599:            if (addSpace)
                    600:                Buf_AddSpace(buf);
1.7       espie     601:            if ((ptr = Str_SYSVMatch(word->s, pat->lhs, &len)) != NULL)
1.1       espie     602:                Str_SYSVSubst(buf, pat->rhs, ptr, len);
                    603:            else
1.9       espie     604:                Buf_Addi(buf, word->s, word->e);
                    605:            return true;
1.7       espie     606:     } else
                    607:        return addSpace;
1.1       espie     608: }
                    609:
1.7       espie     610: void *
1.13      espie     611: get_sysvpattern(const char **p, SymTable *ctxt UNUSED, bool err UNUSED,
                    612:     int endc)
1.1       espie     613: {
1.8       espie     614:     VarPattern         *pattern;
1.7       espie     615:     const char         *cp, *cp2;
                    616:     int cnt = 0;
1.14      espie     617:     char startc = endc == ')' ? '(' : '{';
1.7       espie     618:
                    619:     for (cp = *p;; cp++) {
                    620:        if (*cp == '=' && cnt == 0)
                    621:            break;
                    622:        if (*cp == '\0')
                    623:            return NULL;
                    624:        if (*cp == startc)
                    625:            cnt++;
                    626:        else if (*cp == endc) {
                    627:            cnt--;
                    628:            if (cnt < 0)
                    629:                return NULL;
                    630:        }
                    631:     }
                    632:     for (cp2 = cp+1;; cp2++) {
                    633:        if ((*cp2 == ':' || *cp2 == endc) && cnt == 0)
                    634:            break;
1.14      espie     635:        if (*cp2 == '\0')
                    636:            return NULL;
1.7       espie     637:        if (*cp2 == startc)
                    638:            cnt++;
                    639:        else if (*cp2 == endc) {
                    640:            cnt--;
                    641:            if (cnt < 0)
                    642:                return NULL;
                    643:        }
1.1       espie     644:     }
1.7       espie     645:
1.8       espie     646:     pattern = (VarPattern *)emalloc(sizeof(VarPattern));
1.9       espie     647:     pattern->lbuffer = pattern->lhs = Str_dupi(*p, cp);
1.8       espie     648:     pattern->leftLen = cp - *p;
1.9       espie     649:     pattern->rhs = Str_dupi(cp+1, cp2);
1.8       espie     650:     pattern->rightLen = cp2 - (cp+1);
                    651:     pattern->flags = 0;
1.7       espie     652:     *p = cp2;
1.8       espie     653:     return pattern;
1.1       espie     654: }
                    655:
                    656:
                    657: /*-
                    658:  *-----------------------------------------------------------------------
                    659:  * VarSubstitute --
1.7       espie     660:  *     Perform a string-substitution on the given word, Adding the
                    661:  *     result to the given buffer.
1.1       espie     662:  *-----------------------------------------------------------------------
                    663:  */
1.9       espie     664: static bool
1.13      espie     665: VarSubstitute(struct Name *word, bool addSpace, Buffer buf,
                    666:     void *patternp) /* Pattern for substitution */
1.7       espie     667: {
                    668:     size_t     wordLen;    /* Length of word */
                    669:     const char *cp;        /* General pointer */
                    670:     VarPattern *pattern = (VarPattern *)patternp;
1.1       espie     671:
1.7       espie     672:     wordLen = word->e - word->s;
1.1       espie     673:     if ((pattern->flags & (VAR_SUB_ONE|VAR_SUB_MATCHED)) !=
                    674:        (VAR_SUB_ONE|VAR_SUB_MATCHED)) {
1.7       espie     675:        /* Still substituting -- break it down into simple anchored cases
                    676:         * and if none of them fits, perform the general substitution case.  */
1.1       espie     677:        if ((pattern->flags & VAR_MATCH_START) &&
1.7       espie     678:            (strncmp(word->s, pattern->lhs, pattern->leftLen) == 0)) {
                    679:                /* Anchored at start and beginning of word matches pattern.  */
1.1       espie     680:                if ((pattern->flags & VAR_MATCH_END) &&
                    681:                    (wordLen == pattern->leftLen)) {
1.7       espie     682:                        /* Also anchored at end and matches to the end (word
1.1       espie     683:                         * is same length as pattern) add space and rhs only
1.7       espie     684:                         * if rhs is non-null.  */
1.1       espie     685:                        if (pattern->rightLen != 0) {
                    686:                            if (addSpace)
                    687:                                Buf_AddSpace(buf);
1.9       espie     688:                            addSpace = true;
1.7       espie     689:                            Buf_AddChars(buf, pattern->rightLen,
                    690:                                         pattern->rhs);
1.1       espie     691:                        }
                    692:                        pattern->flags |= VAR_SUB_MATCHED;
                    693:                } else if (pattern->flags & VAR_MATCH_END) {
1.7       espie     694:                    /* Doesn't match to end -- copy word wholesale.  */
1.1       espie     695:                    goto nosub;
                    696:                } else {
1.7       espie     697:                    /* Matches at start but need to copy in
                    698:                     * trailing characters.  */
1.1       espie     699:                    if ((pattern->rightLen + wordLen - pattern->leftLen) != 0){
                    700:                        if (addSpace)
                    701:                            Buf_AddSpace(buf);
1.9       espie     702:                        addSpace = true;
1.1       espie     703:                    }
                    704:                    Buf_AddChars(buf, pattern->rightLen, pattern->rhs);
                    705:                    Buf_AddChars(buf, wordLen - pattern->leftLen,
1.7       espie     706:                                 word->s + pattern->leftLen);
1.1       espie     707:                    pattern->flags |= VAR_SUB_MATCHED;
                    708:                }
                    709:        } else if (pattern->flags & VAR_MATCH_START) {
1.7       espie     710:            /* Had to match at start of word and didn't -- copy whole word.  */
1.1       espie     711:            goto nosub;
                    712:        } else if (pattern->flags & VAR_MATCH_END) {
1.7       espie     713:            /* Anchored at end, Find only place match could occur (leftLen
1.1       espie     714:             * characters from the end of the word) and see if it does. Note
                    715:             * that because the $ will be left at the end of the lhs, we have
1.7       espie     716:             * to use strncmp.  */
                    717:            cp = word->s + (wordLen - pattern->leftLen);
                    718:            if (cp >= word->s &&
                    719:                strncmp(cp, pattern->lhs, pattern->leftLen) == 0) {
                    720:                /* Match found. If we will place characters in the buffer,
1.1       espie     721:                 * add a space before hand as indicated by addSpace, then
                    722:                 * stuff in the initial, unmatched part of the word followed
1.7       espie     723:                 * by the right-hand-side.  */
                    724:                if (((cp - word->s) + pattern->rightLen) != 0) {
1.1       espie     725:                    if (addSpace)
                    726:                        Buf_AddSpace(buf);
1.9       espie     727:                    addSpace = true;
1.1       espie     728:                }
1.9       espie     729:                Buf_Addi(buf, word->s, cp);
1.1       espie     730:                Buf_AddChars(buf, pattern->rightLen, pattern->rhs);
                    731:                pattern->flags |= VAR_SUB_MATCHED;
                    732:            } else {
1.7       espie     733:                /* Had to match at end and didn't. Copy entire word.  */
1.1       espie     734:                goto nosub;
                    735:            }
                    736:        } else {
1.7       espie     737:            /* Pattern is unanchored: search for the pattern in the word using
                    738:             * strstr, copying unmatched portions and the
1.1       espie     739:             * right-hand-side for each match found, handling non-global
                    740:             * substitutions correctly, etc. When the loop is done, any
                    741:             * remaining part of the word (word and wordLen are adjusted
                    742:             * accordingly through the loop) is copied straight into the
                    743:             * buffer.
1.9       espie     744:             * addSpace is set to false as soon as a space is added to the
1.7       espie     745:             * buffer.  */
1.9       espie     746:            bool done;
1.1       espie     747:            size_t origSize;
                    748:
1.9       espie     749:            done = false;
1.1       espie     750:            origSize = Buf_Size(buf);
                    751:            while (!done) {
1.7       espie     752:                cp = strstr(word->s, pattern->lhs);
                    753:                if (cp != NULL) {
                    754:                    if (addSpace && (cp - word->s) + pattern->rightLen != 0){
1.1       espie     755:                        Buf_AddSpace(buf);
1.9       espie     756:                        addSpace = false;
1.1       espie     757:                    }
1.9       espie     758:                    Buf_Addi(buf, word->s, cp);
1.1       espie     759:                    Buf_AddChars(buf, pattern->rightLen, pattern->rhs);
1.7       espie     760:                    wordLen -= (cp - word->s) + pattern->leftLen;
                    761:                    word->s = cp + pattern->leftLen;
                    762:                    if (wordLen == 0 || (pattern->flags & VAR_SUB_GLOBAL) == 0)
1.9       espie     763:                        done = true;
1.1       espie     764:                    pattern->flags |= VAR_SUB_MATCHED;
1.7       espie     765:                } else
1.9       espie     766:                    done = true;
1.1       espie     767:            }
                    768:            if (wordLen != 0) {
                    769:                if (addSpace)
                    770:                    Buf_AddSpace(buf);
1.7       espie     771:                Buf_AddChars(buf, wordLen, word->s);
1.1       espie     772:            }
1.7       espie     773:            /* If added characters to the buffer, need to add a space
1.1       espie     774:             * before we add any more. If we didn't add any, just return
1.7       espie     775:             * the previous value of addSpace.  */
                    776:            return Buf_Size(buf) != origSize || addSpace;
1.1       espie     777:        }
1.7       espie     778:        return addSpace;
1.1       espie     779:     }
                    780:  nosub:
                    781:     if (addSpace)
                    782:        Buf_AddSpace(buf);
1.7       espie     783:     Buf_AddChars(buf, wordLen, word->s);
1.9       espie     784:     return true;
1.1       espie     785: }
                    786:
                    787: #ifndef MAKE_BOOTSTRAP
                    788: /*-
                    789:  *-----------------------------------------------------------------------
                    790:  * VarREError --
                    791:  *     Print the error caused by a regcomp or regexec call.
                    792:  *-----------------------------------------------------------------------
                    793:  */
                    794: static void
1.13      espie     795: VarREError(int err, regex_t *pat, const char *str)
1.1       espie     796: {
1.7       espie     797:     char       *errbuf;
                    798:     int        errlen;
1.1       espie     799:
                    800:     errlen = regerror(err, pat, 0, 0);
                    801:     errbuf = emalloc(errlen);
                    802:     regerror(err, pat, errbuf, errlen);
                    803:     Error("%s: %s", str, errbuf);
                    804:     free(errbuf);
                    805: }
                    806:
                    807: /*-
                    808:  *-----------------------------------------------------------------------
                    809:  * VarRESubstitute --
                    810:  *     Perform a regex substitution on the given word, placing the
                    811:  *     result in the passed buffer.
                    812:  *-----------------------------------------------------------------------
                    813:  */
1.9       espie     814: static bool
1.13      espie     815: VarRESubstitute(struct Name *word, bool addSpace, Buffer buf, void *patternp)
1.7       espie     816: {
                    817:     VarREPattern       *pat;
                    818:     int                xrv;
                    819:     const char         *wp;
                    820:     char               *rp;
                    821:     int                added;
1.1       espie     822:
                    823: #define MAYBE_ADD_SPACE()              \
1.7       espie     824:        if (addSpace && !added)         \
1.1       espie     825:            Buf_AddSpace(buf);          \
                    826:        added = 1
                    827:
                    828:     added = 0;
1.7       espie     829:     wp = word->s;
1.1       espie     830:     pat = patternp;
                    831:
                    832:     if ((pat->flags & (VAR_SUB_ONE|VAR_SUB_MATCHED)) ==
                    833:        (VAR_SUB_ONE|VAR_SUB_MATCHED))
                    834:        xrv = REG_NOMATCH;
                    835:     else {
                    836:     tryagain:
                    837:        xrv = regexec(&pat->re, wp, pat->nsub, pat->matches, 0);
                    838:     }
                    839:
                    840:     switch (xrv) {
                    841:     case 0:
                    842:        pat->flags |= VAR_SUB_MATCHED;
                    843:        if (pat->matches[0].rm_so > 0) {
                    844:            MAYBE_ADD_SPACE();
                    845:            Buf_AddChars(buf, pat->matches[0].rm_so, wp);
                    846:        }
                    847:
                    848:        for (rp = pat->replace; *rp; rp++) {
1.7       espie     849:            if (*rp == '\\' && (rp[1] == '&' || rp[1] == '\\')) {
1.1       espie     850:                MAYBE_ADD_SPACE();
1.7       espie     851:                Buf_AddChar(buf,rp[1]);
1.1       espie     852:                rp++;
                    853:            }
1.7       espie     854:            else if (*rp == '&' || (*rp == '\\' && isdigit(rp[1]))) {
1.1       espie     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", &errstr[0]);
                    874:                    subbuf = "";
                    875:                    sublen = 0;
1.7       espie     876:                } else if (pat->matches[n].rm_so == -1 &&
                    877:                           pat->matches[n].rm_eo == -1) {
1.1       espie     878:                    Error("No match for subexpression %s", &errstr[0]);
                    879:                    subbuf = "";
                    880:                    sublen = 0;
1.7       espie     881:                } else {
1.1       espie     882:                    subbuf = wp + pat->matches[n].rm_so;
                    883:                    sublen = pat->matches[n].rm_eo - pat->matches[n].rm_so;
                    884:                }
                    885:
                    886:                if (sublen > 0) {
                    887:                    MAYBE_ADD_SPACE();
                    888:                    Buf_AddChars(buf, sublen, subbuf);
                    889:                }
                    890:            } else {
                    891:                MAYBE_ADD_SPACE();
                    892:                Buf_AddChar(buf, *rp);
                    893:            }
                    894:        }
                    895:        wp += pat->matches[0].rm_eo;
                    896:        if (pat->flags & VAR_SUB_GLOBAL)
                    897:            goto tryagain;
                    898:        if (*wp) {
                    899:            MAYBE_ADD_SPACE();
1.7       espie     900:            Buf_AddString(buf, wp);
1.1       espie     901:        }
                    902:        break;
                    903:     default:
                    904:        VarREError(xrv, &pat->re, "Unexpected regex error");
                    905:        /* fall through */
                    906:     case REG_NOMATCH:
                    907:        if (*wp) {
                    908:            MAYBE_ADD_SPACE();
1.7       espie     909:            Buf_AddString(buf, wp);
1.1       espie     910:        }
                    911:        break;
                    912:     }
1.7       espie     913:     return addSpace||added;
1.1       espie     914: }
                    915: #endif
                    916:
                    917: /*-
                    918:  *-----------------------------------------------------------------------
                    919:  * VarModify --
                    920:  *     Modify each of the words of the passed string using the given
                    921:  *     function. Used to implement all modifiers.
                    922:  *
                    923:  * Results:
                    924:  *     A string of all the words modified appropriately.
                    925:  *-----------------------------------------------------------------------
                    926:  */
                    927: static char *
1.13      espie     928: VarModify(char *str,           /* String whose words should be trimmed */
1.7       espie     929:                                /* Function to use to modify them */
1.13      espie     930:     bool (*modProc)(struct Name *, bool, Buffer, void *),
                    931:     void *datum)               /* Datum to pass it */
1.1       espie     932: {
1.7       espie     933:     BUFFER       buf;          /* Buffer for the new string */
1.9       espie     934:     bool         addSpace;     /* true if need to add a space to the
1.5       espie     935:                                 * buffer before adding the trimmed
                    936:                                 * word */
1.7       espie     937:     struct Name          word;
1.2       espie     938:
1.1       espie     939:     Buf_Init(&buf, 0);
1.9       espie     940:     addSpace = false;
1.1       espie     941:
1.7       espie     942:     word.e = str;
1.1       espie     943:
1.7       espie     944:     while ((word.s = iterate_words(&word.e)) != NULL) {
                    945:        char termc;
1.1       espie     946:
1.7       espie     947:        termc = *word.e;
                    948:        *((char *)(word.e)) = '\0';
                    949:        addSpace = (*modProc)(&word, addSpace, &buf, datum);
                    950:        *((char *)(word.e)) = termc;
1.5       espie     951:     }
1.1       espie     952:     return Buf_Retrieve(&buf);
                    953: }
                    954:
                    955: /*-
                    956:  *-----------------------------------------------------------------------
                    957:  * VarGetPattern --
                    958:  *     Pass through the tstr looking for 1) escaped delimiters,
                    959:  *     '$'s and backslashes (place the escaped character in
                    960:  *     uninterpreted) and 2) unescaped $'s that aren't before
                    961:  *     the delimiter (expand the variable substitution).
                    962:  *     Return the expanded string or NULL if the delimiter was missing
                    963:  *     If pattern is specified, handle escaped ampersands, and replace
                    964:  *     unescaped ampersands with the lhs of the pattern.
                    965:  *
                    966:  * Results:
                    967:  *     A string of all the words modified appropriately.
                    968:  *     If length is specified, return the string length of the buffer
                    969:  *-----------------------------------------------------------------------
                    970:  */
                    971: static char *
1.13      espie     972: VarGetPattern(SymTable *ctxt, int err, const char **tstr, int delim1,
                    973:     int delim2, size_t *length, VarPattern *pattern)
1.1       espie     974: {
1.7       espie     975:     const char *cp;
                    976:     char       *result;
                    977:     BUFFER     buf;
                    978:     size_t     junk;
1.1       espie     979:
                    980:     Buf_Init(&buf, 0);
                    981:     if (length == NULL)
                    982:        length = &junk;
                    983:
1.7       espie     984: #define IS_A_MATCH(cp, delim1, delim2) \
                    985:     (cp[0] == '\\' && (cp[1] == delim1 || cp[1] == delim2 || \
                    986:      cp[1] == '\\' || cp[1] == '$' || (pattern && cp[1] == '&')))
1.1       espie     987:
                    988:     /*
                    989:      * Skim through until the matching delimiter is found;
                    990:      * pick up variable substitutions on the way. Also allow
                    991:      * backslashes to quote the delimiter, $, and \, but don't
                    992:      * touch other backslashes.
                    993:      */
1.7       espie     994:     for (cp = *tstr; *cp != '\0' && *cp != delim1 && *cp != delim2; cp++) {
                    995:        if (IS_A_MATCH(cp, delim1, delim2)) {
1.1       espie     996:            Buf_AddChar(&buf, cp[1]);
                    997:            cp++;
                    998:        } else if (*cp == '$') {
1.7       espie     999:                /* Allowed at end of pattern */
                   1000:            if (cp[1] == delim1 || cp[1] == delim2)
                   1001:                Buf_AddChar(&buf, *cp);
1.1       espie    1002:            else {
1.7       espie    1003:                size_t len;
                   1004:
                   1005:                /* If unescaped dollar sign not before the delimiter,
                   1006:                 * assume it's a variable substitution and recurse.  */
                   1007:                (void)Var_ParseBuffer(&buf, cp, ctxt, err, &len);
1.1       espie    1008:                cp += len - 1;
                   1009:            }
1.7       espie    1010:        } else if (pattern && *cp == '&')
1.1       espie    1011:            Buf_AddChars(&buf, pattern->leftLen, pattern->lhs);
                   1012:        else
                   1013:            Buf_AddChar(&buf, *cp);
                   1014:     }
                   1015:
1.7       espie    1016:     *length = Buf_Size(&buf);
                   1017:     result = Buf_Retrieve(&buf);
                   1018:
                   1019:     if (*cp != delim1 && *cp != delim2) {
1.1       espie    1020:        *tstr = cp;
                   1021:        *length = 0;
1.7       espie    1022:        free(result);
1.1       espie    1023:        return NULL;
                   1024:     }
                   1025:     else {
                   1026:        *tstr = ++cp;
1.7       espie    1027:        return result;
                   1028:     }
                   1029: }
                   1030:
                   1031: /*-
                   1032:  *-----------------------------------------------------------------------
                   1033:  * VarQuote --
                   1034:  *     Quote shell meta-characters in the string
                   1035:  *
                   1036:  * Results:
                   1037:  *     The quoted string
                   1038:  *-----------------------------------------------------------------------
                   1039:  */
                   1040: static char *
1.13      espie    1041: VarQuote(const char *str, const struct Name *n UNUSED, void *dummy UNUSED)
1.7       espie    1042: {
                   1043:
                   1044:     BUFFER       buf;
                   1045:     /* This should cover most shells :-( */
                   1046:     static char meta[] = "\n \t'`\";&<>()|*?{}[]\\$!#^~";
                   1047:
                   1048:     Buf_Init(&buf, MAKE_BSIZE);
                   1049:     for (; *str; str++) {
                   1050:        if (strchr(meta, *str) != NULL)
                   1051:            Buf_AddChar(&buf, '\\');
                   1052:        Buf_AddChar(&buf, *str);
                   1053:     }
                   1054:     return Buf_Retrieve(&buf);
                   1055: }
                   1056:
                   1057: static void *
1.13      espie    1058: check_empty(const char **p, SymTable *ctxt UNUSED, bool b UNUSED, int endc)
1.7       espie    1059: {
                   1060:     dummy_arg->s = NULL;
                   1061:     if ((*p)[1] == endc || (*p)[1] == ':') {
                   1062:        (*p)++;
                   1063:        return dummy_arg;
                   1064:     } else
                   1065:        return NULL;
                   1066: }
                   1067:
                   1068: static void *
1.13      espie    1069: check_shcmd(const char **p, SymTable *ctxt UNUSED, bool b UNUSED, int endc)
1.7       espie    1070: {
                   1071:     if ((*p)[1] == 'h' && ((*p)[2] == endc || (*p)[2] == ':')) {
                   1072:        (*p)+=2;
                   1073:        return dummy_arg;
                   1074:     } else
                   1075:        return NULL;
                   1076: }
                   1077:
                   1078:
                   1079: static char *
1.13      espie    1080: do_shcmd(const char *s, const struct Name *n UNUSED, void *arg UNUSED)
1.7       espie    1081: {
                   1082:     char       *err;
                   1083:     char       *t;
                   1084:
                   1085:     t = Cmd_Exec(s, &err);
                   1086:     if (err)
                   1087:        Error(err, s);
                   1088:     return t;
                   1089: }
                   1090:
                   1091: static void *
1.13      espie    1092: get_stringarg(const char **p, SymTable *ctxt UNUSED, bool b UNUSED, int endc)
1.7       espie    1093: {
                   1094:     const char *cp;
                   1095:     char       *s;
                   1096:
                   1097:     for (cp = *p + 1; *cp != ':' && *cp != endc; cp++) {
                   1098:        if (*cp == '\\') {
                   1099:            if (cp[1] == ':' || cp[1] == endc || cp[1] == '\\')
                   1100:                cp++;
                   1101:        } else if (*cp == '\0')
                   1102:            return NULL;
1.1       espie    1103:     }
1.9       espie    1104:     s = escape_dupi(*p+1, cp, ":)}");
1.7       espie    1105:     *p = cp;
                   1106:     return s;
                   1107: }
                   1108:
                   1109: static void
1.13      espie    1110: free_stringarg(void *arg)
1.7       espie    1111: {
                   1112:     free(arg);
                   1113: }
                   1114:
                   1115: static char *
1.13      espie    1116: do_upper(const char *s, const struct Name *n UNUSED, void *arg UNUSED)
1.7       espie    1117: {
                   1118:     size_t     len, i;
                   1119:     char       *t;
                   1120:
                   1121:     len = strlen(s);
                   1122:     t = emalloc(len+1);
                   1123:     for (i = 0; i < len; i++)
                   1124:        t[i] = toupper(s[i]);
                   1125:     t[len] = '\0';
                   1126:     return t;
                   1127: }
                   1128:
                   1129: static char *
1.13      espie    1130: do_lower(const char *s, const struct Name *n UNUSED, void *arg UNUSED)
1.7       espie    1131: {
                   1132:     size_t     len, i;
                   1133:     char       *t;
                   1134:
                   1135:     len = strlen(s);
                   1136:     t = emalloc(len+1);
                   1137:     for (i = 0; i < len; i++)
                   1138:        t[i] = tolower(s[i]);
                   1139:     t[len] = '\0';
                   1140:     return t;
1.1       espie    1141: }
                   1142:
1.10      espie    1143: static void *
1.13      espie    1144: get_patternarg(const char **p, SymTable *ctxt, bool err, int endc)
1.10      espie    1145: {
                   1146:     return common_get_patternarg(p, ctxt, err, endc, false);
                   1147: }
                   1148:
1.7       espie    1149: /* Extract anchors */
                   1150: static void *
1.13      espie    1151: get_spatternarg(const char **p, SymTable *ctxt, bool err, int endc)
1.7       espie    1152: {
                   1153:     VarPattern *pattern;
                   1154:
1.10      espie    1155:     pattern = common_get_patternarg(p, ctxt, err, endc, true);
1.7       espie    1156:     if (pattern != NULL && pattern->leftLen > 0) {
                   1157:        if (pattern->lhs[pattern->leftLen-1] == '$') {
                   1158:                pattern->leftLen--;
                   1159:                pattern->flags |= VAR_MATCH_END;
                   1160:        }
                   1161:        if (pattern->lhs[0] == '^') {
                   1162:                pattern->lhs++;
                   1163:                pattern->leftLen--;
                   1164:                pattern->flags |= VAR_MATCH_START;
                   1165:                }
                   1166:     }
                   1167:     return pattern;
                   1168: }
                   1169:
                   1170: static void
1.13      espie    1171: free_looparg(void *arg)
1.1       espie    1172: {
1.7       espie    1173:     struct LoopStuff *l = (struct LoopStuff *)arg;
1.1       espie    1174:
1.15      espie    1175:     Var_DeleteLoopVar(l->var);
1.7       espie    1176:     free(l->expand);
                   1177: }
1.1       espie    1178:
1.7       espie    1179: static char *
1.13      espie    1180: LoopGrab(const char **s)
1.7       espie    1181: {
                   1182:     const char *p, *start;
1.1       espie    1183:
1.7       espie    1184:     start = *s;
                   1185:     for (p = start; *p != '@'; p++) {
                   1186:        if (*p == '\\')
                   1187:            p++;
                   1188:        if (*p == 0)
                   1189:                return NULL;
                   1190:     }
                   1191:     *s = p+1;
1.9       espie    1192:     return escape_dupi(start, p, "@\\");
1.7       espie    1193: }
                   1194:
                   1195: static void *
1.13      espie    1196: get_loop(const char **p, SymTable *ctxt, bool err, int endc)
1.7       espie    1197: {
                   1198:     static struct LoopStuff    loop;
                   1199:     const char *s;
1.15      espie    1200:     const char *var;
1.1       espie    1201:
1.7       espie    1202:     s = *p +1;
1.1       espie    1203:
1.7       espie    1204:     loop.var = NULL;
                   1205:     loop.expand = NULL;
                   1206:     loop.err = err;
1.15      espie    1207:     var = LoopGrab(&s);
                   1208:     if (var != NULL) {
1.7       espie    1209:        loop.expand = LoopGrab(&s);
                   1210:        if (*s == endc || *s == ':') {
                   1211:            *p = s;
1.15      espie    1212:            loop.var = Var_NewLoopVar(var, NULL);
1.7       espie    1213:            return &loop;
                   1214:        }
                   1215:     }
                   1216:     free_looparg(&loop);
                   1217:     return NULL;
                   1218: }
1.1       espie    1219:
1.7       espie    1220: static void *
1.13      espie    1221: common_get_patternarg(const char **p, SymTable *ctxt, bool err, int endc,
                   1222:     bool dosubst)
1.7       espie    1223: {
1.8       espie    1224:     VarPattern *pattern;
1.7       espie    1225:     char       delim;
                   1226:     const char *s;
1.1       espie    1227:
1.8       espie    1228:     pattern = (VarPattern *)emalloc(sizeof(VarPattern));
                   1229:     pattern->flags = 0;
1.7       espie    1230:     s = *p;
1.1       espie    1231:
1.7       espie    1232:     delim = s[1];
                   1233:     if (delim == '\0')
                   1234:        return NULL;
                   1235:     s += 2;
1.1       espie    1236:
1.8       espie    1237:     pattern->rhs = NULL;
                   1238:     pattern->lhs = VarGetPattern(ctxt, err, &s, delim, delim,
                   1239:        &pattern->leftLen, NULL);
                   1240:     pattern->lbuffer = pattern->lhs;
                   1241:     if (pattern->lhs != NULL) {
                   1242:        pattern->rhs = VarGetPattern(ctxt, err, &s, delim, delim,
1.10      espie    1243:            &pattern->rightLen, dosubst ? pattern: NULL);
1.8       espie    1244:        if (pattern->rhs != NULL) {
1.7       espie    1245:            /* Check for global substitution. If 'g' after the final
                   1246:             * delimiter, substitution is global and is marked that
                   1247:             * way.  */
                   1248:            for (;; s++) {
                   1249:                switch (*s) {
                   1250:                case 'g':
1.8       espie    1251:                    pattern->flags |= VAR_SUB_GLOBAL;
1.7       espie    1252:                    continue;
                   1253:                case '1':
1.8       espie    1254:                    pattern->flags |= VAR_SUB_ONE;
1.7       espie    1255:                    continue;
1.1       espie    1256:                }
                   1257:                break;
                   1258:            }
1.7       espie    1259:            if (*s == endc || *s == ':') {
                   1260:                *p = s;
1.8       espie    1261:                return pattern;
1.7       espie    1262:            }
                   1263:        }
                   1264:     }
1.8       espie    1265:     free_patternarg(pattern);
1.7       espie    1266:     return NULL;
                   1267: }
                   1268:
                   1269: static void *
1.13      espie    1270: assign_get_value(const char **p, SymTable *ctxt, bool err, int endc)
1.7       espie    1271: {
                   1272:     const char *s;
                   1273:     int flags;
                   1274:     VarPattern *arg;
                   1275:
                   1276:     s = *p + 1;
                   1277:     if (s[0] == '=')
                   1278:        flags = VAR_EQUAL;
                   1279:     else if (s[0] == '?' && s[1] == '=')
                   1280:        flags = VAR_MAY_EQUAL;
                   1281:     else if (s[0] == '+' && s[1] == '=')
                   1282:        flags = VAR_ADD_EQUAL;
                   1283:     else if (s[0] == '!' && s[1] == '=')
                   1284:        flags = VAR_BANG_EQUAL;
                   1285:     else
                   1286:        return NULL;
1.1       espie    1287:
1.7       espie    1288:     arg = get_value(&s, ctxt, err, endc);
                   1289:     if (arg != NULL) {
                   1290:        *p = s;
                   1291:        arg->flags = flags;
                   1292:     }
                   1293:     return arg;
                   1294: }
1.1       espie    1295:
1.7       espie    1296: static void *
1.13      espie    1297: get_value(const char **p, SymTable *ctxt, bool err, int endc)
1.7       espie    1298: {
1.8       espie    1299:     VarPattern *pattern;
1.7       espie    1300:     const char *s;
1.1       espie    1301:
1.8       espie    1302:     pattern = (VarPattern *)emalloc(sizeof(VarPattern));
1.7       espie    1303:     s = *p + 1;
1.8       espie    1304:     pattern->rhs = NULL;
                   1305:     pattern->lbuffer = VarGetPattern(ctxt, err, &s, ':', endc,
                   1306:        &pattern->leftLen, NULL);
1.7       espie    1307:     if (s[-1] == endc || s[-1] == ':') {
                   1308:        *p = s-1;
1.8       espie    1309:        return pattern;
1.7       espie    1310:     }
1.8       espie    1311:     free_patternarg(pattern);
1.7       espie    1312:     return NULL;
                   1313: }
1.1       espie    1314:
1.7       espie    1315: static void *
1.13      espie    1316: get_cmd(const char **p, SymTable *ctxt, bool err, int endc UNUSED)
1.7       espie    1317: {
1.8       espie    1318:     VarPattern *pattern;
1.7       espie    1319:     const char *s;
1.1       espie    1320:
1.8       espie    1321:     pattern = (VarPattern *)emalloc(sizeof(VarPattern));
1.7       espie    1322:     s = *p + 1;
1.8       espie    1323:     pattern->rhs = NULL;
                   1324:     pattern->lbuffer = VarGetPattern(ctxt, err, &s, '!', '!',
                   1325:        &pattern->leftLen, NULL);
1.7       espie    1326:     if (s[-1] == '!') {
                   1327:        *p = s-1;
1.8       espie    1328:        return pattern;
1.1       espie    1329:     }
1.8       espie    1330:     free_patternarg(pattern);
1.7       espie    1331:     return NULL;
                   1332: }
1.1       espie    1333:
1.7       espie    1334: static void
1.13      espie    1335: free_patternarg(void *p)
1.7       espie    1336: {
                   1337:     VarPattern *vp = (VarPattern *)p;
1.8       espie    1338:
1.7       espie    1339:     free(vp->lbuffer);
                   1340:     free(vp->rhs);
1.8       espie    1341:     free(vp);
1.1       espie    1342: }
                   1343:
1.7       espie    1344: #ifndef MAKE_BOOTSTRAP
1.1       espie    1345: static char *
1.13      espie    1346: do_regex(const char *s, const struct Name *n UNUSED, void *arg)
1.7       espie    1347: {
                   1348:     VarREPattern p2;
                   1349:     VarPattern *p = (VarPattern *)arg;
                   1350:     int        error;
                   1351:     char       *result;
                   1352:
                   1353:     error = regcomp(&p2.re, p->lhs, REG_EXTENDED);
                   1354:     if (error) {
                   1355:        VarREError(error, &p2.re, "RE substitution error");
                   1356:        return var_Error;
                   1357:     }
                   1358:     p2.nsub = p2.re.re_nsub + 1;
                   1359:     p2.replace = p->rhs;
                   1360:     p2.flags = p->flags;
                   1361:     if (p2.nsub < 1)
                   1362:        p2.nsub = 1;
                   1363:     if (p2.nsub > 10)
                   1364:        p2.nsub = 10;
                   1365:     p2.matches = emalloc(p2.nsub * sizeof(regmatch_t));
                   1366:     result = VarModify((char *)s, VarRESubstitute, &p2);
                   1367:     regfree(&p2.re);
                   1368:     free(p2.matches);
                   1369:     return result;
                   1370: }
                   1371: #endif
                   1372:
                   1373: char *
1.13      espie    1374: VarModifiers_Apply(char *str, const struct Name *name, SymTable *ctxt,
1.15      espie    1375:     bool err, bool *freePtr, const char *start, int paren, size_t *lengthPtr)
1.1       espie    1376: {
1.7       espie    1377:     const char *tstr;
1.9       espie    1378:     bool       atstart;    /* Some ODE modifiers only make sense at start */
1.15      espie    1379:     char endc = paren == '(' ? ')' : '}';
1.1       espie    1380:
1.7       espie    1381:     tstr = start;
                   1382:     /*
                   1383:      * Now we need to apply any modifiers the user wants applied.
                   1384:      * These are:
                   1385:      *           :M<pattern>   words which match the given <pattern>.
                   1386:      *                         <pattern> is of the standard file
                   1387:      *                         wildcarding form.
                   1388:      *           :S<d><pat1><d><pat2><d>[g]
                   1389:      *                         Substitute <pat2> for <pat1> in the value
                   1390:      *           :C<d><pat1><d><pat2><d>[g]
                   1391:      *                         Substitute <pat2> for regex <pat1> in the value
                   1392:      *           :H            Substitute the head of each word
                   1393:      *           :T            Substitute the tail of each word
                   1394:      *           :E            Substitute the extension (minus '.') of
                   1395:      *                         each word
                   1396:      *           :R            Substitute the root of each word
                   1397:      *                         (pathname minus the suffix).
                   1398:      *           :lhs=rhs      Like :S, but the rhs goes to the end of
                   1399:      *                         the invocation.
                   1400:      */
                   1401:
1.9       espie    1402:     atstart = true;
1.7       espie    1403:     while (*tstr != endc && *tstr != '\0') {
                   1404:        struct modifier *mod;
                   1405:        void            *arg;
                   1406:        char            *newStr;
                   1407:
                   1408:        tstr++;
                   1409:        if (DEBUG(VAR))
                   1410:            printf("Applying :%c to \"%s\"\n", *tstr, str);
1.2       espie    1411:
1.7       espie    1412:        mod = choose_mod[*tstr];
                   1413:        arg = NULL;
1.1       espie    1414:
1.7       espie    1415:        if (mod != NULL && (!mod->atstart || atstart))
                   1416:            arg = mod->getarg(&tstr, ctxt, err, endc);
                   1417:        if (FEATURES(FEATURE_SYSVVARSUB) && arg == NULL) {
                   1418:            mod = &sysv_mod;
                   1419:            arg = mod->getarg(&tstr, ctxt, err, endc);
                   1420:        }
1.9       espie    1421:        atstart = false;
1.7       espie    1422:        if (arg != NULL) {
                   1423:            if (str != NULL || (mod->atstart && name != NULL)) {
                   1424:                if (mod->word_apply != NULL) {
                   1425:                    newStr = VarModify(str, mod->word_apply, arg);
                   1426:                    if (mod->apply != NULL) {
                   1427:                        char *newStr2;
                   1428:
                   1429:                        newStr2 = mod->apply(newStr, name, arg);
                   1430:                        free(newStr);
                   1431:                        newStr = newStr2;
                   1432:                    }
                   1433:                } else
                   1434:                    newStr = mod->apply(str, name, arg);
                   1435:                if (*freePtr)
                   1436:                    free(str);
                   1437:                str = newStr;
                   1438:                if (str != var_Error)
1.9       espie    1439:                    *freePtr = true;
1.7       espie    1440:                else
1.9       espie    1441:                    *freePtr = false;
1.7       espie    1442:            }
                   1443:            if (mod->freearg != NULL)
                   1444:                mod->freearg(arg);
                   1445:        } else {
                   1446:            Error("Bad modifier: %s\n", tstr);
                   1447:            /* Try skipping to end of var... */
                   1448:            for (tstr++; *tstr != endc && *tstr != '\0';)
                   1449:                tstr++;
                   1450:            if (str != NULL && *freePtr)
                   1451:                free(str);
                   1452:            str = var_Error;
1.12      fgsch    1453:            *freePtr = false;
1.7       espie    1454:            break;
                   1455:        }
                   1456:        if (DEBUG(VAR))
                   1457:            printf("Result is \"%s\"\n", str);
1.1       espie    1458:     }
1.14      espie    1459:     if (*tstr == '\0') {
1.7       espie    1460:        Error("Unclosed variable specification");
1.14      espie    1461:        /* make tstr point at the last char of the variable specification */
                   1462:        tstr--;
                   1463:     }
1.7       espie    1464:
                   1465:     *lengthPtr += tstr - start;
                   1466:     return str;
1.1       espie    1467: }
1.7       espie    1468:
1.1       espie    1469: char *
1.13      espie    1470: Var_GetHead(char *s)
1.1       espie    1471: {
1.7       espie    1472:     return VarModify(s, VarHead, NULL);
1.1       espie    1473: }
                   1474:
                   1475: char *
1.13      espie    1476: Var_GetTail(char *s)
1.1       espie    1477: {
1.7       espie    1478:     return VarModify(s, VarTail, NULL);
1.1       espie    1479: }