Annotation of src/usr.bin/make/for.c, Revision 1.5
1.5 ! espie 1: /* $OpenBSD: for.c,v 1.4 1998/12/05 00:06:27 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: /*
5: * Copyright (c) 1992, The Regents of the University of California.
6: * All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. All advertising materials mentioning features or use of this software
17: * must display the following acknowledgement:
18: * This product includes software developed by the University of
19: * California, Berkeley and its contributors.
20: * 4. Neither the name of the University nor the names of its contributors
21: * may be used to endorse or promote products derived from this software
22: * without specific prior written permission.
23: *
24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34: * SUCH DAMAGE.
35: */
36:
37: #ifndef lint
38: #if 0
1.3 millert 39: static char sccsid[] = "@(#)for.c 8.1 (Berkeley) 6/6/93";
1.1 deraadt 40: #else
1.5 ! espie 41: static char rcsid[] = "$OpenBSD: for.c,v 1.4 1998/12/05 00:06:27 espie Exp $";
1.1 deraadt 42: #endif
43: #endif /* not lint */
44:
45: /*-
46: * for.c --
47: * Functions to handle loops in a makefile.
48: *
49: * Interface:
50: * For_Eval Evaluate the loop in the passed line.
51: * For_Run Run accumulated loop
52: *
53: */
54:
55: #include <ctype.h>
56: #include "make.h"
57: #include "hash.h"
58: #include "dir.h"
59: #include "buf.h"
60:
61: /*
62: * For statements are of the form:
63: *
64: * .for <variable> in <varlist>
65: * ...
66: * .endfor
67: *
68: * The trick is to look for the matching end inside for for loop
69: * To do that, we count the current nesting level of the for loops.
70: * and the .endfor statements, accumulating all the statements between
1.3 millert 71: * the initial .for loop and the matching .endfor;
1.1 deraadt 72: * then we evaluate the for loop for each variable in the varlist.
73: */
74:
1.5 ! espie 75: static int forLevel = 0; /* Nesting level */
! 76: static char *forVar; /* Iteration variable */
! 77: static Buffer forBuf; /* Commands in loop */
! 78: static Lst forLst; /* List of items */
! 79: static unsigned long forLineno; /* Line at beginning of loop */
1.1 deraadt 80:
81: /*
82: * State of a for loop.
83: */
84: typedef struct _For {
1.5 ! espie 85: Buffer buf; /* Unexpanded buffer */
! 86: char* var; /* Index name */
! 87: Lst lst; /* List of variables */
! 88: unsigned long lineno;
1.1 deraadt 89: } For;
90:
91: static int ForExec __P((ClientData, ClientData));
92:
93:
94:
95:
96: /*-
97: *-----------------------------------------------------------------------
98: * For_Eval --
99: * Evaluate the for loop in the passed line. The line
100: * looks like this:
101: * .for <variable> in <varlist>
102: *
103: * Results:
104: * TRUE: We found a for loop, or we are inside a for loop
105: * FALSE: We did not find a for loop, or we found the end of the for
106: * for loop.
107: *
108: * Side Effects:
109: * None.
110: *
111: *-----------------------------------------------------------------------
112: */
113: int
114: For_Eval (line)
115: char *line; /* Line to parse */
116: {
117: char *ptr = line, *sub, *wrd;
118: int level; /* Level at which to report errors. */
119:
120: level = PARSE_FATAL;
121:
122:
123: if (forLevel == 0) {
124: Buffer buf;
125: int varlen;
126:
127: for (ptr++; *ptr && isspace((unsigned char) *ptr); ptr++)
128: continue;
129: /*
130: * If we are not in a for loop quickly determine if the statement is
131: * a for.
132: */
133: if (ptr[0] != 'f' || ptr[1] != 'o' || ptr[2] != 'r' ||
134: !isspace((unsigned char) ptr[3]))
135: return FALSE;
136: ptr += 3;
1.3 millert 137:
1.1 deraadt 138: /*
139: * we found a for loop, and now we are going to parse it.
140: */
141: while (*ptr && isspace((unsigned char) *ptr))
142: ptr++;
1.3 millert 143:
1.1 deraadt 144: /*
145: * Grab the variable
146: */
147: buf = Buf_Init(0);
1.3 millert 148: for (wrd = ptr; *ptr && !isspace((unsigned char) *ptr); ptr++)
1.1 deraadt 149: continue;
150: Buf_AddBytes(buf, ptr - wrd, (Byte *) wrd);
151:
152: forVar = (char *) Buf_GetAll(buf, &varlen);
153: if (varlen == 0) {
154: Parse_Error (level, "missing variable in for");
155: return 0;
156: }
157: Buf_Destroy(buf, FALSE);
158:
159: while (*ptr && isspace((unsigned char) *ptr))
160: ptr++;
161:
162: /*
163: * Grab the `in'
164: */
165: if (ptr[0] != 'i' || ptr[1] != 'n' ||
166: !isspace((unsigned char) ptr[2])) {
167: Parse_Error (level, "missing `in' in for");
168: printf("%s\n", ptr);
169: return 0;
170: }
171: ptr += 3;
172:
173: while (*ptr && isspace((unsigned char) *ptr))
174: ptr++;
175:
176: /*
177: * Make a list with the remaining words
178: */
179: forLst = Lst_Init(FALSE);
1.5 ! espie 180: forLineno = Parse_Getlineno();
1.1 deraadt 181: buf = Buf_Init(0);
1.3 millert 182: sub = Var_Subst(NULL, ptr, VAR_GLOBAL, FALSE);
1.1 deraadt 183:
184: #define ADDWORD() \
185: Buf_AddBytes(buf, ptr - wrd, (Byte *) wrd), \
186: Buf_AddByte(buf, (Byte) '\0'), \
1.3 millert 187: Lst_AtFront(forLst, (ClientData) Buf_GetAll(buf, &varlen)), \
1.1 deraadt 188: Buf_Destroy(buf, FALSE)
189:
190: for (ptr = sub; *ptr && isspace((unsigned char) *ptr); ptr++)
191: continue;
192:
193: for (wrd = ptr; *ptr; ptr++)
194: if (isspace((unsigned char) *ptr)) {
195: ADDWORD();
196: buf = Buf_Init(0);
197: while (*ptr && isspace((unsigned char) *ptr))
198: ptr++;
199: wrd = ptr--;
200: }
201: if (DEBUG(FOR))
202: (void) fprintf(stderr, "For: Iterator %s List %s\n", forVar, sub);
1.3 millert 203: if (ptr - wrd > 0)
1.1 deraadt 204: ADDWORD();
205: else
206: Buf_Destroy(buf, TRUE);
207: free((Address) sub);
1.3 millert 208:
1.1 deraadt 209: forBuf = Buf_Init(0);
210: forLevel++;
211: return 1;
212: }
213: else if (*ptr == '.') {
214:
215: for (ptr++; *ptr && isspace((unsigned char) *ptr); ptr++)
216: continue;
217:
218: if (strncmp(ptr, "endfor", 6) == 0 &&
219: (isspace((unsigned char) ptr[6]) || !ptr[6])) {
220: if (DEBUG(FOR))
221: (void) fprintf(stderr, "For: end for %d\n", forLevel);
222: if (--forLevel < 0) {
223: Parse_Error (level, "for-less endfor");
224: return 0;
225: }
226: }
227: else if (strncmp(ptr, "for", 3) == 0 &&
228: isspace((unsigned char) ptr[3])) {
229: forLevel++;
230: if (DEBUG(FOR))
231: (void) fprintf(stderr, "For: new loop %d\n", forLevel);
232: }
233: }
234:
235: if (forLevel != 0) {
236: Buf_AddBytes(forBuf, strlen(line), (Byte *) line);
237: Buf_AddByte(forBuf, (Byte) '\n');
238: return 1;
239: }
240: else {
241: return 0;
242: }
243: }
244:
245: /*-
246: *-----------------------------------------------------------------------
247: * ForExec --
248: * Expand the for loop for this index and push it in the Makefile
249: *
250: * Results:
251: * None.
252: *
253: * Side Effects:
254: * None.
255: *
256: *-----------------------------------------------------------------------
257: */
258: static int
259: ForExec(namep, argp)
260: ClientData namep;
261: ClientData argp;
262: {
263: char *name = (char *) namep;
264: For *arg = (For *) argp;
265: int len;
266: Var_Set(arg->var, name, VAR_GLOBAL);
267: if (DEBUG(FOR))
268: (void) fprintf(stderr, "--- %s = %s\n", arg->var, name);
1.3 millert 269: Parse_FromString(Var_Subst(arg->var, (char *) Buf_GetAll(arg->buf, &len),
1.5 ! espie 270: VAR_GLOBAL, FALSE), arg->lineno);
1.1 deraadt 271: Var_Delete(arg->var, VAR_GLOBAL);
272:
273: return 0;
274: }
275:
276:
277: /*-
278: *-----------------------------------------------------------------------
279: * For_Run --
280: * Run the for loop, immitating the actions of an include file
281: *
282: * Results:
283: * None.
284: *
285: * Side Effects:
286: * None.
287: *
288: *-----------------------------------------------------------------------
289: */
290: void
291: For_Run()
292: {
293: For arg;
294:
295: if (forVar == NULL || forBuf == NULL || forLst == NULL)
296: return;
297: arg.var = forVar;
298: arg.buf = forBuf;
299: arg.lst = forLst;
1.5 ! espie 300: arg.lineno = forLineno;
1.1 deraadt 301: forVar = NULL;
302: forBuf = NULL;
303: forLst = NULL;
304:
305: Lst_ForEach(arg.lst, ForExec, (ClientData) &arg);
306:
307: free((Address)arg.var);
308: Lst_Destroy(arg.lst, (void (*) __P((ClientData))) free);
309: Buf_Destroy(arg.buf, TRUE);
310: }