source: trunk/src/kmk/for.c@ 23

Last change on this file since 23 was 9, checked in by bird, 23 years ago

Initial revision

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 7.6 KB
Line 
1/*
2 * Copyright (c) 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Christos Zoulas.
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 * @(#)for.c 8.1 (Berkeley) 6/6/93
37 */
38
39#include <sys/cdefs.h>
40__FBSDID("$FreeBSD: src/usr.bin/make/for.c,v 1.19 2002/10/09 03:42:10 jmallett Exp $");
41
42/*-
43 * for.c --
44 * Functions to handle loops in a makefile.
45 *
46 * Interface:
47 * For_Eval Evaluate the loop in the passed line.
48 * For_Run Run accumulated loop
49 *
50 */
51
52#include <ctype.h>
53#include "make.h"
54#include "hash.h"
55#include "dir.h"
56#include "buf.h"
57
58/*
59 * For statements are of the form:
60 *
61 * .for <variable> in <varlist>
62 * ...
63 * .endfor
64 *
65 * The trick is to look for the matching end inside for for loop
66 * To do that, we count the current nesting level of the for loops.
67 * and the .endfor statements, accumulating all the statements between
68 * the initial .for loop and the matching .endfor;
69 * then we evaluate the for loop for each variable in the varlist.
70 */
71
72static int forLevel = 0; /* Nesting level */
73static char *forVar; /* Iteration variable */
74static Buffer forBuf; /* Commands in loop */
75static Lst forLst; /* List of items */
76
77/*
78 * State of a for loop.
79 */
80typedef struct _For {
81 Buffer buf; /* Unexpanded buffer */
82 char* var; /* Index name */
83 Lst lst; /* List of variables */
84} For;
85
86static int ForExec(void *, void *);
87
88
89
90
91
92/*-
93 *-----------------------------------------------------------------------
94 * For_Eval --
95 * Evaluate the for loop in the passed line. The line
96 * looks like this:
97 * .for <variable> in <varlist>
98 *
99 * Results:
100 * TRUE: We found a for loop, or we are inside a for loop
101 * FALSE: We did not find a for loop, or we found the end of the for
102 * for loop.
103 *
104 * Side Effects:
105 * None.
106 *
107 *-----------------------------------------------------------------------
108 */
109int
110For_Eval (char *line)
111{
112 char *ptr = line, *sub, *wrd;
113 int level; /* Level at which to report errors. */
114
115 level = PARSE_FATAL;
116
117
118 if (forLevel == 0) {
119 Buffer buf;
120 int varlen;
121
122 for (ptr++; *ptr && isspace((unsigned char) *ptr); ptr++)
123 continue;
124 /*
125 * If we are not in a for loop quickly determine if the statement is
126 * a for.
127 */
128 if (ptr[0] != 'f' || ptr[1] != 'o' || ptr[2] != 'r' ||
129 !isspace((unsigned char) ptr[3]))
130 return FALSE;
131 ptr += 3;
132
133 /*
134 * we found a for loop, and now we are going to parse it.
135 */
136 while (*ptr && isspace((unsigned char) *ptr))
137 ptr++;
138
139 /*
140 * Grab the variable
141 */
142 buf = Buf_Init(0);
143 for (wrd = ptr; *ptr && !isspace((unsigned char) *ptr); ptr++)
144 continue;
145 Buf_AddBytes(buf, ptr - wrd, (Byte *) wrd);
146
147 forVar = (char *) Buf_GetAll(buf, &varlen);
148 if (varlen == 0) {
149 Parse_Error (level, "missing variable in for");
150 return 0;
151 }
152 Buf_Destroy(buf, FALSE);
153
154 while (*ptr && isspace((unsigned char) *ptr))
155 ptr++;
156
157 /*
158 * Grab the `in'
159 */
160 if (ptr[0] != 'i' || ptr[1] != 'n' ||
161 !isspace((unsigned char) ptr[2])) {
162 Parse_Error (level, "missing `in' in for");
163 printf("%s\n", ptr);
164 return 0;
165 }
166 ptr += 3;
167
168 while (*ptr && isspace((unsigned char) *ptr))
169 ptr++;
170
171 /*
172 * Make a list with the remaining words
173 */
174 forLst = Lst_Init(FALSE);
175 buf = Buf_Init(0);
176 sub = Var_Subst(NULL, ptr, VAR_GLOBAL, FALSE);
177
178#define ADDWORD() \
179 Buf_AddBytes(buf, ptr - wrd, (Byte *) wrd), \
180 Buf_AddByte(buf, (Byte) '\0'), \
181 Lst_AtFront(forLst, (void *) Buf_GetAll(buf, &varlen)), \
182 Buf_Destroy(buf, FALSE)
183
184 for (ptr = sub; *ptr && isspace((unsigned char) *ptr); ptr++)
185 continue;
186
187 for (wrd = ptr; *ptr; ptr++)
188 if (isspace((unsigned char) *ptr)) {
189 ADDWORD();
190 buf = Buf_Init(0);
191 while (*ptr && isspace((unsigned char) *ptr))
192 ptr++;
193 wrd = ptr--;
194 }
195 DEBUGF(FOR, ("For: Iterator %s List %s\n", forVar, sub));
196 if (ptr - wrd > 0)
197 ADDWORD();
198 else
199 Buf_Destroy(buf, TRUE);
200 free(sub);
201
202 forBuf = Buf_Init(0);
203 forLevel++;
204 return 1;
205 }
206 else if (*ptr == '.') {
207
208 for (ptr++; *ptr && isspace((unsigned char) *ptr); ptr++)
209 continue;
210
211 if (strncmp(ptr, "endfor", 6) == 0 &&
212 (isspace((unsigned char) ptr[6]) || !ptr[6])) {
213 DEBUGF(FOR, ("For: end for %d\n", forLevel));
214 if (--forLevel < 0) {
215 Parse_Error (level, "for-less endfor");
216 return 0;
217 }
218 }
219 else if (strncmp(ptr, "for", 3) == 0 &&
220 isspace((unsigned char) ptr[3])) {
221 forLevel++;
222 DEBUGF(FOR, ("For: new loop %d\n", forLevel));
223 }
224 }
225
226 if (forLevel != 0) {
227 Buf_AddBytes(forBuf, strlen(line), (Byte *) line);
228 Buf_AddByte(forBuf, (Byte) '\n');
229 return 1;
230 }
231 else {
232 return 0;
233 }
234}
235
236/*-
237 *-----------------------------------------------------------------------
238 * ForExec --
239 * Expand the for loop for this index and push it in the Makefile
240 *
241 * Results:
242 * None.
243 *
244 * Side Effects:
245 * None.
246 *
247 *-----------------------------------------------------------------------
248 */
249static int
250ForExec(void *namep, void *argp)
251{
252 char *name = (char *) namep;
253 For *arg = (For *) argp;
254 int len;
255 Var_Set(arg->var, name, VAR_GLOBAL);
256 DEBUGF(FOR, ("--- %s = %s\n", arg->var, name));
257 Parse_FromString(Var_Subst(arg->var, (char *) Buf_GetAll(arg->buf, &len),
258 VAR_GLOBAL, FALSE));
259 Var_Delete(arg->var, VAR_GLOBAL);
260
261 return 0;
262}
263
264
265
266/*-
267 *-----------------------------------------------------------------------
268 * For_Run --
269 * Run the for loop, immitating the actions of an include file
270 *
271 * Results:
272 * None.
273 *
274 * Side Effects:
275 * None.
276 *
277 *-----------------------------------------------------------------------
278 */
279void
280For_Run(void)
281{
282 For arg;
283
284 if (forVar == NULL || forBuf == NULL || forLst == NULL)
285 return;
286 arg.var = forVar;
287 arg.buf = forBuf;
288 arg.lst = forLst;
289 forVar = NULL;
290 forBuf = NULL;
291 forLst = NULL;
292
293 Lst_ForEach(arg.lst, ForExec, (void *) &arg);
294
295 free(arg.var);
296 Lst_Destroy(arg.lst, (void (*)(void *)) free);
297 Buf_Destroy(arg.buf, TRUE);
298}
Note: See TracBrowser for help on using the repository browser.