Annotation of src/usr.bin/make/for.c, Revision 1.15
1.15 ! espie 1: /* $OpenBSD: for.c,v 1.14 1999/12/18 02:11:26 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.15 ! espie 85: static char rcsid[] = "$OpenBSD: for.c,v 1.14 1999/12/18 02:11:26 espie Exp $";
1.12 espie 86: #endif
87: #endif /* not lint */
1.1 deraadt 88:
89: /*
90: * For statements are of the form:
91: *
92: * .for <variable> in <varlist>
93: * ...
94: * .endfor
95: *
1.11 espie 96: * The trick is to look for the matching .end inside .for loops.
97: * To do that, we keep track of the nesting level of .for loops
98: * and matching .endfor statements, accumulating all statements between
99: * the initial .for loop and the matching .endfor,
100: * then we evaluate the .for loop for each variable in the varlist.
1.1 deraadt 101: */
102:
1.11 espie 103: /* State of a for loop. */
104: struct For_ {
105: char *text; /* unexpanded text */
106: char *var; /* Index name */
107: Lst lst; /* List of items */
1.13 espie 108: size_t guess; /* Estimated expansion size */
1.11 espie 109: BUFFER buf; /* Accumulating text */
110: unsigned long lineno; /* Line number at start of loop */
111: unsigned long level; /* Nesting level */
112: };
1.1 deraadt 113:
1.11 espie 114: static int ForExec __P((ClientData, ClientData));
1.6 espie 115: static void build_words_list __P((Lst, const char *));
1.1 deraadt 116:
1.6 espie 117: /* Cut a string into words, stuff that into list. */
118: static void
119: build_words_list(lst, s)
120: Lst lst;
121: const char *s;
122: {
123: const char *wrd;
1.1 deraadt 124:
1.6 espie 125: for (;;) {
126: for (; *s != '\0' && isspace(*s); s++)
127: continue;
128: if (*s == '\0')
129: break;
130: for (wrd = s; *s != '\0' && !isspace(*s); s++)
131: continue;
1.11 espie 132: /* note that we fill the list backward, since
133: * Parse_FromString stacks strings. */
1.15 ! espie 134: Lst_AtFront(lst, interval_dup(wrd, s));
1.6 espie 135: }
136: }
1.1 deraadt 137:
1.11 espie 138: /*
1.1 deraadt 139: *-----------------------------------------------------------------------
140: * For_Eval --
141: * Evaluate the for loop in the passed line. The line
142: * looks like this:
143: * .for <variable> in <varlist>
144: *
145: * Results:
1.11 espie 146: * Loop structure, to accumulate further lines.
147: * NULL if this was not a for loop after all.
1.1 deraadt 148: *-----------------------------------------------------------------------
149: */
1.11 espie 150:
151: For *
152: For_Eval(line)
1.1 deraadt 153: char *line; /* Line to parse */
154: {
1.11 espie 155: char *ptr = line;
156: char *wrd;
157: char *sub;
158: char *endVar;
159: For *arg;
160:
161: for (ptr++; *ptr && isspace(*ptr); ptr++)
162: continue;
163: /* If we are not in a for loop quickly determine if the statement is
164: * a for. */
165: if (ptr[0] != 'f' || ptr[1] != 'o' || ptr[2] != 'r' ||
166: !isspace(ptr[3]))
167: return NULL;
168: ptr += 4;
169:
170: while (*ptr && isspace(*ptr))
171: ptr++;
172:
173: /* We found a for loop, and now we are going to parse it. */
174:
175: /* Grab the variable. */
176: for (wrd = ptr; *ptr && !isspace(*ptr); ptr++)
177: continue;
178: if (ptr - wrd == 0) {
179: Parse_Error(PARSE_FATAL, "missing variable in for");
180: return 0;
181: }
182: endVar = ptr++;
1.1 deraadt 183:
1.11 espie 184: while (*ptr && isspace(*ptr))
185: ptr++;
1.1 deraadt 186:
1.11 espie 187: /* Grab the `in'. */
188: if (ptr[0] != 'i' || ptr[1] != 'n' ||
189: !isspace(ptr[2])) {
190: Parse_Error(PARSE_FATAL, "missing `in' in for");
191: printf("%s\n", ptr);
192: return NULL;
193: }
194: ptr += 3;
1.1 deraadt 195:
1.11 espie 196: /* .for loop is go, collate what we need. */
197: arg = emalloc(sizeof(*arg));
198: arg->var = interval_dup(wrd, endVar);
1.1 deraadt 199:
1.11 espie 200: /* Make a list with the remaining words. */
1.13 espie 201: sub = Var_Subst(ptr, VAR_GLOBAL, FALSE);
1.11 espie 202: if (DEBUG(FOR))
203: (void)fprintf(stderr, "For: Iterator %s List %s\n", arg->var, sub);
1.3 millert 204:
1.14 espie 205: arg->lst = Lst_Init();
1.11 espie 206: build_words_list(arg->lst, sub);
207: free(sub);
208: arg->lineno = Parse_Getlineno();
209: arg->level = 1;
210: Buf_Init(&arg->buf, 0);
1.1 deraadt 211:
1.11 espie 212: return arg;
213: }
1.1 deraadt 214:
1.11 espie 215:
216: /*-
217: *-----------------------------------------------------------------------
218: * For_Accumulate --
219: * Accumulate lines in a for loop, until we find the matching endfor.
220: *
221: * Results:
222: * TRUE: keep accumulating lines.
223: * FALSE: We found the matching .endfor
224: *
225: * Side Effects:
226: * Accumulate lines in arg.
227: *-----------------------------------------------------------------------
228: */
229: Boolean
230: For_Accumulate(arg, line)
231: For *arg;
232: const char *line; /* Line to parse */
233: {
234: const char *ptr = line;
1.1 deraadt 235:
1.11 espie 236: assert(arg->level > 0);
1.1 deraadt 237:
1.11 espie 238: if (*ptr == '.') {
1.1 deraadt 239:
1.11 espie 240: for (ptr++; *ptr && isspace(*ptr); ptr++)
1.1 deraadt 241: continue;
242:
243: if (strncmp(ptr, "endfor", 6) == 0 &&
1.11 espie 244: (isspace(ptr[6]) || !ptr[6])) {
1.1 deraadt 245: if (DEBUG(FOR))
1.11 espie 246: (void)fprintf(stderr, "For: end for %lu\n", arg->level);
247: /* If matching endfor, don't add line to buffer. */
248: if (--arg->level == 0)
249: return FALSE;
1.1 deraadt 250: }
251: else if (strncmp(ptr, "for", 3) == 0 &&
1.11 espie 252: isspace(ptr[3])) {
253: arg->level++;
1.1 deraadt 254: if (DEBUG(FOR))
1.11 espie 255: (void)fprintf(stderr, "For: new loop %lu\n", arg->level);
1.1 deraadt 256: }
257: }
1.11 espie 258: Buf_AddString(&arg->buf, line);
259: Buf_AddChar(&arg->buf, '\n');
260: return TRUE;
261: }
1.1 deraadt 262:
263:
1.13 espie 264: #define GUESS_EXPANSION 32
1.1 deraadt 265: /*-
266: *-----------------------------------------------------------------------
267: * ForExec --
268: * Expand the for loop for this index and push it in the Makefile
269: *-----------------------------------------------------------------------
270: */
271: static int
272: ForExec(namep, argp)
273: ClientData namep;
274: ClientData argp;
275: {
1.11 espie 276: char *name = (char *)namep;
277: For *arg = (For *)argp;
278:
1.13 espie 279: Buf_Init(&arg->buf, arg->guess);
1.1 deraadt 280: Var_Set(arg->var, name, VAR_GLOBAL);
281: if (DEBUG(FOR))
1.11 espie 282: (void)fprintf(stderr, "--- %s = %s\n", arg->var, name);
1.13 espie 283: Var_SubstVar(&arg->buf, arg->text, arg->var, VAR_GLOBAL);
284: if (Buf_Size(&arg->buf) >= arg->guess)
285: arg->guess = Buf_Size(&arg->buf) + GUESS_EXPANSION;
286:
287: Parse_FromString(Buf_Retrieve(&arg->buf), arg->lineno);
1.1 deraadt 288: Var_Delete(arg->var, VAR_GLOBAL);
289: return 0;
290: }
291:
292:
293: /*-
294: *-----------------------------------------------------------------------
295: * For_Run --
1.11 espie 296: * Run the for loop, pushing expanded lines for reparse
1.1 deraadt 297: *-----------------------------------------------------------------------
298: */
1.11 espie 299:
1.1 deraadt 300: void
1.11 espie 301: For_Run(arg)
302: For *arg;
1.1 deraadt 303: {
1.11 espie 304: arg->text = Buf_Retrieve(&arg->buf);
1.13 espie 305: arg->guess = Buf_Size(&arg->buf) + GUESS_EXPANSION;
1.1 deraadt 306:
1.15 ! espie 307: Lst_ForEach(arg->lst, ForExec, arg);
1.11 espie 308: free(arg->var);
309: free(arg->text);
310: Lst_Destroy(arg->lst, (void (*) __P((ClientData)))free);
311: free(arg);
1.1 deraadt 312: }