Annotation of src/usr.bin/make/for.c, Revision 1.13
1.13 ! wiz 1: /* $NetBSD: for.c,v 1.12 2002/03/12 20:15:15 christos Exp $ */
1.3 christos 2:
1.1 cgd 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:
1.6 lukem 36: #ifdef MAKE_BOOTSTRAP
1.13 ! wiz 37: static char rcsid[] = "$NetBSD: for.c,v 1.12 2002/03/12 20:15:15 christos Exp $";
1.6 lukem 38: #else
1.5 christos 39: #include <sys/cdefs.h>
1.1 cgd 40: #ifndef lint
1.3 christos 41: #if 0
1.4 christos 42: static char sccsid[] = "@(#)for.c 8.1 (Berkeley) 6/6/93";
1.3 christos 43: #else
1.13 ! wiz 44: __RCSID("$NetBSD: for.c,v 1.12 2002/03/12 20:15:15 christos Exp $");
1.3 christos 45: #endif
1.1 cgd 46: #endif /* not lint */
1.6 lukem 47: #endif
1.1 cgd 48:
49: /*-
50: * for.c --
51: * Functions to handle loops in a makefile.
52: *
53: * Interface:
54: * For_Eval Evaluate the loop in the passed line.
55: * For_Run Run accumulated loop
56: *
57: */
58:
1.13 ! wiz 59: #include <assert.h>
1.1 cgd 60: #include <ctype.h>
1.13 ! wiz 61:
1.1 cgd 62: #include "make.h"
63: #include "hash.h"
64: #include "dir.h"
65: #include "buf.h"
66:
67: /*
68: * For statements are of the form:
69: *
70: * .for <variable> in <varlist>
71: * ...
72: * .endfor
73: *
74: * The trick is to look for the matching end inside for for loop
75: * To do that, we count the current nesting level of the for loops.
76: * and the .endfor statements, accumulating all the statements between
1.4 christos 77: * the initial .for loop and the matching .endfor;
1.1 cgd 78: * then we evaluate the for loop for each variable in the varlist.
1.7 christos 79: *
80: * Note that any nested fors are just passed through; they get handled
81: * recursively in For_Eval when we're expanding the enclosing for in
82: * For_Run.
1.1 cgd 83: */
84:
85: static int forLevel = 0; /* Nesting level */
86:
87: /*
88: * State of a for loop.
89: */
1.2 jtc 90: typedef struct _For {
1.7 christos 91: Buffer buf; /* Body of loop */
92: char **vars; /* Iteration variables */
93: int nvars; /* # of iteration vars */
94: Lst lst; /* List of items */
1.2 jtc 95: } For;
1.1 cgd 96:
1.7 christos 97: static For accumFor; /* Loop being accumulated */
1.1 cgd 98:
1.13 ! wiz 99: static void ForAddVar(const char *, size_t);
1.1 cgd 100:
101:
102:
1.7 christos 103:
104: /*-
105: *-----------------------------------------------------------------------
106: * ForAddVar --
107: * Add an iteration variable to the currently accumulating for.
108: *
109: * Results: none
110: * Side effects: no additional side effects.
111: *-----------------------------------------------------------------------
112: */
113: static void
1.13 ! wiz 114: ForAddVar(const char *data, size_t len)
1.7 christos 115: {
116: Buffer buf;
1.8 simonb 117: int varlen;
1.7 christos 118:
119: buf = Buf_Init(0);
120: Buf_AddBytes(buf, len, (Byte *) data);
121:
122: accumFor.nvars++;
123: accumFor.vars = erealloc(accumFor.vars, accumFor.nvars*sizeof(char *));
124:
125: accumFor.vars[accumFor.nvars-1] = (char *) Buf_GetAll(buf, &varlen);
126:
127: Buf_Destroy(buf, FALSE);
128: }
129:
1.1 cgd 130: /*-
131: *-----------------------------------------------------------------------
132: * For_Eval --
133: * Evaluate the for loop in the passed line. The line
134: * looks like this:
135: * .for <variable> in <varlist>
136: *
1.13 ! wiz 137: * Input:
! 138: * line Line to parse
! 139: *
1.1 cgd 140: * Results:
141: * TRUE: We found a for loop, or we are inside a for loop
142: * FALSE: We did not find a for loop, or we found the end of the for
143: * for loop.
144: *
145: * Side Effects:
146: * None.
147: *
148: *-----------------------------------------------------------------------
149: */
150: int
1.13 ! wiz 151: For_Eval(char *line)
1.1 cgd 152: {
1.7 christos 153: char *ptr = line, *sub, *in, *wrd;
1.1 cgd 154: int level; /* Level at which to report errors. */
155:
156: level = PARSE_FATAL;
157:
158:
159: if (forLevel == 0) {
160: Buffer buf;
161: int varlen;
1.12 christos 162: static const char instr[] = "in";
1.1 cgd 163:
1.2 jtc 164: for (ptr++; *ptr && isspace((unsigned char) *ptr); ptr++)
1.1 cgd 165: continue;
166: /*
167: * If we are not in a for loop quickly determine if the statement is
168: * a for.
169: */
1.2 jtc 170: if (ptr[0] != 'f' || ptr[1] != 'o' || ptr[2] != 'r' ||
171: !isspace((unsigned char) ptr[3]))
1.1 cgd 172: return FALSE;
173: ptr += 3;
1.4 christos 174:
1.1 cgd 175: /*
176: * we found a for loop, and now we are going to parse it.
177: */
1.2 jtc 178: while (*ptr && isspace((unsigned char) *ptr))
1.1 cgd 179: ptr++;
1.4 christos 180:
1.1 cgd 181: /*
1.7 christos 182: * Find the "in".
1.1 cgd 183: */
1.7 christos 184: for (in = ptr; *in; in++) {
185: if (isspace((unsigned char) in[0]) && in[1]== 'i' &&
186: in[2] == 'n' &&
187: (in[3] == '\0' || isspace((unsigned char) in[3])))
188: break;
189: }
190: if (*in == '\0') {
191: Parse_Error(level, "missing `in' in for");
1.1 cgd 192: return 0;
193: }
194:
195: /*
1.7 christos 196: * Grab the variables.
1.1 cgd 197: */
1.7 christos 198: accumFor.vars = NULL;
199:
200: while (ptr < in) {
201: wrd = ptr;
202: while (*ptr && !isspace((unsigned char) *ptr))
203: ptr++;
204: ForAddVar(wrd, ptr - wrd);
205: while (*ptr && isspace((unsigned char) *ptr))
206: ptr++;
207: }
208:
209: if (accumFor.nvars == 0) {
210: Parse_Error(level, "no iteration variables in for");
1.1 cgd 211: return 0;
212: }
1.7 christos 213:
214: /* At this point we should be pointing right at the "in" */
1.12 christos 215: /*
216: * compensate for hp/ux's brain damaged assert macro that
217: * does not handle double quotes nicely.
218: */
219: assert(!memcmp(ptr, instr, 2));
1.7 christos 220: ptr += 2;
1.1 cgd 221:
1.2 jtc 222: while (*ptr && isspace((unsigned char) *ptr))
1.1 cgd 223: ptr++;
224:
225: /*
226: * Make a list with the remaining words
227: */
1.7 christos 228: accumFor.lst = Lst_Init(FALSE);
1.1 cgd 229: buf = Buf_Init(0);
1.4 christos 230: sub = Var_Subst(NULL, ptr, VAR_GLOBAL, FALSE);
1.1 cgd 231:
232: #define ADDWORD() \
233: Buf_AddBytes(buf, ptr - wrd, (Byte *) wrd), \
234: Buf_AddByte(buf, (Byte) '\0'), \
1.7 christos 235: Lst_AtFront(accumFor.lst, (ClientData) Buf_GetAll(buf, &varlen)), \
1.1 cgd 236: Buf_Destroy(buf, FALSE)
237:
1.2 jtc 238: for (ptr = sub; *ptr && isspace((unsigned char) *ptr); ptr++)
1.1 cgd 239: continue;
240:
241: for (wrd = ptr; *ptr; ptr++)
1.2 jtc 242: if (isspace((unsigned char) *ptr)) {
1.1 cgd 243: ADDWORD();
244: buf = Buf_Init(0);
1.2 jtc 245: while (*ptr && isspace((unsigned char) *ptr))
1.1 cgd 246: ptr++;
247: wrd = ptr--;
248: }
1.7 christos 249: if (DEBUG(FOR)) {
250: int i;
251: for (i = 0; i < accumFor.nvars; i++) {
252: (void) fprintf(stderr, "For: variable %s\n", accumFor.vars[i]);
253: }
254: (void) fprintf(stderr, "For: list %s\n", sub);
255: }
1.4 christos 256: if (ptr - wrd > 0)
1.1 cgd 257: ADDWORD();
258: else
259: Buf_Destroy(buf, TRUE);
260: free((Address) sub);
1.4 christos 261:
1.7 christos 262: accumFor.buf = Buf_Init(0);
1.1 cgd 263: forLevel++;
264: return 1;
265: }
266: else if (*ptr == '.') {
267:
1.2 jtc 268: for (ptr++; *ptr && isspace((unsigned char) *ptr); ptr++)
1.1 cgd 269: continue;
270:
1.2 jtc 271: if (strncmp(ptr, "endfor", 6) == 0 &&
272: (isspace((unsigned char) ptr[6]) || !ptr[6])) {
1.1 cgd 273: if (DEBUG(FOR))
274: (void) fprintf(stderr, "For: end for %d\n", forLevel);
275: if (--forLevel < 0) {
276: Parse_Error (level, "for-less endfor");
277: return 0;
278: }
279: }
1.2 jtc 280: else if (strncmp(ptr, "for", 3) == 0 &&
281: isspace((unsigned char) ptr[3])) {
1.1 cgd 282: forLevel++;
283: if (DEBUG(FOR))
284: (void) fprintf(stderr, "For: new loop %d\n", forLevel);
285: }
286: }
287:
288: if (forLevel != 0) {
1.7 christos 289: Buf_AddBytes(accumFor.buf, strlen(line), (Byte *) line);
290: Buf_AddByte(accumFor.buf, (Byte) '\n');
1.1 cgd 291: return 1;
292: }
293: else {
294: return 0;
295: }
296: }
297:
298:
299: /*-
300: *-----------------------------------------------------------------------
301: * For_Run --
1.7 christos 302: * Run the for loop, imitating the actions of an include file
1.1 cgd 303: *
304: * Results:
305: * None.
306: *
307: * Side Effects:
308: * None.
309: *
310: *-----------------------------------------------------------------------
311: */
312: void
1.13 ! wiz 313: For_Run(void)
1.1 cgd 314: {
1.2 jtc 315: For arg;
1.7 christos 316: LstNode ln;
317: char **values;
318: int i, done = 0, len;
1.10 mycroft 319: char *guy, *orig_guy, *old_guy;
1.7 christos 320:
321: if (accumFor.buf == NULL || accumFor.vars == NULL || accumFor.lst == NULL)
322: return;
323: arg = accumFor;
324: accumFor.buf = NULL;
325: accumFor.vars = NULL;
326: accumFor.nvars = 0;
327: accumFor.lst = NULL;
1.1 cgd 328:
1.7 christos 329: if (Lst_Open(arg.lst) != SUCCESS)
1.1 cgd 330: return;
331:
1.7 christos 332: values = emalloc(arg.nvars * sizeof(char *));
333:
334: while (!done) {
335: /*
336: * due to the dumb way this is set up, this loop must run
337: * backwards.
338: */
339: for (i = arg.nvars - 1; i >= 0; i--) {
340: ln = Lst_Next(arg.lst);
341: if (ln == NILLNODE) {
342: if (i != arg.nvars-1) {
343: Parse_Error(PARSE_FATAL,
344: "Not enough words in for substitution list");
345: }
346: done = 1;
347: break;
348: } else {
349: values[i] = (char *) Lst_Datum(ln);
350: }
351: }
352: if (done)
353: break;
354:
355: for (i = 0; i < arg.nvars; i++) {
1.11 sjg 356: Var_Set(arg.vars[i], values[i], VAR_GLOBAL, 0);
1.7 christos 357: if (DEBUG(FOR))
358: (void) fprintf(stderr, "--- %s = %s\n", arg.vars[i],
359: values[i]);
360: }
361:
362: /*
363: * Hack, hack, kludge.
364: * This is really ugly, but to do it any better way would require
365: * making major changes to var.c, which I don't want to get into
366: * yet. There is no mechanism for expanding some variables, only
367: * for expanding a single variable. That should be corrected, but
368: * not right away. (XXX)
369: */
370:
371: guy = (char *) Buf_GetAll(arg.buf, &len);
1.10 mycroft 372: orig_guy = guy;
373: for (i = 0; i < arg.nvars; i++) {
374: old_guy = guy;
375: guy = Var_Subst(arg.vars[i], guy, VAR_GLOBAL, FALSE);
376: if (old_guy != orig_guy)
377: free(old_guy);
378: }
1.7 christos 379: Parse_FromString(guy);
380:
381: for (i = 0; i < arg.nvars; i++)
1.10 mycroft 382: Var_Delete(arg.vars[i], VAR_GLOBAL);
1.7 christos 383: }
384:
385: free(values);
386:
387: Lst_Close(arg.lst);
388:
389: for (i=0; i<arg.nvars; i++) {
390: free(arg.vars[i]);
391: }
392: free(arg.vars);
1.1 cgd 393:
1.13 ! wiz 394: Lst_Destroy(arg.lst, (void (*)(ClientData)) free);
1.1 cgd 395: Buf_Destroy(arg.buf, TRUE);
396: }
CVSweb <webmaster@jp.NetBSD.org>