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

1.24      espie       1: /*     $OpenPackages$ */
                      2: /*     $OpenBSD: for.c,v 1.4 1998/12/05 00:06:27 espie Exp $   */
                      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>
        !            69: #include <string.h>
        !            70: #include "config.h"
        !            71: #include "defines.h"
        !            72: #include "buf.h"
        !            73: #include "for.h"
        !            74: #include "lst.h"
        !            75: #include "error.h"
        !            76: #include "var.h"
        !            77: #include "lowparse.h"
        !            78: #include "str.h"
        !            79: #include "memory.h"
1.1       deraadt    80:
                     81: /*
                     82:  * For statements are of the form:
                     83:  *
1.24      espie      84:  * .for <variable> [variable...] in <varlist>
1.1       deraadt    85:  * ...
                     86:  * .endfor
                     87:  *
1.11      espie      88:  * The trick is to look for the matching .end inside .for loops.
                     89:  * To do that, we keep track of the nesting level of .for loops
                     90:  * and matching .endfor statements, accumulating all statements between
                     91:  * the initial .for loop and the matching .endfor,
                     92:  * then we evaluate the .for loop for each variable in the varlist.
1.1       deraadt    93:  */
                     94:
1.11      espie      95: /* State of a for loop.  */
                     96: struct For_ {
1.25    ! espie      97:     char               *text;          /* Unexpanded text              */
        !            98:     LIST               vars;           /* List of variables            */
        !            99:     LstNode            var;            /* Current var                  */
        !           100:     int                        nvars;          /* Total number of vars         */
1.24      espie     101:     LIST               lst;            /* List of items                */
1.13      espie     102:     size_t             guess;          /* Estimated expansion size     */
1.24      espie     103:     BUFFER             buf;            /* Accumulating text            */
                    104:     unsigned long      lineno;         /* Line number at start of loop */
1.11      espie     105:     unsigned long      level;          /* Nesting level                */
1.25    ! espie     106:     bool               freeold;
1.11      espie     107: };
1.1       deraadt   108:
1.25    ! espie     109: /* ForExec(value, handle);
        !           110:  *     Expands next variable in loop sequence described by handle to value. */
1.24      espie     111: static void ForExec(void *, void *);
1.25    ! espie     112:
        !           113: /* n = build_words_list(lst, s);
        !           114:  *     Cuts string into words, pushes words into list, in reverse order,
        !           115:  *     because Parse_FromString works as a stack.
        !           116:  *     Returns the number of words.  */
1.24      espie     117: static unsigned long build_words_list(Lst, const char *);
1.1       deraadt   118:
1.24      espie     119: static unsigned long
1.6       espie     120: build_words_list(lst, s)
                    121:     Lst lst;
                    122:     const char *s;
                    123: {
1.22      espie     124:     const char *end, *wrd;
1.24      espie     125:     unsigned long n;
1.1       deraadt   126:
1.24      espie     127:     n = 0;
1.22      espie     128:     end = s;
                    129:
1.24      espie     130:     while ((wrd = iterate_words(&end)) != NULL) {
1.25    ! espie     131:        Lst_AtFront(lst, escape_dupi(wrd, end, "\"'"));
1.24      espie     132:        n++;
                    133:     }
                    134:     return n;
1.6       espie     135: }
1.1       deraadt   136:
1.11      espie     137: For *
                    138: For_Eval(line)
1.24      espie     139:     const char     *line;    /* Line to parse */
1.1       deraadt   140: {
1.24      espie     141:     const char *ptr = line;
                    142:     const char *wrd;
                    143:     char       *sub;
                    144:     const char *endVar;
1.11      espie     145:     For        *arg;
1.24      espie     146:     unsigned long n;
1.11      espie     147:
                    148:     /* If we are not in a for loop quickly determine if the statement is
                    149:      * a for.  */
                    150:     if (ptr[0] != 'f' || ptr[1] != 'o' || ptr[2] != 'r' ||
                    151:        !isspace(ptr[3]))
                    152:        return NULL;
                    153:     ptr += 4;
                    154:
                    155:     while (*ptr && isspace(*ptr))
                    156:        ptr++;
                    157:
                    158:     /* We found a for loop, and now we are going to parse it.  */
                    159:
1.24      espie     160:     arg = emalloc(sizeof(*arg));
                    161:     arg->nvars = 0;
                    162:     Lst_Init(&arg->vars);
                    163:
                    164:     for (;;) {
                    165:        /* Grab the variables.  */
                    166:        for (wrd = ptr; *ptr && !isspace(*ptr); ptr++)
                    167:            continue;
                    168:        if (ptr - wrd == 0) {
                    169:            Parse_Error(PARSE_FATAL, "Syntax error in for");
                    170:            return 0;
                    171:        }
                    172:        endVar = ptr++;
                    173:        while (*ptr && isspace(*ptr))
                    174:            ptr++;
1.25    ! espie     175:        /* End of variable list ? */
1.24      espie     176:        if (endVar - wrd == 2 && wrd[0] == 'i' && wrd[1] == 'n')
                    177:            break;
1.25    ! espie     178:        Lst_AtEnd(&arg->vars, Str_dupi(wrd, endVar));
1.24      espie     179:        arg->nvars++;
                    180:     }
                    181:     if (arg->nvars == 0) {
                    182:        Parse_Error(PARSE_FATAL, "Missing variable in for");
1.11      espie     183:        return 0;
                    184:     }
1.1       deraadt   185:
1.11      espie     186:     /* Make a list with the remaining words.  */
1.25    ! espie     187:     sub = Var_Subst(ptr, NULL, false);
1.24      espie     188:     if (DEBUG(FOR)) {
                    189:        LstNode ln;
                    190:        (void)fprintf(stderr, "For: Iterator ");
                    191:        for (ln = Lst_First(&arg->vars); ln != NULL; ln = Lst_Adv(ln))
                    192:                (void)fprintf(stderr, "%s ", (char *)Lst_Datum(ln));
                    193:        (void)fprintf(stderr, "List %s\n", sub);
                    194:     }
1.3       millert   195:
1.18      espie     196:     Lst_Init(&arg->lst);
1.24      espie     197:     n = build_words_list(&arg->lst, sub);
1.11      espie     198:     free(sub);
1.24      espie     199:     if (arg->nvars != 1 && n % arg->nvars != 0) {
                    200:        Parse_Error(PARSE_FATAL, "Wrong number of items in for loop");
                    201:        return 0;
                    202:     }
1.11      espie     203:     arg->lineno = Parse_Getlineno();
                    204:     arg->level = 1;
                    205:     Buf_Init(&arg->buf, 0);
1.1       deraadt   206:
1.11      espie     207:     return arg;
                    208: }
