Annotation of src/usr.bin/make/for.c, Revision 1.11
1.11 ! espie 1: /* $OpenBSD: for.c,v 1.10 1999/12/16 17:02:45 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.11 ! espie 68: static char rcsid[] = "$OpenBSD: for.c,v 1.10 1999/12/16 17:02:45 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: *
1.11 ! espie 95: * The trick is to look for the matching .end inside .for loops.
! 96: * To do that, we keep track of the nesting level of .for loops
! 97: * and matching .endfor statements, accumulating all statements between
! 98: * the initial .for loop and the matching .endfor,
! 99: * then we evaluate the .for loop for each variable in the varlist.
1.1 deraadt 100: */
101:
1.11 ! espie 102: /* State of a for loop. */
! 103: struct For_ {
! 104: char *text; /* unexpanded text */
! 105: char *var; /* Index name */
! 106: Lst lst; /* List of items */
! 107: BUFFER buf; /* Accumulating text */
! 108: unsigned long lineno; /* Line number at start of loop */
! 109: unsigned long level; /* Nesting level */
! 110: };
1.1 deraadt 111:
1.11 ! espie 112: static int ForExec __P((ClientData, ClientData));
1.6 espie 113: static void build_words_list __P((Lst, const char *));
1.1 deraadt 114:
1.6 espie 115: /* Cut a string into words, stuff that into list. */
116: static void
117: build_words_list(lst, s)
118: Lst lst;
119: const char *s;
120: {
121: const char *wrd;
1.1 deraadt 122:
1.6 espie 123: for (;;) {
124: for (; *s != '\0' && isspace(*s); s++)
125: continue;
126: if (*s == '\0')
127: break;
128: for (wrd = s; *s != '\0' && !isspace(*s); s++)
129: continue;
1.11 ! espie 130: /* note that we fill the list backward, since
! 131: * Parse_FromString stacks strings. */
1.6 espie 132: Lst_AtFront(lst, (ClientData)interval_dup(wrd, s));
133: }
134: }
1.1 deraadt 135:
1.11 ! espie 136: /*
1.1 deraadt 137: *-----------------------------------------------------------------------
138: * For_Eval --
139: * Evaluate the for loop in the passed line. The line
140: * looks like this:
141: * .for <variable> in <varlist>
142: *
143: * Results:
1.11 ! espie 144: * Loop structure, to accumulate further lines.
! 145: * NULL if this was not a for loop after all.
1.1 deraadt 146: *-----------------------------------------------------------------------
147: */
1.11 ! espie 148:
! 149: For *
! 150: For_Eval(line)
1.1 deraadt 151: char *line; /* Line to parse */
152: {
1.11 ! espie 153: char *ptr = line;
! 154: char *wrd;
! 155: char *sub;
! 156: char *endVar;
! 157: For *arg;
! 158:
! 159: for (ptr++; *ptr && isspace(*ptr); ptr++)
! 160: continue;
! 161: /* If we are not in a for loop quickly determine if the statement is
! 162: * a for. */
! 163: if (ptr[0] != 'f' || ptr[1] != 'o' || ptr[2] != 'r' ||
! 164: !isspace(ptr[3]))
! 165: return NULL;
! 166: ptr += 4;
! 167:
! 168: while (*ptr && isspace(*ptr))
! 169: ptr++;
! 170:
! 171: /* We found a for loop, and now we are going to parse it. */
! 172:
! 173: /* Grab the variable. */
! 174: for (wrd = ptr; *ptr && !isspace(*ptr); ptr++)
! 175: continue;
! 176: if (ptr - wrd == 0) {
! 177: Parse_Error(PARSE_FATAL, "missing variable in for");
! 178: return 0;
! 179: }
! 180: endVar = ptr++;
1.1 deraadt 181:
1.11 ! espie 182: while (*ptr && isspace(*ptr))
! 183: ptr++;
1.1 deraadt 184:
1.11 ! espie 185: /* Grab the `in'. */
! 186: if (ptr[0] != 'i' || ptr[1] != 'n' ||
! 187: !isspace(ptr[2])) {
! 188: Parse_Error(PARSE_FATAL, "missing `in' in for");
! 189: printf("%s\n", ptr);
! 190: return NULL;
! 191: }
! 192: ptr += 3;
1.1 deraadt 193:
1.11 ! espie 194: /* .for loop is go, collate what we need. */
! 195: arg = emalloc(sizeof(*arg));
! 196: arg->var = interval_dup(wrd, endVar);
1.1 deraadt 197:
1.11 ! espie 198: /* Make a list with the remaining words. */
! 199: sub = Var_Subst(NULL, ptr, VAR_GLOBAL, FALSE);
! 200: if (DEBUG(FOR))
! 201: (void)fprintf(stderr, "For: Iterator %s List %s\n", arg->var, sub);
1.3 millert 202:
1.11 ! espie 203: arg->lst = Lst_Init(FALSE);
! 204: build_words_list(arg->lst, sub);
! 205: free(sub);
! 206: arg->lineno = Parse_Getlineno();
! 207: arg->level = 1;
! 208: Buf_Init(&arg->buf, 0);
1.1 deraadt 209:
1.11 ! espie 210: return arg;
! 211: }
1.1 deraadt 212:
1.11 ! espie 213:
! 214: /*-
! 215: *-----------------------------------------------------------------------
! 216: * For_Accumulate --
! 217: * Accumulate lines in a for loop, until we find the matching endfor.
! 218: *
! 219: * Results:
! 220: * TRUE: keep accumulating lines.
! 221: * FALSE: We found the matching .endfor
! 222: *
! 223: * Side Effects:
! 224: * Accumulate lines in arg.
! 225: *-----------------------------------------------------------------------
! 226: */
! 227: Boolean
! 228: For_Accumulate(arg, line)
! 229: For *arg;
! 230: const char *line; /* Line to parse */
! 231: {
! 232: const char *ptr = line;
1.1 deraadt 233:
1.11 ! espie 234: assert(arg->level > 0);
1.1 deraadt 235:
1.11 ! espie 236: if (*ptr == '.') {
1.1 deraadt 237:
1.11 ! espie 238: for (ptr++; *ptr && isspace(*ptr); ptr++)
1.1 deraadt 239: continue;
240:
241: if (strncmp(ptr, "endfor", 6) == 0 &&
1.11 ! espie 242: (isspace(ptr[6]) || !ptr[6])) {
1.1 deraadt 243: if (DEBUG(FOR))
1.11 ! espie 244: (void)fprintf(stderr, "For: end for %lu\n", arg->level);
! 245: /* If matching endfor, don't add line to buffer. */
! 246: if (--arg->level == 0)
! 247: return FALSE;
1.1 deraadt 248: }
249: else if (strncmp(ptr, "for", 3) == 0 &&
1.11 ! espie 250: isspace(ptr[3])) {
! 251: arg->level++;
1.1 deraadt 252: if (DEBUG(FOR))
1.11 ! espie 253: (void)fprintf(stderr, "For: new loop %lu\n", arg->level);
1.1 deraadt 254: }
255: }
1.11 ! espie 256: Buf_AddString(&arg->buf, line);
! 257: Buf_AddChar(&arg->buf, '\n');
! 258: return TRUE;
! 259: }
1.1 deraadt 260:
261:
262: /*-
263: *-----------------------------------------------------------------------
264: * ForExec --
265: * Expand the for loop for this index and push it in the Makefile
266: *-----------------------------------------------------------------------
267: */
268: static int
269: ForExec(namep, argp)
270: ClientData namep;
271: ClientData argp;
272: {
1.11 ! espie 273: char *name = (char *)namep;
! 274: For *arg = (For *)argp;
! 275:
1.1 deraadt 276: Var_Set(arg->var, name, VAR_GLOBAL);
277: if (DEBUG(FOR))
1.11 ! espie 278: (void)fprintf(stderr, "--- %s = %s\n", arg->var, name);
! 279: Parse_FromString(Var_Subst(arg->var, arg->text, VAR_GLOBAL, FALSE),
! 280: arg->lineno);
1.1 deraadt 281: Var_Delete(arg->var, VAR_GLOBAL);
282: return 0;
283: }
284:
285:
286: /*-
287: *-----------------------------------------------------------------------
288: * For_Run --
1.11 ! espie 289: * Run the for loop, pushing expanded lines for reparse
1.1 deraadt 290: *-----------------------------------------------------------------------
291: */
1.11 ! espie 292:
1.1 deraadt 293: void
1.11 ! espie 294: For_Run(arg)
! 295: For *arg;
1.1 deraadt 296: {
1.11 ! espie 297: arg->text = Buf_Retrieve(&arg->buf);
1.1 deraadt 298:
1.11 ! espie 299: Lst_ForEach(arg->lst, ForExec, (ClientData)arg);
! 300: free(arg->var);
! 301: free(arg->text);
! 302: Lst_Destroy(arg->lst, (void (*) __P((ClientData)))free);
! 303: free(arg);
1.1 deraadt 304: }