- Inline silly #define MACRO.
[dragonfly.git] / usr.bin / make / for.c
CommitLineData
984263bc 1/*
9a309bcc
MD
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.
984263bc
MD
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.
1de703da
MD
35 *
36 * @(#)for.c 8.1 (Berkeley) 6/6/93
37 * $FreeBSD: src/usr.bin/make/for.c,v 1.10 1999/09/11 13:08:01 hoek Exp $
e035775c 38 * $DragonFly: src/usr.bin/make/for.c,v 1.21 2005/01/24 05:11:01 okumoto Exp $
984263bc
MD
39 */
40
984263bc
MD
41/*-
42 * for.c --
43 * Functions to handle loops in a makefile.
44 *
45 * Interface:
46 * For_Eval Evaluate the loop in the passed line.
47 * For_Run Run accumulated loop
48 *
49 */
50
9863ce62
MO
51#include <ctype.h>
52#include <stdlib.h>
53#include <string.h>
54
55#include "buf.h"
56#include "dir.h"
57#include "for.h"
58#include "globals.h"
59#include "lst.h"
60#include "make.h"
61#include "parse.h"
62#include "util.h"
63#include "var.h"
984263bc
MD
64
65/*
66 * For statements are of the form:
67 *
68 * .for <variable> in <varlist>
69 * ...
70 * .endfor
71 *
72 * The trick is to look for the matching end inside for for loop
73 * To do that, we count the current nesting level of the for loops.
74 * and the .endfor statements, accumulating all the statements between
75 * the initial .for loop and the matching .endfor;
76 * then we evaluate the for loop for each variable in the varlist.
77 */
78
79static int forLevel = 0; /* Nesting level */
80static char *forVar; /* Iteration variable */
6a3d9147 81static Buffer *forBuf; /* Commands in loop */
0a7e0b85 82static Lst forLst; /* List of items */
984263bc
MD
83
84/*
85 * State of a for loop.
86 */
87typedef struct _For {
6a3d9147 88 Buffer *buf; /* Unexpanded buffer */
984263bc 89 char* var; /* Index name */
0a7e0b85 90 Lst lst; /* List of variables */
d3de034c 91 int lineno; /* Line # */
984263bc
MD
92} For;
93
9edd457e 94static int ForExec(void *, void *);
984263bc 95
984263bc
MD
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 */
113int
fbfaa208 114For_Eval(char *line)
984263bc
MD
115{
116 char *ptr = line, *sub, *wrd;
117 int level; /* Level at which to report errors. */
118
119 level = PARSE_FATAL;
120
121
122 if (forLevel == 0) {
6a3d9147 123 Buffer *buf;
9cf296a4 124 size_t varlen;
984263bc 125
fbfaa208 126 for (ptr++; *ptr && isspace((unsigned char)*ptr); ptr++)
984263bc
MD
127 continue;
128 /*
129 * If we are not in a for loop quickly determine if the statement is
130 * a for.
131 */
132 if (ptr[0] != 'f' || ptr[1] != 'o' || ptr[2] != 'r' ||
fbfaa208
MO
133 !isspace((unsigned char)ptr[3]))
134 return (FALSE);
984263bc
MD
135 ptr += 3;
136
137 /*
138 * we found a for loop, and now we are going to parse it.
139 */
fbfaa208 140 while (*ptr && isspace((unsigned char)*ptr))
984263bc
MD
141 ptr++;
142
143 /*
144 * Grab the variable
145 */
146 buf = Buf_Init(0);
fbfaa208 147 for (wrd = ptr; *ptr && !isspace((unsigned char)*ptr); ptr++)
984263bc 148 continue;
fbfaa208 149 Buf_AddBytes(buf, ptr - wrd, (Byte *)wrd);
984263bc 150
fbfaa208 151 forVar = (char *)Buf_GetAll(buf, &varlen);
984263bc 152 if (varlen == 0) {
fbfaa208
MO
153 Parse_Error(level, "missing variable in for");
154 return (0);
984263bc
MD
155 }
156 Buf_Destroy(buf, FALSE);
157
fbfaa208 158 while (*ptr && isspace((unsigned char)*ptr))
984263bc
MD
159 ptr++;
160
161 /*
162 * Grab the `in'
163 */
164 if (ptr[0] != 'i' || ptr[1] != 'n' ||
fbfaa208
MO
165 !isspace((unsigned char)ptr[2])) {
166 Parse_Error(level, "missing `in' in for");
984263bc 167 printf("%s\n", ptr);
fbfaa208 168 return (0);
984263bc
MD
169 }
170 ptr += 3;
171
fbfaa208 172 while (*ptr && isspace((unsigned char)*ptr))
984263bc
MD
173 ptr++;
174
175 /*
176 * Make a list with the remaining words
177 */
0a7e0b85 178 Lst_Init(&forLst);
984263bc 179 buf = Buf_Init(0);
4bd279b8 180 sub = Var_Subst(NULL, ptr, VAR_CMD, FALSE);
984263bc 181
fbfaa208 182 for (ptr = sub; *ptr && isspace((unsigned char)*ptr); ptr++)
984263bc
MD
183 continue;
184
185 for (wrd = ptr; *ptr; ptr++)
fbfaa208 186 if (isspace((unsigned char)*ptr)) {
e035775c
MO
187 Buf_AddBytes(buf, ptr - wrd, (Byte *)wrd);
188 Lst_AtFront(&forLst, Buf_GetAll(buf, &varlen));
189 Buf_Destroy(buf, FALSE);
984263bc 190 buf = Buf_Init(0);
fbfaa208 191 while (*ptr && isspace((unsigned char)*ptr))
984263bc
MD
192 ptr++;
193 wrd = ptr--;
194 }
913800f5 195 DEBUGF(FOR, ("For: Iterator %s List %s\n", forVar, sub));
e035775c
MO
196 if (ptr - wrd > 0) {
197 Buf_AddBytes(buf, ptr - wrd, (Byte *)wrd);
198 Lst_AtFront(&forLst, Buf_GetAll(buf, &varlen));
199 Buf_Destroy(buf, FALSE);
200 } else {
984263bc 201 Buf_Destroy(buf, TRUE);
e035775c 202 }
9edd457e 203 free(sub);
984263bc
MD
204
205 forBuf = Buf_Init(0);
206 forLevel++;
fbfaa208 207 return (1);
984263bc
MD
208 }
209 else if (*ptr == '.') {
210
fbfaa208 211 for (ptr++; *ptr && isspace((unsigned char)*ptr); ptr++)
984263bc
MD
212 continue;
213
214 if (strncmp(ptr, "endfor", 6) == 0 &&
fbfaa208 215 (isspace((unsigned char)ptr[6]) || !ptr[6])) {
913800f5 216 DEBUGF(FOR, ("For: end for %d\n", forLevel));
984263bc 217 if (--forLevel < 0) {
fbfaa208
MO
218 Parse_Error(level, "for-less endfor");
219 return (0);
984263bc
MD
220 }
221 }
222 else if (strncmp(ptr, "for", 3) == 0 &&
fbfaa208 223 isspace((unsigned char)ptr[3])) {
984263bc 224 forLevel++;
913800f5 225 DEBUGF(FOR, ("For: new loop %d\n", forLevel));
984263bc
MD
226 }
227 }
228
229 if (forLevel != 0) {
fbfaa208
MO
230 Buf_AddBytes(forBuf, strlen(line), (Byte *)line);
231 Buf_AddByte(forBuf, (Byte)'\n');
232 return (1);
984263bc
MD
233 }
234 else {
fbfaa208 235 return (0);
984263bc
MD
236 }
237}
238
239/*-
240 *-----------------------------------------------------------------------
241 * ForExec --
242 * Expand the for loop for this index and push it in the Makefile
243 *
244 * Results:
245 * None.
246 *
247 * Side Effects:
248 * None.
249 *
250 *-----------------------------------------------------------------------
251 */
252static int
84de9e23 253ForExec(void *namep, void *argp)
984263bc 254{
9a4c88c2
MO
255 char *name = namep;
256 For *arg = argp;
9a4c88c2 257
984263bc 258 Var_Set(arg->var, name, VAR_GLOBAL);
913800f5 259 DEBUGF(FOR, ("--- %s = %s\n", arg->var, name));
67492fd2 260 Parse_FromString(Var_Subst(arg->var, (char *)Buf_GetAll(arg->buf, NULL),
d3de034c 261 VAR_GLOBAL, FALSE), arg->lineno);
984263bc
MD
262 Var_Delete(arg->var, VAR_GLOBAL);
263
fbfaa208 264 return (0);
984263bc
MD
265}
266
984263bc
MD
267/*-
268 *-----------------------------------------------------------------------
269 * For_Run --
270 * Run the for loop, immitating the actions of an include file
271 *
272 * Results:
273 * None.
274 *
275 * Side Effects:
276 * None.
277 *
278 *-----------------------------------------------------------------------
279 */
280void
d3de034c 281For_Run(int lineno)
984263bc
MD
282{
283 For arg;
284
0a7e0b85 285 if (forVar == NULL || forBuf == NULL)
984263bc
MD
286 return;
287 arg.var = forVar;
288 arg.buf = forBuf;
0a7e0b85
MO
289
290 /* move the forLst to the arg to get it free for nested for's */
291 Lst_Init(&arg.lst);
292 Lst_Concat(&arg.lst, &forLst, LST_CONCLINK);
293
d3de034c 294 arg.lineno = lineno;
984263bc
MD
295 forVar = NULL;
296 forBuf = NULL;
984263bc 297
0a7e0b85 298 Lst_ForEach(&arg.lst, ForExec, &arg);
984263bc 299
9edd457e 300 free(arg.var);
0a7e0b85 301 Lst_Destroy(&arg.lst, free);
984263bc
MD
302 Buf_Destroy(arg.buf, TRUE);
303}