1141104Sharti/*-
294589Sobrien * Copyright (c) 1993
394589Sobrien *	The Regents of the University of California.  All rights reserved.
41590Srgrimes *
594589Sobrien * This code is derived from software contributed to Berkeley by
694589Sobrien * Christos Zoulas.
794589Sobrien *
81590Srgrimes * Redistribution and use in source and binary forms, with or without
91590Srgrimes * modification, are permitted provided that the following conditions
101590Srgrimes * are met:
111590Srgrimes * 1. Redistributions of source code must retain the above copyright
121590Srgrimes *    notice, this list of conditions and the following disclaimer.
131590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141590Srgrimes *    notice, this list of conditions and the following disclaimer in the
151590Srgrimes *    documentation and/or other materials provided with the distribution.
16141104Sharti * 3. Neither the name of the University nor the names of its contributors
171590Srgrimes *    may be used to endorse or promote products derived from this software
181590Srgrimes *    without specific prior written permission.
191590Srgrimes *
201590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
211590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
221590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
231590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
241590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
251590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
261590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
271590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
281590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
291590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
301590Srgrimes * SUCH DAMAGE.
3162833Swsanchez *
3262833Swsanchez * @(#)for.c	8.1 (Berkeley) 6/6/93
331590Srgrimes */
341590Srgrimes
3562833Swsanchez#include <sys/cdefs.h>
3694587Sobrien__FBSDID("$FreeBSD$");
371590Srgrimes
381590Srgrimes/*-
391590Srgrimes * for.c --
401590Srgrimes *	Functions to handle loops in a makefile.
411590Srgrimes *
421590Srgrimes * Interface:
431590Srgrimes *	For_Eval 	Evaluate the loop in the passed line.
441590Srgrimes *	For_Run		Run accumulated loop
451590Srgrimes *
461590Srgrimes */
471590Srgrimes
48141104Sharti#include <ctype.h>
49141104Sharti#include <stdlib.h>
50141104Sharti#include <string.h>
511590Srgrimes
52141104Sharti#include "buf.h"
53141104Sharti#include "for.h"
54141104Sharti#include "globals.h"
55141104Sharti#include "lst.h"
56141104Sharti#include "parse.h"
57177545Sru#include "str.h"
58141104Sharti#include "util.h"
59141104Sharti#include "var.h"
60141104Sharti
611590Srgrimes/*
621590Srgrimes * For statements are of the form:
631590Srgrimes *
641590Srgrimes * .for <variable> in <varlist>
651590Srgrimes * ...
661590Srgrimes * .endfor
671590Srgrimes *
681590Srgrimes * The trick is to look for the matching end inside for for loop
691590Srgrimes * To do that, we count the current nesting level of the for loops.
701590Srgrimes * and the .endfor statements, accumulating all the statements between
718874Srgrimes * the initial .for loop and the matching .endfor;
721590Srgrimes * then we evaluate the for loop for each variable in the varlist.
731590Srgrimes */
741590Srgrimes
75142298Shartistatic int	forLevel = 0;	/* Nesting level */
76142298Shartistatic char	*forVar;	/* Iteration variable */
77142298Shartistatic Buffer	*forBuf;	/* Commands in loop */
78142298Shartistatic Lst	forLst;		/* List of items */
791590Srgrimes
80144894Sharti/**
81144894Sharti * For_For
821590Srgrimes *	Evaluate the for loop in the passed line. The line
831590Srgrimes *	looks like this:
841590Srgrimes *	    .for <variable> in <varlist>
85144894Sharti *	The line pointer points just behind the for.
861590Srgrimes *
871590Srgrimes * Results:
88144894Sharti *	TRUE: Syntax ok.
89144894Sharti *	FALSE: Syntax error.
901590Srgrimes */
91144894ShartiBoolean
92144894ShartiFor_For(char *line)
931590Srgrimes{
94142298Sharti	char	*ptr;
95144894Sharti	char	*wrd;
96142298Sharti	char	*sub;
97144894Sharti	Buffer	*buf;
98144894Sharti	size_t	varlen;
99177545Sru	int	i;
100177545Sru	ArgArray words;
1011590Srgrimes
102142298Sharti	ptr = line;
1031590Srgrimes
104144894Sharti	/*
105144894Sharti	 * Skip space between for and the variable.
106144894Sharti	 */
107144894Sharti	for (ptr++; *ptr && isspace((u_char)*ptr); ptr++)
108144894Sharti		;
1091590Srgrimes
110144894Sharti	/*
111144894Sharti	 * Grab the variable
112144894Sharti	 */
113144894Sharti	for (wrd = ptr; *ptr && !isspace((u_char)*ptr); ptr++)
114144894Sharti		;
1151590Srgrimes
116144894Sharti	buf = Buf_Init(0);
117144894Sharti	Buf_AppendRange(buf, wrd, ptr);
118144894Sharti	forVar = Buf_GetAll(buf, &varlen);
1198874Srgrimes
120144894Sharti	if (varlen == 0) {
121144894Sharti		Buf_Destroy(buf, TRUE);
122144894Sharti		Parse_Error(PARSE_FATAL, "missing variable in for");
123144894Sharti		return (FALSE);
124144894Sharti	}
125144894Sharti	Buf_Destroy(buf, FALSE);
1268874Srgrimes
127144894Sharti	/*
128144894Sharti	 * Skip to 'in'.
129144894Sharti	 */
130144894Sharti	while (*ptr && isspace((u_char)*ptr))
131144894Sharti		ptr++;
1321590Srgrimes
133144894Sharti	/*
134144894Sharti	 * Grab the `in'
135144894Sharti	 */
136144894Sharti	if (ptr[0] != 'i' || ptr[1] != 'n' || !isspace((u_char)ptr[2])) {
137144894Sharti		free(forVar);
138144894Sharti		Parse_Error(PARSE_FATAL, "missing `in' in for");
139144894Sharti		fprintf(stderr, "%s\n", ptr);
140144894Sharti		return (FALSE);
141144894Sharti	}
142144894Sharti	ptr += 3;
1431590Srgrimes
144144894Sharti	/*
145144894Sharti	 * Skip to values
146144894Sharti	 */
147144894Sharti	while (*ptr && isspace((u_char)*ptr))
148144894Sharti		ptr++;
1491590Srgrimes
150144894Sharti	/*
151144894Sharti	 * Make a list with the remaining words
152144894Sharti	 */
153146027Sharti	sub = Buf_Peel(Var_Subst(ptr, VAR_CMD, FALSE));
154177545Sru	brk_string(&words, sub, FALSE);
155144894Sharti	Lst_Init(&forLst);
156177545Sru	for (i = 1; i < words.argc; i++) {
157177545Sru		if (words.argv[i][0] != '\0')
158177545Sru			Lst_AtFront(&forLst, estrdup(words.argv[i]));
159144894Sharti	}
160177545Sru	ArgArray_Done(&words);
161144894Sharti	DEBUGF(FOR, ("For: Iterator %s List %s\n", forVar, sub));
162144894Sharti	free(sub);
1638874Srgrimes
164144894Sharti	forBuf = Buf_Init(0);
165144894Sharti	forLevel++;
166144894Sharti	return (TRUE);
167144894Sharti}
168144894Sharti
169144894Sharti/**
170144894Sharti * For_Eval
171144894Sharti *	Eat a line of the .for body looking for embedded .for loops
172144894Sharti *	and the .endfor
173144894Sharti */
174144894ShartiBoolean
175144894ShartiFor_Eval(char *line)
176144894Sharti{
177144894Sharti	char *ptr;
178144894Sharti
179144894Sharti	ptr = line;
180144894Sharti
181142298Sharti	if (*ptr == '.') {
182142298Sharti		/*
183142298Sharti		 * Need to check for 'endfor' and 'for' to find the end
184142298Sharti		 * of our loop or to find embedded for loops.
185142298Sharti		 */
186144894Sharti		for (ptr++; *ptr != '\0' && isspace((u_char)*ptr); ptr++)
187142298Sharti			;
1881590Srgrimes
189144894Sharti		/* XXX the isspace is wrong */
190142298Sharti		if (strncmp(ptr, "endfor", 6) == 0 &&
191144894Sharti		    (isspace((u_char)ptr[6]) || ptr[6] == '\0')) {
192142298Sharti			DEBUGF(FOR, ("For: end for %d\n", forLevel));
193144894Sharti			if (forLevel == 0) {
194144894Sharti				/* should not be here */
195144894Sharti				abort();
196142298Sharti			}
197144894Sharti			forLevel--;
1981590Srgrimes
199142298Sharti		} else if (strncmp(ptr, "for", 3) == 0 &&
200144894Sharti		    isspace((u_char)ptr[3])) {
201142298Sharti			forLevel++;
202142298Sharti			DEBUGF(FOR, ("For: new loop %d\n", forLevel));
203142298Sharti		}
2041590Srgrimes	}
205142298Sharti
206142298Sharti	if (forLevel != 0) {
207142298Sharti		/*
208142298Sharti		 * Still in loop - append the line
209142298Sharti		 */
210142298Sharti		Buf_Append(forBuf, line);
211142298Sharti		Buf_AddByte(forBuf, (Byte)'\n');
212144894Sharti		return (TRUE);
2131590Srgrimes	}
2141590Srgrimes
215144894Sharti	return (FALSE);
2161590Srgrimes}
2171590Srgrimes
2181590Srgrimes/*-
2191590Srgrimes *-----------------------------------------------------------------------
2201590Srgrimes * For_Run --
221228992Suqs *	Run the for loop, imitating the actions of an include file
2221590Srgrimes *
2231590Srgrimes * Results:
2241590Srgrimes *	None.
2251590Srgrimes *
2261590Srgrimes * Side Effects:
227142299Sharti *	The values of the variables forLst, forVar and forBuf are freed.
2281590Srgrimes *
2291590Srgrimes *-----------------------------------------------------------------------
2301590Srgrimes */
2311590Srgrimesvoid
232126824SruFor_Run(int lineno)
2331590Srgrimes{
234142299Sharti	Lst		values;	/* list of values for the variable */
235142299Sharti	char		*var;	/* the variable's name */
236142299Sharti	Buffer		*buf;	/* the contents of the for loop */
237142299Sharti	const char	*val;	/* current value of loop variable */
238142299Sharti	LstNode		*ln;
239142457Sharti	char		*str;
2401590Srgrimes
241142298Sharti	if (forVar == NULL || forBuf == NULL)
242142298Sharti		return;
243138916Sharti
244142299Sharti	/* copy the global variables to have them free for embedded fors */
245142299Sharti	var = forVar;
246142299Sharti	buf = forBuf;
247142299Sharti	Lst_Init(&values);
248142299Sharti	Lst_Concat(&values, &forLst, LST_CONCLINK);
249138916Sharti
250142298Sharti	forVar = NULL;
251142298Sharti	forBuf = NULL;
2521590Srgrimes
253142299Sharti	LST_FOREACH(ln, &values) {
254142299Sharti		val = Lst_Datum(ln);
255186558Sobrien		Var_SetGlobal(var, val);
2561590Srgrimes
257142299Sharti		DEBUGF(FOR, ("--- %s = %s\n", var, val));
258146048Sharti		str = Buf_Peel(Var_SubstOnly(var, Buf_Data(buf), FALSE));
259142299Sharti
260142457Sharti		Parse_FromString(str, lineno);
261142299Sharti		Var_Delete(var, VAR_GLOBAL);
262142299Sharti	}
263142299Sharti
264142299Sharti	free(var);
265142299Sharti	Lst_Destroy(&values, free);
266142299Sharti	Buf_Destroy(buf, TRUE);
2671590Srgrimes}
268