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: }