aboutsummaryrefslogtreecommitdiff
path: root/for.c
diff options
context:
space:
mode:
Diffstat (limited to 'for.c')
-rw-r--r--for.c253
1 files changed, 133 insertions, 120 deletions
diff --git a/for.c b/for.c
index af55179dee8d..5705d9c5de0d 100644
--- a/for.c
+++ b/for.c
@@ -1,4 +1,4 @@
-/* $NetBSD: for.c,v 1.134 2021/01/10 21:20:46 rillig Exp $ */
+/* $NetBSD: for.c,v 1.141 2021/02/04 21:33:13 rillig Exp $ */
/*
* Copyright (c) 1992, The Regents of the University of California.
@@ -29,7 +29,7 @@
* SUCH DAMAGE.
*/
-/*-
+/*
* Handling of .for/.endfor loops in a makefile.
*
* For loops have the form:
@@ -58,9 +58,8 @@
#include "make.h"
/* "@(#)for.c 8.1 (Berkeley) 6/6/93" */
-MAKE_RCSID("$NetBSD: for.c,v 1.134 2021/01/10 21:20:46 rillig Exp $");
+MAKE_RCSID("$NetBSD: for.c,v 1.141 2021/02/04 21:33:13 rillig Exp $");
-static int forLevel = 0; /* Nesting level */
/* One of the variables to the left of the "in" in a .for loop. */
typedef struct ForVar {
@@ -68,10 +67,7 @@ typedef struct ForVar {
size_t nameLen;
} ForVar;
-/*
- * State of a for loop.
- */
-typedef struct For {
+typedef struct ForLoop {
Buffer body; /* Unexpanded body of the loop */
Vector /* of ForVar */ vars; /* Iteration variables */
Words items; /* Substitution items */
@@ -81,22 +77,33 @@ typedef struct For {
* only ${V} and $(V). */
Boolean short_var;
unsigned int sub_next; /* Where to continue iterating */
-} For;
+} ForLoop;
-static For *accumFor; /* Loop being accumulated */
-static void
-ForAddVar(For *f, const char *name, size_t len)
+static ForLoop *accumFor; /* Loop being accumulated */
+static int forLevel = 0; /* Nesting level */
+
+
+static ForLoop *
+ForLoop_New(void)
{
- ForVar *var = Vector_Push(&f->vars);
- var->name = bmake_strldup(name, len);
- var->nameLen = len;
+ ForLoop *f = bmake_malloc(sizeof *f);
+
+ Buf_Init(&f->body);
+ Vector_Init(&f->vars, sizeof(ForVar));
+ f->items.words = NULL;
+ f->items.freeIt = NULL;
+ Buf_Init(&f->curBody);
+ f->short_var = FALSE;
+ f->sub_next = 0;
+
+ return f;
}
static void
-For_Free(For *f)
+ForLoop_Free(ForLoop *f)
{
- Buf_Destroy(&f->body, TRUE);
+ Buf_Done(&f->body);
while (f->vars.len > 0) {
ForVar *var = Vector_Pop(&f->vars);
@@ -105,11 +112,89 @@ For_Free(For *f)
Vector_Done(&f->vars);
Words_Free(f->items);
- Buf_Destroy(&f->curBody, TRUE);
+ Buf_Done(&f->curBody);
free(f);
}
+static void
+ForLoop_AddVar(ForLoop *f, const char *name, size_t len)
+{
+ ForVar *var = Vector_Push(&f->vars);
+ var->name = bmake_strldup(name, len);
+ var->nameLen = len;
+}
+
+static Boolean
+ForLoop_ParseVarnames(ForLoop *f, const char **pp)
+{
+ const char *p = *pp;
+
+ for (;;) {
+ size_t len;
+
+ cpp_skip_whitespace(&p);
+ if (*p == '\0') {
+ Parse_Error(PARSE_FATAL, "missing `in' in for");
+ return FALSE;
+ }
+
+ /*
+ * XXX: This allows arbitrary variable names;
+ * see directive-for.mk.
+ */
+ for (len = 1; p[len] != '\0' && !ch_isspace(p[len]); len++)
+ continue;
+
+ if (len == 2 && p[0] == 'i' && p[1] == 'n') {
+ p += 2;
+ break;
+ }
+ if (len == 1)
+ f->short_var = TRUE;
+
+ ForLoop_AddVar(f, p, len);
+ p += len;
+ }
+
+ if (f->vars.len == 0) {
+ Parse_Error(PARSE_FATAL, "no iteration variables in for");
+ return FALSE;
+ }
+
+ *pp = p;
+ return TRUE;
+}
+
+static Boolean
+ForLoop_ParseItems(ForLoop *f, const char *p)
+{
+ char *items;
+
+ cpp_skip_whitespace(&p);
+
+ if (Var_Subst(p, SCOPE_GLOBAL, VARE_WANTRES, &items) != VPR_OK) {
+ Parse_Error(PARSE_FATAL, "Error in .for loop items");
+ return FALSE;
+ }
+
+ f->items = Str_Words(items, FALSE);
+ free(items);
+
+ if (f->items.len == 1 && f->items.words[0][0] == '\0')
+ f->items.len = 0; /* .for var in ${:U} */
+
+ if (f->items.len != 0 && f->items.len % f->vars.len != 0) {
+ Parse_Error(PARSE_FATAL,
+ "Wrong number of words (%u) in .for "
+ "substitution list with %u variables",
+ (unsigned)f->items.len, (unsigned)f->vars.len);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
static Boolean
IsFor(const char *p)
{
@@ -138,7 +223,7 @@ IsEndfor(const char *p)
int
For_Eval(const char *line)
{
- For *f;
+ ForLoop *f;
const char *p;
p = line + 1; /* skip the '.' */
@@ -153,113 +238,41 @@ For_Eval(const char *line)
}
p += 3;
- /*
- * we found a for loop, and now we are going to parse it.
- */
+ f = ForLoop_New();
- f = bmake_malloc(sizeof *f);
- Buf_Init(&f->body);
- Vector_Init(&f->vars, sizeof(ForVar));
- f->items.words = NULL;
- f->items.freeIt = NULL;
- Buf_Init(&f->curBody);
- f->short_var = FALSE;
- f->sub_next = 0;
-
- /* Grab the variables. Terminate on "in". */
- for (;;) {
- size_t len;
-
- cpp_skip_whitespace(&p);
- if (*p == '\0') {
- Parse_Error(PARSE_FATAL, "missing `in' in for");
- For_Free(f);
- return -1;
- }
-
- /*
- * XXX: This allows arbitrary variable names;
- * see directive-for.mk.
- */
- for (len = 1; p[len] != '\0' && !ch_isspace(p[len]); len++)
- continue;
-
- if (len == 2 && p[0] == 'i' && p[1] == 'n') {
- p += 2;
- break;
- }
- if (len == 1)
- f->short_var = TRUE;
-
- ForAddVar(f, p, len);
- p += len;
- }
-
- if (f->vars.len == 0) {
- Parse_Error(PARSE_FATAL, "no iteration variables in for");
- For_Free(f);
+ if (!ForLoop_ParseVarnames(f, &p)) {
+ ForLoop_Free(f);
return -1;
}
- cpp_skip_whitespace(&p);
-
- {
- char *items;
- if (Var_Subst(p, VAR_GLOBAL, VARE_WANTRES, &items) != VPR_OK) {
- Parse_Error(PARSE_FATAL, "Error in .for loop items");
- f->items.len = 0;
- goto done;
- }
-
- f->items = Str_Words(items, FALSE);
- free(items);
-
- if (f->items.len == 1 && f->items.words[0][0] == '\0')
- f->items.len = 0; /* .for var in ${:U} */
+ if (!ForLoop_ParseItems(f, p)) {
+ /* Continue parsing the .for loop, but don't iterate. */
+ f->items.len = 0;
}
- {
- size_t nitems, nvars;
-
- if ((nitems = f->items.len) > 0 &&
- nitems % (nvars = f->vars.len) != 0) {
- Parse_Error(PARSE_FATAL,
- "Wrong number of words (%u) in .for "
- "substitution list with %u variables",
- (unsigned)nitems, (unsigned)nvars);
- /*
- * Return 'success' so that the body of the .for loop
- * is accumulated.
- * Remove all items so that the loop doesn't iterate.
- */
- f->items.len = 0;
- }
- }
-
-done:
accumFor = f;
forLevel = 1;
return 1;
}
/*
- * Add another line to a .for loop.
+ * Add another line to the .for loop that is being built up.
* Returns FALSE when the matching .endfor is reached.
*/
Boolean
For_Accum(const char *line)
{
- const char *ptr = line;
+ const char *p = line;
- if (*ptr == '.') {
- ptr++;
- cpp_skip_whitespace(&ptr);
+ if (*p == '.') {
+ p++;
+ cpp_skip_whitespace(&p);
- if (IsEndfor(ptr)) {
+ if (IsEndfor(p)) {
DEBUG1(FOR, "For: end for %d\n", forLevel);
if (--forLevel <= 0)
return FALSE;
- } else if (IsFor(ptr)) {
+ } else if (IsFor(p)) {
forLevel++;
DEBUG1(FOR, "For: new loop %d\n", forLevel);
}
@@ -307,11 +320,11 @@ for_var_len(const char *var)
* that characters that break this syntax must be backslash-escaped.
*/
static Boolean
-NeedsEscapes(const char *word, char endc)
+NeedsEscapes(const char *value, char endc)
{
const char *p;
- for (p = word; *p != '\0'; p++) {
+ for (p = value; *p != '\0'; p++) {
if (*p == ':' || *p == '$' || *p == '\\' || *p == endc)
return TRUE;
}
@@ -356,8 +369,8 @@ Buf_AddEscaped(Buffer *cmds, const char *item, char endc)
* expression like ${i} or ${i:...} or $(i) or $(i:...) with ":Uvalue".
*/
static void
-SubstVarLong(For *f, const char **pp, const char *bodyEnd, char endc,
- const char **inout_mark)
+ForLoop_SubstVarLong(ForLoop *f, const char **pp, const char *bodyEnd,
+ char endc, const char **inout_mark)
{
size_t i;
const char *p = *pp;
@@ -397,7 +410,7 @@ SubstVarLong(For *f, const char **pp, const char *bodyEnd, char endc,
* variable expressions like $i with their ${:U...} expansion.
*/
static void
-SubstVarShort(For *f, const char *p, const char **inout_mark)
+ForLoop_SubstVarShort(ForLoop *f, const char *p, const char **inout_mark)
{
const char ch = *p;
ForVar *vars;
@@ -432,12 +445,12 @@ found:
* This code assumes that the variable with the empty name will never be
* defined, see unit-tests/varname-empty.mk for more details.
*
- * The detection of substitutions of the loop control variable is naive.
- * Many of the modifiers use \ to escape $ (not $) so it is possible
+ * The detection of substitutions of the loop control variables is naive.
+ * Many of the modifiers use '\' to escape '$' (not '$'), so it is possible
* to contrive a makefile where an unwanted substitution happens.
*/
static void
-ForSubstBody(For *f)
+ForLoop_SubstBody(ForLoop *f)
{
const char *p, *bodyEnd;
const char *mark; /* where the last replacement left off */
@@ -449,10 +462,10 @@ ForSubstBody(For *f)
for (p = mark; (p = strchr(p, '$')) != NULL;) {
if (p[1] == '{' || p[1] == '(') {
p += 2;
- SubstVarLong(f, &p, bodyEnd, p[-1] == '{' ? '}' : ')',
- &mark);
+ ForLoop_SubstVarLong(f, &p, bodyEnd,
+ p[-1] == '{' ? '}' : ')', &mark);
} else if (p[1] != '\0') {
- SubstVarShort(f, p + 1, &mark);
+ ForLoop_SubstVarShort(f, p + 1, &mark);
p += 2;
} else
break;
@@ -468,15 +481,15 @@ ForSubstBody(For *f)
static char *
ForReadMore(void *v_arg, size_t *out_len)
{
- For *f = v_arg;
+ ForLoop *f = v_arg;
if (f->sub_next == f->items.len) {
/* No more iterations */
- For_Free(f);
+ ForLoop_Free(f);
return NULL;
}
- ForSubstBody(f);
+ ForLoop_SubstBody(f);
DEBUG1(FOR, "For: loop body:\n%s", f->curBody.data);
f->sub_next += (unsigned int)f->vars.len;
@@ -488,7 +501,7 @@ ForReadMore(void *v_arg, size_t *out_len)
void
For_Run(int lineno)
{
- For *f = accumFor;
+ ForLoop *f = accumFor;
accumFor = NULL;
if (f->items.len == 0) {
@@ -496,7 +509,7 @@ For_Run(int lineno)
* Nothing to expand - possibly due to an earlier syntax
* error.
*/
- For_Free(f);
+ ForLoop_Free(f);
return;
}