1.1       deraadt   209:
1.24      espie     210:
1.25    ! espie     211: bool
1.11      espie     212: For_Accumulate(arg, line)
1.24      espie     213:     For            *arg;
                    214:     const char     *line;    /* Line to parse */
1.11      espie     215: {
                    216:     const char     *ptr = line;
1.1       deraadt   217:
1.11      espie     218:     assert(arg->level > 0);
1.1       deraadt   219:
1.11      espie     220:     if (*ptr == '.') {
1.1       deraadt   221:
1.11      espie     222:        for (ptr++; *ptr && isspace(*ptr); ptr++)
1.1       deraadt   223:            continue;
                    224:
                    225:        if (strncmp(ptr, "endfor", 6) == 0 &&
1.11      espie     226:            (isspace(ptr[6]) || !ptr[6])) {
1.1       deraadt   227:            if (DEBUG(FOR))
1.11      espie     228:                (void)fprintf(stderr, "For: end for %lu\n", arg->level);
                    229:            /* If matching endfor, don't add line to buffer.  */
                    230:            if (--arg->level == 0)
1.25    ! espie     231:                return false;
1.1       deraadt   232:        }
                    233:        else if (strncmp(ptr, "for", 3) == 0 &&
1.11      espie     234:                 isspace(ptr[3])) {
                    235:            arg->level++;
1.1       deraadt   236:            if (DEBUG(FOR))
1.11      espie     237:                (void)fprintf(stderr, "For: new loop %lu\n", arg->level);
1.1       deraadt   238:        }
                    239:     }
1.11      espie     240:     Buf_AddString(&arg->buf, line);
                    241:     Buf_AddChar(&arg->buf, '\n');
1.25    ! espie     242:     return true;
1.11      espie     243: }
1.1       deraadt   244:
                    245:
1.13      espie     246: #define GUESS_EXPANSION 32
1.16      espie     247: static void
1.25    ! espie     248: ForExec(valuep, argp)
        !           249:     void *valuep;
1.17      espie     250:     void *argp;
1.1       deraadt   251: {
1.25    ! espie     252:     char *value = (char *)valuep;
1.11      espie     253:     For *arg = (For *)argp;
1.24      espie     254:     BUFFER buf;
                    255:
                    256:     /* Parse_FromString pushes stuff back, so we need to go over vars in
                    257:        reverse.  */
                    258:     if (arg->var == NULL) {
                    259:        arg->var = Lst_Last(&arg->vars);
                    260:        arg->text = Buf_Retrieve(&arg->buf);
1.25    ! espie     261:        arg->freeold = false;
1.24      espie     262:     }
1.11      espie     263:
1.1       deraadt   264:     if (DEBUG(FOR))
1.25    ! espie     265:        (void)fprintf(stderr, "--- %s = %s\n", (char *)Lst_Datum(arg->var),
        !           266:            value);
1.24      espie     267:     Buf_Init(&buf, arg->guess);
1.25    ! espie     268:     Var_SubstVar(&buf, arg->text, Lst_Datum(arg->var), value);
1.24      espie     269:     if (arg->freeold)
                    270:        free(arg->text);
                    271:     arg->text = Buf_Retrieve(&buf);
1.25    ! espie     272:     arg->freeold = true;
1.24      espie     273:     arg->var = Lst_Rev(arg->var);
                    274:     if (arg->var == NULL)
                    275:        Parse_FromString(arg->text, arg->lineno);
1.1       deraadt   276: }
                    277:
1.11      espie     278:
1.1       deraadt   279: void
1.11      espie     280: For_Run(arg)
                    281:     For *arg;
1.1       deraadt   282: {
1.11      espie     283:     arg->text = Buf_Retrieve(&arg->buf);
1.13      espie     284:     arg->guess = Buf_Size(&arg->buf) + GUESS_EXPANSION;
1.1       deraadt   285:
1.24      espie     286:     arg->var = NULL;
1.18      espie     287:     Lst_ForEach(&arg->lst, ForExec, arg);
1.24      espie     288:     Buf_Destroy(&arg->buf);
                    289:     Lst_Destroy(&arg->vars, (SimpleProc)free);
1.18      espie     290:     Lst_Destroy(&arg->lst, (SimpleProc)free);
1.11      espie     291:     free(arg);
1.1       deraadt   292: }