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

Annotation of src/usr.bin/make/for.c, Revision 1.45

1.45    ! espie       1: /*     $OpenBSD: for.c,v 1.44 2013/11/01 17:54:37 espie Exp $  */
1.24      espie       2: /*     $NetBSD: for.c,v 1.4 1996/11/06 17:59:05 christos Exp $ */
1.1       deraadt     3:
                      4: /*
1.6       espie       5:  * Copyright (c) 1999 Marc Espie.
                      6:  *
                      7:  * Extensive code modifications for the OpenBSD project.
                      8:  *
                      9:  * Redistribution and use in source and binary forms, with or without
                     10:  * modification, are permitted provided that the following conditions
                     11:  * are met:
                     12:  * 1. Redistributions of source code must retain the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer.
                     14:  * 2. Redistributions in binary form must reproduce the above copyright
                     15:  *    notice, this list of conditions and the following disclaimer in the
                     16:  *    documentation and/or other materials provided with the distribution.
                     17:  *
                     18:  * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS
                     19:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
                     20:  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
                     21:  * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OPENBSD
                     22:  * PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
                     23:  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
                     24:  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     25:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                     26:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     27:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
                     28:  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     29:  */
                     30:
                     31: /*
1.1       deraadt    32:  * Copyright (c) 1992, The Regents of the University of California.
                     33:  * All rights reserved.
                     34:  *
                     35:  * Redistribution and use in source and binary forms, with or without
                     36:  * modification, are permitted provided that the following conditions
                     37:  * are met:
                     38:  * 1. Redistributions of source code must retain the above copyright
                     39:  *    notice, this list of conditions and the following disclaimer.
                     40:  * 2. Redistributions in binary form must reproduce the above copyright
                     41:  *    notice, this list of conditions and the following disclaimer in the
                     42:  *    documentation and/or other materials provided with the distribution.
1.29      millert    43:  * 3. Neither the name of the University nor the names of its contributors
1.1       deraadt    44:  *    may be used to endorse or promote products derived from this software
                     45:  *    without specific prior written permission.
                     46:  *
                     47:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     48:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     49:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     50:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     51:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     52:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     53:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     54:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     55:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     56:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     57:  * SUCH DAMAGE.
                     58:  */
                     59:
1.25      espie      60: #include <assert.h>
                     61: #include <ctype.h>
                     62: #include <stddef.h>
                     63: #include <stdio.h>
1.26      espie      64: #include <stdlib.h>
1.25      espie      65: #include <string.h>
                     66: #include "config.h"
                     67: #include "defines.h"
                     68: #include "buf.h"
                     69: #include "for.h"
                     70: #include "lst.h"
                     71: #include "error.h"
                     72: #include "var.h"
                     73: #include "lowparse.h"
                     74: #include "str.h"
                     75: #include "memory.h"
1.1       deraadt    76:
                     77: /*
                     78:  * For statements are of the form:
                     79:  *
1.24      espie      80:  * .for <variable> [variable...] in <varlist>
1.1       deraadt    81:  * ...
                     82:  * .endfor
                     83:  *
1.11      espie      84:  * The trick is to look for the matching .end inside .for loops.
                     85:  * To do that, we keep track of the nesting level of .for loops
                     86:  * and matching .endfor statements, accumulating all statements between
                     87:  * the initial .for loop and the matching .endfor,
                     88:  * then we evaluate the .for loop for each variable in the varlist.
1.1       deraadt    89:  */
                     90:
1.11      espie      91: /* State of a for loop.  */
                     92: struct For_ {
1.36      espie      93:        char            *text;          /* Unexpanded text              */
                     94:        LIST            vars;           /* List of variables            */
                     95:        LstNode         var;            /* Current var                  */
                     96:        int             nvars;          /* Total number of vars         */
                     97:        LIST            lst;            /* List of items                */
                     98:        size_t          guess;          /* Estimated expansion size     */
                     99:        BUFFER          buf;            /* Accumulating text            */
                    100:        unsigned long   lineno;         /* Line number at start of loop */
                    101:        unsigned long   level;          /* Nesting level                */
                    102:        bool            freeold;
1.11      espie     103: };
1.1       deraadt   104:
1.25      espie     105: /* ForExec(value, handle);
                    106:  *     Expands next variable in loop sequence described by handle to value. */
