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

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