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

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