Hiding pointer in typedefs is evil. 'Buffer *' -> 'Buffer'
[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 $
6a3d9147 38 * $DragonFly: src/usr.bin/make/for.c,v 1.18 2005/01/06 13:18:58 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
913800f5 182#define ADDWORD() \
fbfaa208
MO
183 Buf_AddBytes(buf, ptr - wrd, (Byte *)wrd), \
184 Buf_AddByte(buf, (Byte)'\0'), \
0a7e0b85 185 Lst_AtFront(&forLst, Buf_GetAll(buf, &varlen)), \
984263bc
MD
186 Buf_Destroy(buf, FALSE)
187
fbfaa208 188 for (ptr = sub; *ptr && isspace((unsigned char)*ptr); ptr++)
984263bc
MD
189 continue;
190
191 for (wrd = ptr; *ptr; ptr++)
fbfaa208 192 if (isspace((unsigned char)*ptr)) {
984263bc
MD
193 ADDWORD();
194 buf = Buf_Init(0);
fbfaa208 195 while (*ptr && isspace((unsigned char)*ptr))
984263bc
MD
196 ptr++;
197 wrd = ptr--;
198 }
913800f5 199 DEBUGF(FOR, ("For: Iterator %s List %s\n", forVar, sub));
984263bc
MD
200 if (ptr - wrd > 0)
201 ADDWORD();
202 else
203 Buf_Destroy(buf, TRUE);
9edd457e 204 free(sub);
984263bc
MD
205
206 forBuf = Buf_Init(0);
207 forLevel++;
fbfaa208 208 return (1);
984263bc
MD
209 }
210 else if (*ptr == '.') {
211
fbfaa208 212 for (ptr++; *ptr && isspace((unsigned char)*ptr); ptr++)
984263bc
MD
213 continue;
214
215 if (strncmp(ptr, "endfor", 6) == 0 &&
fbfaa208 216 (isspace((unsigned char)ptr[6]) || !ptr[6])) {
913800f5 217 DEBUGF(FOR, ("For: end for %d\n", forLevel));
984263bc 218 if (--forLevel < 0) {
fbfaa208
MO
219 Parse_Error(level, "for-less endfor");
220 return (0);
984263bc
MD
221 }
222 }
223 else if (strncmp(ptr, "for", 3) == 0 &&
fbfaa208 224 isspace((unsigned char)ptr[3])) {
984263bc 225 forLevel++;
913800f5 226 DEBUGF(FOR, ("For: new loop %d\n", forLevel));
984263bc
MD
227 }
228 }
229
230 if (forLevel != 0) {
fbfaa208
MO
231 Buf_AddBytes(forBuf, strlen(line), (Byte *)line);
232 Buf_AddByte(forBuf, (Byte)'\n');
233 return (1);
984263bc
MD
234 }
235 else {
fbfaa208 236 return (0);
984263bc
MD
237 }
238}
239
240/*-
241 *-----------------------------------------------------------------------
242 * ForExec --
243 * Expand the for loop for this index and push it in the Makefile
244 *
245 * Results:
246 * None.
247 *
248 * Side Effects:
249 * None.
250 *
251 *-----------------------------------------------------------------------
252 */
253static int
84de9e23 254ForExec(void *namep, void *argp)
984263bc 255{
9a4c88c2
MO
256 char *name = namep;
257 For *arg = argp;
9cf296a4 258 size_t len;
9a4c88c2 259
984263bc 260 Var_Set(arg->var, name, VAR_GLOBAL);
913800f5 261 DEBUGF(FOR, ("--- %s = %s\n", arg->var, name));
fbfaa208 262 Parse_FromString(Var_Subst(arg->var, (char *)Buf_GetAll(arg->buf, &len),
d3de034c 263 VAR_GLOBAL, FALSE), arg->lineno);
984263bc
MD
264 Var_Delete(arg->var, VAR_GLOBAL);
265
fbfaa208 266 return (0);
984263bc
MD
267}
268
984263bc
MD
269/*-
270 *-----------------------------------------------------------------------
271 * For_Run --
272 * Run the for loop, immitating the actions of an include file
273 *
274 * Results:
275 * None.
276 *
277 * Side Effects:
278 * None.
279 *
280 *-----------------------------------------------------------------------
281 */
282void
d3de034c 283For_Run(int lineno)
984263bc
MD
284{
285 For arg;
286
0a7e0b85 287 if (forVar == NULL || forBuf == NULL)
984263bc
MD
288 return;
289 arg.var = forVar;
290 arg.buf = forBuf;
0a7e0b85
MO
291
292 /* move the forLst to the arg to get it free for nested for's */
293 Lst_Init(&arg.lst);
294 Lst_Concat(&arg.lst, &forLst, LST_CONCLINK);
295
d3de034c 296 arg.lineno = lineno;
984263bc
MD
297 forVar = NULL;
298 forBuf = NULL;
984263bc 299
0a7e0b85 300 Lst_ForEach(&arg.lst, ForExec, &arg);
984263bc 301
9edd457e 302 free(arg.var);
0a7e0b85 303 Lst_Destroy(&arg.lst, free);
984263bc
MD
304 Buf_Destroy(arg.buf, TRUE);
305}