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

1.42    ! espie       1: /*     $OpenBSD: for.c,v 1.41 2010/07/15 10:37:32 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:
                    141:        while (isspace(*ptr))
                    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.  */
                    152:                for (wrd = ptr; *ptr && !isspace(*ptr); ptr++)
                    153:                        continue;
                    154:                if (ptr - wrd == 0) {
                    155:                        Parse_Error(PARSE_FATAL, "Syntax error in for");
                    156:                        return 0;
                    157:                }
                    158:                endVar = ptr++;
                    159:                while (isspace(*ptr))
                    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) {
                    187:                Parse_Error(PARSE_FATAL, "Wrong number of items in for loop");
                    188:                return 0;
                    189:        }
                    190:        arg->lineno = Parse_Getlineno();
                    191:        arg->level = 1;
                    192:        Buf_Init(&arg->buf, 0);
                    193:
                    194:        return arg;
1.11      espie     195: }
1.1       deraadt   196:
1.24      espie     197:
1.25      espie     198: bool
1.30      espie     199: For_Accumulate(For *arg, const char *line)
1.11      espie     200: {
1.36      espie     201:        const char *ptr = line;
1.1       deraadt   202:
1.36      espie     203:        assert(arg->level > 0);
1.1       deraadt   204:
1.36      espie     205:        if (*ptr == '.') {
1.1       deraadt   206:
1.36      espie     207:                for (ptr++; isspace(*ptr); ptr++)
                    208:                        continue;
1.1       deraadt   209:
1.36      espie     210:                if (strncmp(ptr, "endfor", 6) == 0 &&
                    211:                    (isspace(ptr[6]) || !ptr[6])) {
                    212:                        if (DEBUG(FOR))
1.39      espie     213:                                (void)fprintf(stderr, "For: end for %lu\n",
1.36      espie     214:                                    arg->level);
                    215:                        /* If matching endfor, don't add line to buffer.  */
                    216:                        if (--arg->level == 0)
                    217:                                return false;
                    218:                }
                    219:                else if (strncmp(ptr, "for", 3) == 0 &&
                    220:                     isspace(ptr[3])) {
                    221:                        arg->level++;
                    222:                        if (DEBUG(FOR))
1.39      espie     223:                                (void)fprintf(stderr, "For: new loop %lu\n",
1.36      espie     224:                                    arg->level);
                    225:                }
                    226:        }
                    227:        Buf_AddString(&arg->buf, line);
                    228:        Buf_AddChar(&arg->buf, '\n');
                    229:        return true;
1.11      espie     230: }
1.1       deraadt   231:
                    232:
1.13      espie     233: #define GUESS_EXPANSION 32
1.16      espie     234: static void
1.30      espie     235: ForExec(void *valuep, void *argp)
1.1       deraadt   236: {
1.36      espie     237:        char *value = (char *)valuep;
                    238:        For *arg = (For *)argp;
                    239:        BUFFER buf;
                    240:
                    241:        /* Parse_FromString pushes stuff back, so we need to go over vars in
                    242:           reverse.  */
                    243:        if (arg->var == NULL) {
                    244:                arg->var = Lst_Last(&arg->vars);
                    245:                arg->text = Buf_Retrieve(&arg->buf);
                    246:                arg->freeold = false;
                    247:        }
1.11      espie     248:
1.36      espie     249:        if (DEBUG(FOR))
1.39      espie     250:                (void)fprintf(stderr, "--- %s = %s\n",
1.40      espie     251:                    Var_LoopVarName(Lst_Datum(arg->var)), value);
1.36      espie     252:        Buf_Init(&buf, arg->guess);
                    253:        Var_SubstVar(&buf, arg->text, Lst_Datum(arg->var), value);
                    254:        if (arg->freeold)
                    255:                free(arg->text);
                    256:        arg->text = Buf_Retrieve(&buf);
                    257:        arg->freeold = true;
                    258:        arg->var = Lst_Rev(arg->var);
                    259:        if (arg->var == NULL)
                    260:                Parse_FromString(arg->text, arg->lineno);
1.1       deraadt   261: }
                    262:
1.11      espie     263:
1.1       deraadt   264: void
1.30      espie     265: For_Run(For *arg)
1.1       deraadt   266: {
1.36      espie     267:        arg->text = Buf_Retrieve(&arg->buf);
                    268:        arg->guess = Buf_Size(&arg->buf) + GUESS_EXPANSION;
1.1       deraadt   269:
1.36      espie     270:        arg->var = NULL;
                    271:        Lst_ForEach(&arg->lst, ForExec, arg);
                    272:        Buf_Destroy(&arg->buf);
                    273:        Lst_Destroy(&arg->vars, (SimpleProc)Var_DeleteLoopVar);
                    274:        Lst_Destroy(&arg->lst, (SimpleProc)free);
                    275:        free(arg);
1.1       deraadt   276: }