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>
| 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 146048 2005-05-10 12:02:15Z harti $");
| 36__FBSDID("$FreeBSD: head/usr.bin/make/for.c 177545 2008-03-24 12:33:28Z ru $");
|
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"
| 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 "str.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;
| 60#include "util.h" 61#include "var.h" 62 63/* 64 * For statements are of the form: 65 * 66 * .for <variable> in <varlist> 67 * ... 68 * .endfor 69 * 70 * The trick is to look for the matching end inside for for loop 71 * To do that, we count the current nesting level of the for loops. 72 * and the .endfor statements, accumulating all the statements between 73 * the initial .for loop and the matching .endfor; 74 * then we evaluate the for loop for each variable in the varlist. 75 */ 76 77static int forLevel = 0; /* Nesting level */ 78static char *forVar; /* Iteration variable */ 79static Buffer *forBuf; /* Commands in loop */ 80static Lst forLst; /* List of items */ 81 82/** 83 * For_For 84 * Evaluate the for loop in the passed line. The line 85 * looks like this: 86 * .for <variable> in <varlist> 87 * The line pointer points just behind the for. 88 * 89 * Results: 90 * TRUE: Syntax ok. 91 * FALSE: Syntax error. 92 */ 93Boolean 94For_For(char *line) 95{ 96 char *ptr; 97 char *wrd; 98 char *sub; 99 Buffer *buf; 100 size_t varlen;
|
| 101 int i; 102 ArgArray words;
|
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
| 103 104 ptr = line; 105 106 /* 107 * Skip space between for and the variable. 108 */ 109 for (ptr++; *ptr && isspace((u_char)*ptr); ptr++) 110 ; 111 112 /* 113 * Grab the variable 114 */ 115 for (wrd = ptr; *ptr && !isspace((u_char)*ptr); ptr++) 116 ; 117 118 buf = Buf_Init(0); 119 Buf_AppendRange(buf, wrd, ptr); 120 forVar = Buf_GetAll(buf, &varlen); 121 122 if (varlen == 0) { 123 Buf_Destroy(buf, TRUE); 124 Parse_Error(PARSE_FATAL, "missing variable in for"); 125 return (FALSE); 126 } 127 Buf_Destroy(buf, FALSE); 128 129 /* 130 * Skip to 'in'. 131 */ 132 while (*ptr && isspace((u_char)*ptr)) 133 ptr++; 134 135 /* 136 * Grab the `in' 137 */ 138 if (ptr[0] != 'i' || ptr[1] != 'n' || !isspace((u_char)ptr[2])) { 139 free(forVar); 140 Parse_Error(PARSE_FATAL, "missing `in' in for"); 141 fprintf(stderr, "%s\n", ptr); 142 return (FALSE); 143 } 144 ptr += 3; 145 146 /* 147 * Skip to values 148 */ 149 while (*ptr && isspace((u_char)*ptr)) 150 ptr++; 151 152 /* 153 * 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 */ 155 sub = Buf_Peel(Var_Subst(ptr, VAR_CMD, FALSE));
|
154 for (ptr = sub; *ptr != '\0' && isspace((u_char)*ptr); ptr++) 155 ; 156
| 156 brk_string(&words, sub, FALSE);
|
157 Lst_Init(&forLst);
| 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 }
| 158 for (i = 1; i < words.argc; i++) { 159 if (words.argv[i][0] != '\0') 160 Lst_AtFront(&forLst, estrdup(words.argv[i]));
|
169 }
| 161 }
|
| 162 ArgArray_Done(&words);
|
170 DEBUGF(FOR, ("For: Iterator %s List %s\n", forVar, sub));
| 163 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), FALSE)); 275 276 Parse_FromString(str, lineno); 277 Var_Delete(var, VAR_GLOBAL); 278 } 279 280 free(var); 281 Lst_Destroy(&values, free); 282 Buf_Destroy(buf, TRUE); 283}
| 164 free(sub); 165 166 forBuf = Buf_Init(0); 167 forLevel++; 168 return (TRUE); 169} 170 171/** 172 * For_Eval 173 * Eat a line of the .for body looking for embedded .for loops 174 * and the .endfor 175 */ 176Boolean 177For_Eval(char *line) 178{ 179 char *ptr; 180 181 ptr = line; 182 183 if (*ptr == '.') { 184 /* 185 * Need to check for 'endfor' and 'for' to find the end 186 * of our loop or to find embedded for loops. 187 */ 188 for (ptr++; *ptr != '\0' && isspace((u_char)*ptr); ptr++) 189 ; 190 191 /* XXX the isspace is wrong */ 192 if (strncmp(ptr, "endfor", 6) == 0 && 193 (isspace((u_char)ptr[6]) || ptr[6] == '\0')) { 194 DEBUGF(FOR, ("For: end for %d\n", forLevel)); 195 if (forLevel == 0) { 196 /* should not be here */ 197 abort(); 198 } 199 forLevel--; 200 201 } else if (strncmp(ptr, "for", 3) == 0 && 202 isspace((u_char)ptr[3])) { 203 forLevel++; 204 DEBUGF(FOR, ("For: new loop %d\n", forLevel)); 205 } 206 } 207 208 if (forLevel != 0) { 209 /* 210 * Still in loop - append the line 211 */ 212 Buf_Append(forBuf, line); 213 Buf_AddByte(forBuf, (Byte)'\n'); 214 return (TRUE); 215 } 216 217 return (FALSE); 218} 219 220/*- 221 *----------------------------------------------------------------------- 222 * For_Run -- 223 * Run the for loop, immitating the actions of an include file 224 * 225 * Results: 226 * None. 227 * 228 * Side Effects: 229 * The values of the variables forLst, forVar and forBuf are freed. 230 * 231 *----------------------------------------------------------------------- 232 */ 233void 234For_Run(int lineno) 235{ 236 Lst values; /* list of values for the variable */ 237 char *var; /* the variable's name */ 238 Buffer *buf; /* the contents of the for loop */ 239 const char *val; /* current value of loop variable */ 240 LstNode *ln; 241 char *str; 242 243 if (forVar == NULL || forBuf == NULL) 244 return; 245 246 /* copy the global variables to have them free for embedded fors */ 247 var = forVar; 248 buf = forBuf; 249 Lst_Init(&values); 250 Lst_Concat(&values, &forLst, LST_CONCLINK); 251 252 forVar = NULL; 253 forBuf = NULL; 254 255 LST_FOREACH(ln, &values) { 256 val = Lst_Datum(ln); 257 Var_Set(var, val, VAR_GLOBAL); 258 259 DEBUGF(FOR, ("--- %s = %s\n", var, val)); 260 str = Buf_Peel(Var_SubstOnly(var, Buf_Data(buf), FALSE)); 261 262 Parse_FromString(str, lineno); 263 Var_Delete(var, VAR_GLOBAL); 264 } 265 266 free(var); 267 Lst_Destroy(&values, free); 268 Buf_Destroy(buf, TRUE); 269}
|