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