for.c revision 146027
1/*- 2 * Copyright (c) 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Christos Zoulas. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * @(#)for.c 8.1 (Berkeley) 6/6/93 33 */ 34 35#include <sys/cdefs.h> 36__FBSDID("$FreeBSD: head/usr.bin/make/for.c 146027 2005-05-09 14:06:04Z harti $"); 37 38/*- 39 * for.c -- 40 * Functions to handle loops in a makefile. 41 * 42 * Interface: 43 * For_Eval Evaluate the loop in the passed line. 44 * For_Run Run accumulated loop 45 * 46 */ 47 48#include <ctype.h> 49#include <stdlib.h> 50#include <string.h> 51 52#include "buf.h" 53#include "dir.h" 54#include "for.h" 55#include "globals.h" 56#include "lst.h" 57#include "make.h" 58#include "parse.h" 59#include "util.h" 60#include "var.h" 61 62/* 63 * For statements are of the form: 64 * 65 * .for <variable> in <varlist> 66 * ... 67 * .endfor 68 * 69 * The trick is to look for the matching end inside for for loop 70 * To do that, we count the current nesting level of the for loops. 71 * and the .endfor statements, accumulating all the statements between 72 * the initial .for loop and the matching .endfor; 73 * then we evaluate the for loop for each variable in the varlist. 74 */ 75 76static int forLevel = 0; /* Nesting level */ 77static char *forVar; /* Iteration variable */ 78static Buffer *forBuf; /* Commands in loop */ 79static Lst forLst; /* List of items */ 80 81/** 82 * For_For 83 * Evaluate the for loop in the passed line. The line 84 * looks like this: 85 * .for <variable> in <varlist> 86 * The line pointer points just behind the for. 87 * 88 * Results: 89 * TRUE: Syntax ok. 90 * FALSE: Syntax error. 91 */ 92Boolean 93For_For(char *line) 94{ 95 char *ptr; 96 char *wrd; 97 char *sub; 98 Buffer *buf; 99 size_t varlen; 100 101 ptr = line; 102 103 /* 104 * Skip space between for and the variable. 105 */ 106 for (ptr++; *ptr && isspace((u_char)*ptr); ptr++) 107 ; 108 109 /* 110 * Grab the variable 111 */ 112 for (wrd = ptr; *ptr && !isspace((u_char)*ptr); ptr++) 113 ; 114 115 buf = Buf_Init(0); 116 Buf_AppendRange(buf, wrd, ptr); 117 forVar = Buf_GetAll(buf, &varlen); 118 119 if (varlen == 0) { 120 Buf_Destroy(buf, TRUE); 121 Parse_Error(PARSE_FATAL, "missing variable in for"); 122 return (FALSE); 123 } 124 Buf_Destroy(buf, FALSE); 125 126 /* 127 * Skip to 'in'. 128 */ 129 while (*ptr && isspace((u_char)*ptr)) 130 ptr++; 131 132 /* 133 * Grab the `in' 134 */ 135 if (ptr[0] != 'i' || ptr[1] != 'n' || !isspace((u_char)ptr[2])) { 136 free(forVar); 137 Parse_Error(PARSE_FATAL, "missing `in' in for"); 138 fprintf(stderr, "%s\n", ptr); 139 return (FALSE); 140 } 141 ptr += 3; 142 143 /* 144 * Skip to values 145 */ 146 while (*ptr && isspace((u_char)*ptr)) 147 ptr++; 148 149 /* 150 * Make a list with the remaining words 151 * XXX should use brk_string here. 152 */ 153 sub = Buf_Peel(Var_Subst(ptr, VAR_CMD, FALSE)); 154 for (ptr = sub; *ptr != '\0' && isspace((u_char)*ptr); ptr++) 155 ; 156 157 Lst_Init(&forLst); 158 buf = Buf_Init(0); 159 for (wrd = ptr; *ptr != '\0'; ptr++) { 160 if (isspace((u_char)*ptr)) { 161 Buf_AppendRange(buf, wrd, ptr); 162 Lst_AtFront(&forLst, Buf_Peel(buf)); 163 164 buf = Buf_Init(0); 165 while (*ptr != '\0' && isspace((u_char)*ptr)) 166 ptr++; 167 wrd = ptr--; 168 } 169 } 170 DEBUGF(FOR, ("For: Iterator %s List %s\n", forVar, sub)); 171 172 if (ptr - wrd > 0) { 173 Buf_AppendRange(buf, wrd, ptr); 174 Lst_AtFront(&forLst, Buf_Peel(buf)); 175 } else { 176 Buf_Destroy(buf, TRUE); 177 } 178 free(sub); 179 180 forBuf = Buf_Init(0); 181 forLevel++; 182 return (TRUE); 183} 184 185/** 186 * For_Eval 187 * Eat a line of the .for body looking for embedded .for loops 188 * and the .endfor 189 */ 190Boolean 191For_Eval(char *line) 192{ 193 char *ptr; 194 195 ptr = line; 196 197 if (*ptr == '.') { 198 /* 199 * Need to check for 'endfor' and 'for' to find the end 200 * of our loop or to find embedded for loops. 201 */ 202 for (ptr++; *ptr != '\0' && isspace((u_char)*ptr); ptr++) 203 ; 204 205 /* XXX the isspace is wrong */ 206 if (strncmp(ptr, "endfor", 6) == 0 && 207 (isspace((u_char)ptr[6]) || ptr[6] == '\0')) { 208 DEBUGF(FOR, ("For: end for %d\n", forLevel)); 209 if (forLevel == 0) { 210 /* should not be here */ 211 abort(); 212 } 213 forLevel--; 214 215 } else if (strncmp(ptr, "for", 3) == 0 && 216 isspace((u_char)ptr[3])) { 217 forLevel++; 218 DEBUGF(FOR, ("For: new loop %d\n", forLevel)); 219 } 220 } 221 222 if (forLevel != 0) { 223 /* 224 * Still in loop - append the line 225 */ 226 Buf_Append(forBuf, line); 227 Buf_AddByte(forBuf, (Byte)'\n'); 228 return (TRUE); 229 } 230 231 return (FALSE); 232} 233 234/*- 235 *----------------------------------------------------------------------- 236 * For_Run -- 237 * Run the for loop, immitating the actions of an include file 238 * 239 * Results: 240 * None. 241 * 242 * Side Effects: 243 * The values of the variables forLst, forVar and forBuf are freed. 244 * 245 *----------------------------------------------------------------------- 246 */ 247void 248For_Run(int lineno) 249{ 250 Lst values; /* list of values for the variable */ 251 char *var; /* the variable's name */ 252 Buffer *buf; /* the contents of the for loop */ 253 const char *val; /* current value of loop variable */ 254 LstNode *ln; 255 char *str; 256 257 if (forVar == NULL || forBuf == NULL) 258 return; 259 260 /* copy the global variables to have them free for embedded fors */ 261 var = forVar; 262 buf = forBuf; 263 Lst_Init(&values); 264 Lst_Concat(&values, &forLst, LST_CONCLINK); 265 266 forVar = NULL; 267 forBuf = NULL; 268 269 LST_FOREACH(ln, &values) { 270 val = Lst_Datum(ln); 271 Var_Set(var, val, VAR_GLOBAL); 272 273 DEBUGF(FOR, ("--- %s = %s\n", var, val)); 274 str = Buf_Peel(Var_SubstOnly(var, Buf_Data(buf), 275 VAR_GLOBAL, FALSE)); 276 277 Parse_FromString(str, lineno); 278 Var_Delete(var, VAR_GLOBAL); 279 } 280 281 free(var); 282 Lst_Destroy(&values, free); 283 Buf_Destroy(buf, TRUE); 284} 285