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