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

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