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