Annotation of src/usr.bin/make/for.c, Revision 1.22
1.22 ! espie 1: /* $OpenBSD: for.c,v 1.21 2000/09/14 13:32:06 espie Exp $ */
1.3 millert 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.
43: * 3. All advertising materials mentioning features or use of this software
44: * must display the following acknowledgement:
45: * This product includes software developed by the University of
46: * California, Berkeley and its contributors.
47: * 4. Neither the name of the University nor the names of its contributors
48: * may be used to endorse or promote products derived from this software
49: * without specific prior written permission.
50: *
51: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
52: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
55: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61: * SUCH DAMAGE.
62: */
63:
64: /*-
65: * for.c --
66: * Functions to handle loops in a makefile.
67: *
68: * Interface:
1.12 espie 69: * For_Eval Evaluate the .for in the passed line
70: * For_Accumulate Add lines to an accumulating loop
1.1 deraadt 71: * For_Run Run accumulated loop
72: *
73: */
74:
75: #include <ctype.h>
1.12 espie 76: #include <assert.h>
77: #include <stddef.h>
1.1 deraadt 78: #include "make.h"
79: #include "buf.h"
1.12 espie 80:
81: #ifndef lint
82: #if 0
83: static char sccsid[] = "@(#)for.c 8.1 (Berkeley) 6/6/93";
84: #else
1.21 espie 85: UNUSED
1.22 ! espie 86: static char rcsid[] = "$OpenBSD: for.c,v 1.21 2000/09/14 13:32:06 espie Exp $";
1.12 espie 87: #endif
88: #endif /* not lint */
1.1 deraadt 89:
90: /*
91: * For statements are of the form:
92: *
93: * .for <variable> in <varlist>
94: * ...
95: * .endfor
96: *
1.11 espie 97: * The trick is to look for the matching .end inside .for loops.
98: * To do that, we keep track of the nesting level of .for loops
99: * and matching .endfor statements, accumulating all statements between
100: * the initial .for loop and the matching .endfor,
101: * then we evaluate the .for loop for each variable in the varlist.
1.1 deraadt 102: */
103:
1.11 espie 104: /* State of a for loop. */
105: struct For_ {
106: char *text; /* unexpanded text */
107: char *var; /* Index name */
1.18 espie 108: LIST lst; /* List of items */
1.13 espie 109: size_t guess; /* Estimated expansion size */
1.11 espie 110: BUFFER buf; /* Accumulating text */
111: unsigned long lineno; /* Line number at start of loop */
112: unsigned long level; /* Nesting level */
113: };
1.1 deraadt 114:
1.17 espie 115: static void ForExec __P((void *, void *));
1.6 espie 116: static void build_words_list __P((Lst, const char *));
1.1 deraadt 117:
1.6 espie 118: /* Cut a string into words, stuff that into list. */
119: static void
120: build_words_list(lst, s)
121: Lst lst;
122: const char *s;
123: {
1.22 ! espie 124: const char *end, *wrd;
1.1 deraadt 125:
1.22 ! espie 126: end = s;
! 127:
! 128: while ((wrd = iterate_words(&end)) != NULL)
! 129: Lst_AtFront(lst, escape_dup(wrd, end, "\"'"));
1.6 espie 130: }
1.1 deraadt 131:
1.11 espie 132: /*
1.1 deraadt 133: *-----------------------------------------------------------------------
134: * For_Eval --
135: * Evaluate the for loop in the passed line. The line
136: * looks like this:
137: * .for <variable> in <varlist>
138: *
139: * Results:
1.11 espie 140: * Loop structure, to accumulate further lines.
141: * NULL if this was not a for loop after all.
1.1 deraadt 142: *-----------------------------------------------------------------------
143: */
1.11 espie 144:
145: For *
146: For_Eval(line)
1.1 deraadt 147: char *line; /* Line to parse */
148: {
1.11 espie 149: char *ptr = line;
150: char *wrd;
151: char *sub;
152: char *endVar;
153: For *arg;
154:
155: for (ptr++; *ptr && isspace(*ptr); ptr++)
156: continue;
157: /* If we are not in a for loop quickly determine if the statement is
158: * a for. */
159: if (ptr[0] != 'f' || ptr[1] != 'o' || ptr[2] != 'r' ||
160: !isspace(ptr[3]))
161: return NULL;
162: ptr += 4;
163:
164: while (*ptr && isspace(*ptr))
165: ptr++;
166:
167: /* We found a for loop, and now we are going to parse it. */
168:
169: /* Grab the variable. */
170: for (wrd = ptr; *ptr && !isspace(*ptr); ptr++)
171: continue;
172: if (ptr - wrd == 0) {
173: Parse_Error(PARSE_FATAL, "missing variable in for");
174: return 0;
175: }
176: endVar = ptr++;
1.1 deraadt 177:
1.11 espie 178: while (*ptr && isspace(*ptr))
179: ptr++;
1.1 deraadt 180:
1.11 espie 181: /* Grab the `in'. */
182: if (ptr[0] != 'i' || ptr[1] != 'n' ||
183: !isspace(ptr[2])) {
184: Parse_Error(PARSE_FATAL, "missing `in' in for");
185: printf("%s\n", ptr);
186: return NULL;
187: }
188: ptr += 3;
1.1 deraadt 189:
1.11 espie 190: /* .for loop is go, collate what we need. */
191: arg = emalloc(sizeof(*arg));
192: arg->var = interval_dup(wrd, endVar);
1.1 deraadt 193:
1.11 espie 194: /* Make a list with the remaining words. */
1.20 espie 195: sub = Var_Subst(ptr, NULL, FALSE);
1.11 espie 196: if (DEBUG(FOR))
197: (void)fprintf(stderr, "For: Iterator %s List %s\n", arg->var, sub);
1.3 millert 198:
1.18 espie 199: Lst_Init(&arg->lst);
200: build_words_list(&arg->lst, sub);
1.11 espie 201: free(sub);
202: arg->lineno = Parse_Getlineno();
203: arg->level = 1;
204: Buf_Init(&arg->buf, 0);
1.1 deraadt 205:
1.11 espie 206: return arg;
207: }
1.1 deraadt 208:
1.11 espie 209:
210: /*-
211: *-----------------------------------------------------------------------
212: * For_Accumulate --
213: * Accumulate lines in a for loop, until we find the matching endfor.
214: *
215: * Results:
216: * TRUE: keep accumulating lines.
217: * FALSE: We found the matching .endfor
218: *
219: * Side Effects:
220: * Accumulate lines in arg.
221: *-----------------------------------------------------------------------
222: */
223: Boolean
224: For_Accumulate(arg, line)
225: For *arg;
226: const char *line; /* Line to parse */
227: {
228: const char *ptr = line;
1.1 deraadt 229:
1.11 espie 230: assert(arg->level > 0);
1.1 deraadt 231:
1.11 espie 232: if (*ptr == '.') {
1.1 deraadt 233:
1.11 espie 234: for (ptr++; *ptr && isspace(*ptr); ptr++)
1.1 deraadt 235: continue;
236:
237: if (strncmp(ptr, "endfor", 6) == 0 &&
1.11 espie 238: (isspace(ptr[6]) || !ptr[6])) {
1.1 deraadt 239: if (DEBUG(FOR))
1.11 espie 240: (void)fprintf(stderr, "For: end for %lu\n", arg->level);
241: /* If matching endfor, don't add line to buffer. */
242: if (--arg->level == 0)
243: return FALSE;
1.1 deraadt 244: }
245: else if (strncmp(ptr, "for", 3) == 0 &&
1.11 espie 246: isspace(ptr[3])) {
247: arg->level++;
1.1 deraadt 248: if (DEBUG(FOR))
1.11 espie 249: (void)fprintf(stderr, "For: new loop %lu\n", arg->level);
1.1 deraadt 250: }
251: }
1.11 espie 252: Buf_AddString(&arg->buf, line);
253: Buf_AddChar(&arg->buf, '\n');
254: return TRUE;
255: }
1.1 deraadt 256:
257:
1.13 espie 258: #define GUESS_EXPANSION 32
1.1 deraadt 259: /*-
260: *-----------------------------------------------------------------------
261: * ForExec --
262: * Expand the for loop for this index and push it in the Makefile
263: *-----------------------------------------------------------------------
264: */
1.16 espie 265: static void
1.1 deraadt 266: ForExec(namep, argp)
1.17 espie 267: void *namep;
268: void *argp;
1.1 deraadt 269: {
1.11 espie 270: char *name = (char *)namep;
271: For *arg = (For *)argp;
272:
1.13 espie 273: Buf_Init(&arg->buf, arg->guess);
1.1 deraadt 274: Var_Set(arg->var, name, VAR_GLOBAL);
275: if (DEBUG(FOR))
1.11 espie 276: (void)fprintf(stderr, "--- %s = %s\n", arg->var, name);
1.13 espie 277: Var_SubstVar(&arg->buf, arg->text, arg->var, VAR_GLOBAL);
278: if (Buf_Size(&arg->buf) >= arg->guess)
279: arg->guess = Buf_Size(&arg->buf) + GUESS_EXPANSION;
280:
281: Parse_FromString(Buf_Retrieve(&arg->buf), arg->lineno);
1.1 deraadt 282: Var_Delete(arg->var, VAR_GLOBAL);
283: }
284:
285:
286: /*-
287: *-----------------------------------------------------------------------
288: * For_Run --
1.11 espie 289: * Run the for loop, pushing expanded lines for reparse
1.1 deraadt 290: *-----------------------------------------------------------------------
291: */
1.11 espie 292:
1.1 deraadt 293: void
1.11 espie 294: For_Run(arg)
295: For *arg;
1.1 deraadt 296: {
1.11 espie 297: arg->text = Buf_Retrieve(&arg->buf);
1.13 espie 298: arg->guess = Buf_Size(&arg->buf) + GUESS_EXPANSION;
1.1 deraadt 299:
1.18 espie 300: Lst_ForEach(&arg->lst, ForExec, arg);
1.11 espie 301: free(arg->var);
302: free(arg->text);
1.18 espie 303: Lst_Destroy(&arg->lst, (SimpleProc)free);
1.11 espie 304: free(arg);
1.1 deraadt 305: }