Annotation of src/usr.bin/make/for.c, Revision 1.8
1.8 ! espie 1: /* $OpenBSD: for.c,v 1.7 1999/12/06 22:24:31 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: #ifndef lint
65: #if 0
1.3 millert 66: static char sccsid[] = "@(#)for.c 8.1 (Berkeley) 6/6/93";
1.1 deraadt 67: #else
1.8 ! espie 68: static char rcsid[] = "$OpenBSD: for.c,v 1.7 1999/12/06 22:24:31 espie Exp $";
1.1 deraadt 69: #endif
70: #endif /* not lint */
71:
72: /*-
73: * for.c --
74: * Functions to handle loops in a makefile.
75: *
76: * Interface:
77: * For_Eval Evaluate the loop in the passed line.
78: * For_Run Run accumulated loop
79: *
80: */
81:
82: #include <ctype.h>
83: #include "make.h"
84: #include "hash.h"
85: #include "dir.h"
86: #include "buf.h"
87:
88: /*
89: * For statements are of the form:
90: *
91: * .for <variable> in <varlist>
92: * ...
93: * .endfor
94: *
95: * The trick is to look for the matching end inside for for loop
96: * To do that, we count the current nesting level of the for loops.
97: * and the .endfor statements, accumulating all the statements between
1.3 millert 98: * the initial .for loop and the matching .endfor;
1.1 deraadt 99: * then we evaluate the for loop for each variable in the varlist.
100: */
101:
1.5 espie 102: static int forLevel = 0; /* Nesting level */
103: static char *forVar; /* Iteration variable */
104: static Buffer forBuf; /* Commands in loop */
105: static Lst forLst; /* List of items */
106: static unsigned long forLineno; /* Line at beginning of loop */
1.1 deraadt 107:
108: /*
109: * State of a for loop.
110: */
111: typedef struct _For {
1.5 espie 112: Buffer buf; /* Unexpanded buffer */
113: char* var; /* Index name */
114: Lst lst; /* List of variables */
115: unsigned long lineno;
1.1 deraadt 116: } For;
117:
118: static int ForExec __P((ClientData, ClientData));
1.6 espie 119: static void build_words_list __P((Lst, const char *));
1.1 deraadt 120:
1.6 espie 121: /* Cut a string into words, stuff that into list. */
122: static void
123: build_words_list(lst, s)
124: Lst lst;
125: const char *s;
126: {
127: const char *wrd;
1.1 deraadt 128:
1.6 espie 129: for (;;) {
130: for (; *s != '\0' && isspace(*s); s++)
131: continue;
132: if (*s == '\0')
133: break;
134: for (wrd = s; *s != '\0' && !isspace(*s); s++)
135: continue;
136: /* note that we fill the list backward, since
137: * Parse_FromString stacks strings. */
138: Lst_AtFront(lst, (ClientData)interval_dup(wrd, s));
139: }
140: }
1.1 deraadt 141:
142:
143: /*-
144: *-----------------------------------------------------------------------
145: * For_Eval --
146: * Evaluate the for loop in the passed line. The line
147: * looks like this:
148: * .for <variable> in <varlist>
149: *
150: * Results:
151: * TRUE: We found a for loop, or we are inside a for loop
152: * FALSE: We did not find a for loop, or we found the end of the for
153: * for loop.
154: *
155: * Side Effects:
156: * None.
157: *
158: *-----------------------------------------------------------------------
159: */
160: int
161: For_Eval (line)
162: char *line; /* Line to parse */
163: {
1.6 espie 164: char *ptr = line;
1.1 deraadt 165: int level; /* Level at which to report errors. */
166:
167: level = PARSE_FATAL;
168:
169:
170: if (forLevel == 0) {
1.6 espie 171: char *endVar;
172: char *sub;
173: char *wrd;
1.1 deraadt 174:
175: for (ptr++; *ptr && isspace((unsigned char) *ptr); ptr++)
176: continue;
1.6 espie 177: /* If we are not in a for loop quickly determine if the statement is
178: * a for. */
1.1 deraadt 179: if (ptr[0] != 'f' || ptr[1] != 'o' || ptr[2] != 'r' ||
180: !isspace((unsigned char) ptr[3]))
181: return FALSE;
182: ptr += 3;
1.3 millert 183:
1.6 espie 184: /* We found a for loop, and now we are going to parse it. */
1.1 deraadt 185: while (*ptr && isspace((unsigned char) *ptr))
186: ptr++;
1.3 millert 187:
1.6 espie 188: /* Grab the variable. */
1.3 millert 189: for (wrd = ptr; *ptr && !isspace((unsigned char) *ptr); ptr++)
1.1 deraadt 190: continue;
191:
1.6 espie 192: if (ptr - wrd == 0) {
193: Parse_Error(level, "missing variable in for");
1.1 deraadt 194: return 0;
195: }
1.6 espie 196: endVar = ptr++;
1.1 deraadt 197:
198: while (*ptr && isspace((unsigned char) *ptr))
199: ptr++;
200:
1.6 espie 201: /* Grab the `in'. */
1.1 deraadt 202: if (ptr[0] != 'i' || ptr[1] != 'n' ||
203: !isspace((unsigned char) ptr[2])) {
1.6 espie 204: Parse_Error(level, "missing `in' in for");
1.1 deraadt 205: printf("%s\n", ptr);
206: return 0;
207: }
208: ptr += 3;
209:
1.6 espie 210: /* .for loop is go, collate what we need. */
211: forVar = interval_dup(wrd, endVar);
1.1 deraadt 212:
1.6 espie 213: /* Make a list with the remaining words. */
1.3 millert 214: sub = Var_Subst(NULL, ptr, VAR_GLOBAL, FALSE);
1.1 deraadt 215: if (DEBUG(FOR))
1.6 espie 216: (void)fprintf(stderr, "For: Iterator %s List %s\n", forVar, sub);
1.3 millert 217:
1.6 espie 218: forLst = Lst_Init(FALSE);
219: build_words_list(forLst, sub);
220: free(sub);
221: forLineno = Parse_Getlineno();
1.1 deraadt 222: forBuf = Buf_Init(0);
223: forLevel++;
224: return 1;
225: }
226: else if (*ptr == '.') {
227:
228: for (ptr++; *ptr && isspace((unsigned char) *ptr); ptr++)
229: continue;
230:
231: if (strncmp(ptr, "endfor", 6) == 0 &&
232: (isspace((unsigned char) ptr[6]) || !ptr[6])) {
233: if (DEBUG(FOR))
234: (void) fprintf(stderr, "For: end for %d\n", forLevel);
235: if (--forLevel < 0) {
1.6 espie 236: Parse_Error(level, "for-less endfor");
1.1 deraadt 237: return 0;
238: }
239: }
240: else if (strncmp(ptr, "for", 3) == 0 &&
241: isspace((unsigned char) ptr[3])) {
242: forLevel++;
243: if (DEBUG(FOR))
244: (void) fprintf(stderr, "For: new loop %d\n", forLevel);
245: }
246: }
247:
248: if (forLevel != 0) {
1.8 ! espie 249: Buf_AddString(forBuf, line);
1.7 espie 250: Buf_AddChar(forBuf, '\n');
1.1 deraadt 251: return 1;
252: }
253: else {
254: return 0;
255: }
256: }
257:
258: /*-
259: *-----------------------------------------------------------------------
260: * ForExec --
261: * Expand the for loop for this index and push it in the Makefile
262: *
263: * Results:
264: * None.
265: *
266: * Side Effects:
267: * None.
268: *
269: *-----------------------------------------------------------------------
270: */
271: static int
272: ForExec(namep, argp)
273: ClientData namep;
274: ClientData argp;
275: {
276: char *name = (char *) namep;
277: For *arg = (For *) argp;
278: Var_Set(arg->var, name, VAR_GLOBAL);
279: if (DEBUG(FOR))
280: (void) fprintf(stderr, "--- %s = %s\n", arg->var, name);
1.7 espie 281: Parse_FromString(Var_Subst(arg->var, Buf_GetAll(arg->buf, NULL),
1.5 espie 282: VAR_GLOBAL, FALSE), arg->lineno);
1.1 deraadt 283: Var_Delete(arg->var, VAR_GLOBAL);
284:
285: return 0;
286: }
287:
288:
289: /*-
290: *-----------------------------------------------------------------------
291: * For_Run --
292: * Run the for loop, immitating the actions of an include file
293: *
294: * Results:
295: * None.
296: *
297: * Side Effects:
298: * None.
299: *
300: *-----------------------------------------------------------------------
301: */
302: void
303: For_Run()
304: {
305: For arg;
306:
307: if (forVar == NULL || forBuf == NULL || forLst == NULL)
308: return;
309: arg.var = forVar;
310: arg.buf = forBuf;
311: arg.lst = forLst;
1.5 espie 312: arg.lineno = forLineno;
1.1 deraadt 313: forVar = NULL;
314: forBuf = NULL;
315: forLst = NULL;
316:
317: Lst_ForEach(arg.lst, ForExec, (ClientData) &arg);
318:
319: free((Address)arg.var);
320: Lst_Destroy(arg.lst, (void (*) __P((ClientData))) free);
321: Buf_Destroy(arg.buf, TRUE);
322: }