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

1.24      espie       1: /*     $OpenPackages$ */
1.32      espie       2: /*     $OpenBSD: for.c,v 1.31 2007/03/20 03:50:39 tedu Exp $   */
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))
                    179:                        (void)fprintf(stderr, "%s ", (char *)Lst_Datum(ln));
                    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))
                    213:                                (void)fprintf(stderr, "For: end for %lu\n",
                    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))
                    223:                                (void)fprintf(stderr, "For: new loop %lu\n",
                    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))
                    250:                (void)fprintf(stderr, "--- %s = %s\n",
                    251:                    (char *)Lst_Datum(arg->var), value);
                    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: }