1.24      espie     107: static void ForExec(void *, void *);
1.25      espie     108:
                    109: /* n = build_words_list(lst, s);
                    110:  *     Cuts string into words, pushes words into list, in reverse order,
                    111:  *     because Parse_FromString works as a stack.
                    112:  *     Returns the number of words.  */
1.24      espie     113: static unsigned long build_words_list(Lst, const char *);
1.1       deraadt   114:
1.24      espie     115: static unsigned long
1.30      espie     116: build_words_list(Lst lst, const char *s)
1.6       espie     117: {
1.36      espie     118:        const char *end, *wrd;
                    119:        unsigned long n;
1.1       deraadt   120:
1.36      espie     121:        n = 0;
                    122:        end = s;
1.22      espie     123:
1.36      espie     124:        while ((wrd = iterate_words(&end)) != NULL) {
                    125:                Lst_AtFront(lst, escape_dupi(wrd, end, "\"'"));
                    126:                n++;
                    127:        }
                    128:        return n;
1.6       espie     129: }
1.1       deraadt   130:
1.11      espie     131: For *
1.30      espie     132: For_Eval(const char *line)
1.1       deraadt   133: {
1.36      espie     134:        const char      *ptr = line;
                    135:        const char      *wrd;
                    136:        char    *sub;
                    137:        const char      *endVar;
                    138:        For     *arg;
                    139:        unsigned long n;
                    140:
1.45    ! espie     141:        while (ISSPACE(*ptr))
1.36      espie     142:                ptr++;
                    143:
                    144:        /* Parse loop.  */
                    145:
                    146:        arg = emalloc(sizeof(*arg));
                    147:        arg->nvars = 0;
                    148:        Lst_Init(&arg->vars);
                    149:
                    150:        for (;;) {
                    151:                /* Grab the variables.  */
1.45    ! espie     152:                for (wrd = ptr; *ptr && !ISSPACE(*ptr); ptr++)
1.36      espie     153:                        continue;
                    154:                if (ptr - wrd == 0) {
                    155:                        Parse_Error(PARSE_FATAL, "Syntax error in for");
                    156:                        return 0;
                    157:                }
                    158:                endVar = ptr++;
1.45    ! espie     159:                while (ISSPACE(*ptr))
1.36      espie     160:                        ptr++;
                    161:                /* End of variable list ? */
                    162:                if (endVar - wrd == 2 && wrd[0] == 'i' && wrd[1] == 'n')
                    163:                        break;
                    164:                Lst_AtEnd(&arg->vars, Var_NewLoopVar(wrd, endVar));
                    165:                arg->nvars++;
                    166:        }
                    167:        if (arg->nvars == 0) {
                    168:                Parse_Error(PARSE_FATAL, "Missing variable in for");
                    169:                return 0;
                    170:        }
                    171:
                    172:        /* Make a list with the remaining words.  */
                    173:        sub = Var_Subst(ptr, NULL, false);
                    174:        if (DEBUG(FOR)) {
                    175:                LstNode ln;
                    176:                (void)fprintf(stderr, "For: Iterator ");
                    177:                for (ln = Lst_First(&arg->vars); ln != NULL; ln = Lst_Adv(ln))
1.41      espie     178:                        (void)fprintf(stderr, "%s ",
1.40      espie     179:                            Var_LoopVarName(Lst_Datum(ln)));
1.36      espie     180:                (void)fprintf(stderr, "List %s\n", sub);
1.24      espie     181:        }
1.1       deraadt   182:
1.36      espie     183:        Lst_Init(&arg->lst);
                    184:        n = build_words_list(&arg->lst, sub);
                    185:        free(sub);
                    186:        if (arg->nvars != 1 && n % arg->nvars != 0) {
1.43      espie     187:                LstNode ln;
1.44      espie     188:
1.36      espie     189:                Parse_Error(PARSE_FATAL, "Wrong number of items in for loop");
1.43      espie     190:                (void)fprintf(stderr, "%lu items for %d variables:",
                    191:                    n, arg->nvars);
1.44      espie     192:                for (ln = Lst_First(&arg->lst); ln != NULL; ln = Lst_Adv(ln)) {
                    193:                        char *p = Lst_Datum(ln);
                    194:
                    195:                        (void)fprintf(stderr, " %s", p);
                    196:                }
1.43      espie     197:                (void)fprintf(stderr, "\n");
1.36      espie     198:                return 0;
                    199:        }
                    200:        arg->lineno = Parse_Getlineno();
                    201:        arg->level = 1;
                    202:        Buf_Init(&arg->buf, 0);
                    203:
                    204:        return arg;
1.11      espie     205: }
1.1       deraadt   206:
1.24      espie     207:
1.25      espie     208: bool
1.30      espie     209: For_Accumulate(For *arg, const char *line)
1.11      espie     210: {
1.36      espie     211:        const char *ptr = line;
1.1       deraadt   212:
1.36      espie     213:        assert(arg->level > 0);
1.1       deraadt   214:
1.36      espie     215:        if (*ptr == '.') {
1.1       deraadt   216:
1.45    ! espie     217:                for (ptr++; ISSPACE(*ptr); ptr++)
1.36      espie     218:                        continue;
1.1       deraadt   219:
1.36      espie     220:                if (strncmp(ptr, "endfor", 6) == 0 &&
1.45    ! espie     221:                    (ISSPACE(ptr[6]) || !ptr[6])) {
1.36      espie     222:                        if (DEBUG(FOR))
1.39      espie     223:                                (void)fprintf(stderr, "For: end for %lu\n",
1.36      espie     224:                                    arg->level);
                    225:                        /* If matching endfor, don't add line to buffer.  */
                    226:                        if (--arg->level == 0)
                    227:                                return false;
                    228:                }
                    229:                else if (strncmp(ptr, "for", 3) == 0 &&
1.45    ! espie     230:                     ISSPACE(ptr[3])) {
1.36      espie     231:                        arg->level++;
                    232:                        if (DEBUG(FOR))
1.39      espie     233:                                (void)fprintf(stderr, "For: new loop %lu\n",
1.36      espie     234:                                    arg->level);
                    235:                }
                    236:        }
                    237:        Buf_AddString(&arg->buf, line);
                    238:        Buf_AddChar(&arg->buf, '\n');
                    239:        return true;
1.11      espie     240: }
1.1       deraadt   241:
                    242:
