Annotation of src/usr.bin/make/for.c, Revision 1.28
1.24 espie 1: /* $OpenPackages$ */
1.28 ! espie 2: /* $OpenBSD: for.c,v 1.27 2002/06/11 21:12:11 espie Exp $ */
1.24 espie 3: /* $NetBSD: for.c,v 1.4 1996/11/06 17:59:05 christos Exp $ */
1.1 deraadt 4:
5: /*
1.6 espie 6: * Copyright (c) 1999 Marc Espie.
7: *
8: * Extensive code modifications for the OpenBSD project.
9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
18: *
19: * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS
20: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OPENBSD
23: * PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30: */
31:
32: /*
1.1 deraadt 33: * Copyright (c) 1992, The Regents of the University of California.
34: * All rights reserved.
35: *
36: * Redistribution and use in source and binary forms, with or without
37: * modification, are permitted provided that the following conditions
38: * are met:
39: * 1. Redistributions of source code must retain the above copyright
40: * notice, this list of conditions and the following disclaimer.
41: * 2. Redistributions in binary form must reproduce the above copyright
42: * notice, this list of conditions and the following disclaimer in the
43: * documentation and/or other materials provided with the distribution.
44: * 3. All advertising materials mentioning features or use of this software
45: * must display the following acknowledgement:
46: * This product includes software developed by the University of
47: * California, Berkeley and its contributors.
48: * 4. Neither the name of the University nor the names of its contributors
49: * may be used to endorse or promote products derived from this software
50: * without specific prior written permission.
51: *
52: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62: * SUCH DAMAGE.
63: */
64:
1.25 espie 65: #include <assert.h>
66: #include <ctype.h>
67: #include <stddef.h>
68: #include <stdio.h>
1.26 espie 69: #include <stdlib.h>
1.25 espie 70: #include <string.h>
71: #include "config.h"
72: #include "defines.h"
73: #include "buf.h"
74: #include "for.h"
75: #include "lst.h"
76: #include "error.h"
77: #include "var.h"
78: #include "lowparse.h"
79: #include "str.h"
80: #include "memory.h"
1.1 deraadt 81:
82: /*
83: * For statements are of the form:
84: *
1.24 espie 85: * .for <variable> [variable...] in <varlist>
1.1 deraadt 86: * ...
87: * .endfor
88: *
1.11 espie 89: * The trick is to look for the matching .end inside .for loops.
90: * To do that, we keep track of the nesting level of .for loops
91: * and matching .endfor statements, accumulating all statements between
92: * the initial .for loop and the matching .endfor,
93: * then we evaluate the .for loop for each variable in the varlist.
1.1 deraadt 94: */
95:
1.11 espie 96: /* State of a for loop. */
97: struct For_ {
1.25 espie 98: char *text; /* Unexpanded text */
99: LIST vars; /* List of variables */
100: LstNode var; /* Current var */
101: int nvars; /* Total number of vars */
1.24 espie 102: LIST lst; /* List of items */
1.13 espie 103: size_t guess; /* Estimated expansion size */
1.24 espie 104: BUFFER buf; /* Accumulating text */
105: unsigned long lineno; /* Line number at start of loop */
1.11 espie 106: unsigned long level; /* Nesting level */
1.25 espie 107: bool freeold;
1.11 espie 108: };
1.1 deraadt 109:
1.25 espie 110: /* ForExec(value, handle);
111: * Expands next variable in loop sequence described by handle to value. */
1.24 espie 112: static void ForExec(void *, void *);
1.25 espie 113:
114: /* n = build_words_list(lst, s);
115: * Cuts string into words, pushes words into list, in reverse order,
116: * because Parse_FromString works as a stack.
117: * Returns the number of words. */
1.24 espie 118: static unsigned long build_words_list(Lst, const char *);
1.1 deraadt 119:
1.24 espie 120: static unsigned long
1.6 espie 121: build_words_list(lst, s)
122: Lst lst;
123: const char *s;
124: {
1.22 espie 125: const char *end, *wrd;
1.24 espie 126: unsigned long n;
1.1 deraadt 127:
1.24 espie 128: n = 0;
1.22 espie 129: end = s;
130:
1.24 espie 131: while ((wrd = iterate_words(&end)) != NULL) {
1.25 espie 132: Lst_AtFront(lst, escape_dupi(wrd, end, "\"'"));
1.24 espie 133: n++;
134: }
135: return n;
1.6 espie 136: }
1.1 deraadt 137:
1.11 espie 138: For *
139: For_Eval(line)
1.24 espie 140: const char *line; /* Line to parse */
1.1 deraadt 141: {
1.24 espie 142: const char *ptr = line;
143: const char *wrd;
144: char *sub;
145: const char *endVar;
1.11 espie 146: For *arg;
1.24 espie 147: unsigned long n;
1.11 espie 148:
149: while (*ptr && isspace(*ptr))
150: ptr++;
151:
1.28 ! espie 152: /* Parse loop. */
1.11 espie 153:
1.24 espie 154: arg = emalloc(sizeof(*arg));
155: arg->nvars = 0;
156: Lst_Init(&arg->vars);
157:
158: for (;;) {
159: /* Grab the variables. */
160: for (wrd = ptr; *ptr && !isspace(*ptr); ptr++)
161: continue;
162: if (ptr - wrd == 0) {
163: Parse_Error(PARSE_FATAL, "Syntax error in for");
164: return 0;
165: }
166: endVar = ptr++;
167: while (*ptr && isspace(*ptr))
168: ptr++;
1.25 espie 169: /* End of variable list ? */
1.24 espie 170: if (endVar - wrd == 2 && wrd[0] == 'i' && wrd[1] == 'n')
171: break;
1.25 espie 172: Lst_AtEnd(&arg->vars, Str_dupi(wrd, endVar));
1.24 espie 173: arg->nvars++;
174: }
175: if (arg->nvars == 0) {
176: Parse_Error(PARSE_FATAL, "Missing variable in for");
1.11 espie 177: return 0;
178: }
1.1 deraadt 179:
1.11 espie 180: /* Make a list with the remaining words. */
1.25 espie 181: sub = Var_Subst(ptr, NULL, false);
1.24 espie 182: if (DEBUG(FOR)) {
183: LstNode ln;
184: (void)fprintf(stderr, "For: Iterator ");
185: for (ln = Lst_First(&arg->vars); ln != NULL; ln = Lst_Adv(ln))
186: (void)fprintf(stderr, "%s ", (char *)Lst_Datum(ln));
187: (void)fprintf(stderr, "List %s\n", sub);
188: }
1.3 millert 189:
1.18 espie 190: Lst_Init(&arg->lst);
1.24 espie 191: n = build_words_list(&arg->lst, sub);
1.11 espie 192: free(sub);
1.24 espie 193: if (arg->nvars != 1 && n % arg->nvars != 0) {
194: Parse_Error(PARSE_FATAL, "Wrong number of items in for loop");
195: return 0;
196: }
1.11 espie 197: arg->lineno = Parse_Getlineno();
198: arg->level = 1;
199: Buf_Init(&arg->buf, 0);
1.1 deraadt 200:
1.11 espie 201: return arg;
202: }
1.1 deraadt 203:
1.24 espie 204:
1.25 espie 205: bool
1.11 espie 206: For_Accumulate(arg, line)
1.24 espie 207: For *arg;
208: const char *line; /* Line to parse */
1.11 espie 209: {
210: const char *ptr = line;
1.1 deraadt 211:
1.11 espie 212: assert(arg->level > 0);
1.1 deraadt 213:
1.11 espie 214: if (*ptr == '.') {
1.1 deraadt 215:
1.11 espie 216: for (ptr++; *ptr && isspace(*ptr); ptr++)
1.1 deraadt 217: continue;
218:
219: if (strncmp(ptr, "endfor", 6) == 0 &&
1.11 espie 220: (isspace(ptr[6]) || !ptr[6])) {
1.1 deraadt 221: if (DEBUG(FOR))
1.11 espie 222: (void)fprintf(stderr, "For: end for %lu\n", arg->level);
223: /* If matching endfor, don't add line to buffer. */
224: if (--arg->level == 0)
1.25 espie 225: return false;
1.1 deraadt 226: }
227: else if (strncmp(ptr, "for", 3) == 0 &&
1.11 espie 228: isspace(ptr[3])) {
229: arg->level++;
1.1 deraadt 230: if (DEBUG(FOR))
1.11 espie 231: (void)fprintf(stderr, "For: new loop %lu\n", arg->level);
1.1 deraadt 232: }
233: }
1.11 espie 234: Buf_AddString(&arg->buf, line);
235: Buf_AddChar(&arg->buf, '\n');
1.25 espie 236: return true;
1.11 espie 237: }
1.1 deraadt 238:
239:
1.13 espie 240: #define GUESS_EXPANSION 32
1.16 espie 241: static void
1.25 espie 242: ForExec(valuep, argp)
243: void *valuep;
1.17 espie 244: void *argp;
1.1 deraadt 245: {
1.25 espie 246: char *value = (char *)valuep;
1.11 espie 247: For *arg = (For *)argp;
1.24 espie 248: BUFFER buf;
249:
250: /* Parse_FromString pushes stuff back, so we need to go over vars in
251: reverse. */
252: if (arg->var == NULL) {
253: arg->var = Lst_Last(&arg->vars);
254: arg->text = Buf_Retrieve(&arg->buf);
1.25 espie 255: arg->freeold = false;
1.24 espie 256: }
1.11 espie 257:
1.1 deraadt 258: if (DEBUG(FOR))
1.25 espie 259: (void)fprintf(stderr, "--- %s = %s\n", (char *)Lst_Datum(arg->var),
260: value);
1.24 espie 261: Buf_Init(&buf, arg->guess);
1.25 espie 262: Var_SubstVar(&buf, arg->text, Lst_Datum(arg->var), value);
1.24 espie 263: if (arg->freeold)
264: free(arg->text);
265: arg->text = Buf_Retrieve(&buf);
1.25 espie 266: arg->freeold = true;
1.24 espie 267: arg->var = Lst_Rev(arg->var);
268: if (arg->var == NULL)
269: Parse_FromString(arg->text, arg->lineno);
1.1 deraadt 270: }
271:
1.11 espie 272:
1.1 deraadt 273: void
1.11 espie 274: For_Run(arg)
275: For *arg;
1.1 deraadt 276: {
1.11 espie 277: arg->text = Buf_Retrieve(&arg->buf);
1.13 espie 278: arg->guess = Buf_Size(&arg->buf) + GUESS_EXPANSION;
1.1 deraadt 279:
1.24 espie 280: arg->var = NULL;
1.18 espie 281: Lst_ForEach(&arg->lst, ForExec, arg);
1.24 espie 282: Buf_Destroy(&arg->buf);
283: Lst_Destroy(&arg->vars, (SimpleProc)free);
1.18 espie 284: Lst_Destroy(&arg->lst, (SimpleProc)free);
1.11 espie 285: free(arg);
1.1 deraadt 286: }