1.13      espie     243: #define GUESS_EXPANSION 32
1.16      espie     244: static void
1.30      espie     245: ForExec(void *valuep, void *argp)
1.1       deraadt   246: {
1.36      espie     247:        char *value = (char *)valuep;
                    248:        For *arg = (For *)argp;
                    249:        BUFFER buf;
                    250:
                    251:        /* Parse_FromString pushes stuff back, so we need to go over vars in
                    252:           reverse.  */
                    253:        if (arg->var == NULL) {
                    254:                arg->var = Lst_Last(&arg->vars);
                    255:                arg->text = Buf_Retrieve(&arg->buf);
                    256:                arg->freeold = false;
                    257:        }
1.11      espie     258:
1.36      espie     259:        if (DEBUG(FOR))
1.39      espie     260:                (void)fprintf(stderr, "--- %s = %s\n",
1.40      espie     261:                    Var_LoopVarName(Lst_Datum(arg->var)), value);
1.36      espie     262:        Buf_Init(&buf, arg->guess);
                    263:        Var_SubstVar(&buf, arg->text, Lst_Datum(arg->var), value);
                    264:        if (arg->freeold)
                    265:                free(arg->text);
                    266:        arg->text = Buf_Retrieve(&buf);
                    267:        arg->freeold = true;
                    268:        arg->var = Lst_Rev(arg->var);
                    269:        if (arg->var == NULL)
                    270:                Parse_FromString(arg->text, arg->lineno);
1.1       deraadt   271: }
                    272:
1.11      espie     273:
1.1       deraadt   274: void
1.30      espie     275: For_Run(For *arg)
1.1       deraadt   276: {
1.36      espie     277:        arg->text = Buf_Retrieve(&arg->buf);
                    278:        arg->guess = Buf_Size(&arg->buf) + GUESS_EXPANSION;
1.1       deraadt   279:
1.36      espie     280:        arg->var = NULL;
                    281:        Lst_ForEach(&arg->lst, ForExec, arg);
                    282:        Buf_Destroy(&arg->buf);
                    283:        Lst_Destroy(&arg->vars, (SimpleProc)Var_DeleteLoopVar);
                    284:        Lst_Destroy(&arg->lst, (SimpleProc)free);
                    285:        free(arg);
1.1       deraadt   286: }