Module Name:    src
Committed By:   rillig
Date:           Sun Dec  5 11:40:03 UTC 2021

Modified Files:
        src/usr.bin/make: for.c str.h
        src/usr.bin/make/unit-tests: directive-for-escape.mk

Log Message:
make: inline Str_Words into .for loop handling

This saves one memory allocation and a bit of copying, per .for loop.

No functional change.


To generate a diff of this commit:
cvs rdiff -u -r1.147 -r1.148 src/usr.bin/make/for.c
cvs rdiff -u -r1.9 -r1.10 src/usr.bin/make/str.h
cvs rdiff -u -r1.11 -r1.12 \
    src/usr.bin/make/unit-tests/directive-for-escape.mk

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/usr.bin/make/for.c
diff -u src/usr.bin/make/for.c:1.147 src/usr.bin/make/for.c:1.148
--- src/usr.bin/make/for.c:1.147	Thu Sep  2 07:02:07 2021
+++ src/usr.bin/make/for.c	Sun Dec  5 11:40:03 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: for.c,v 1.147 2021/09/02 07:02:07 rillig Exp $	*/
+/*	$NetBSD: for.c,v 1.148 2021/12/05 11:40:03 rillig Exp $	*/
 
 /*
  * Copyright (c) 1992, The Regents of the University of California.
@@ -58,7 +58,7 @@
 #include "make.h"
 
 /*	"@(#)for.c	8.1 (Berkeley) 6/6/93"	*/
-MAKE_RCSID("$NetBSD: for.c,v 1.147 2021/09/02 07:02:07 rillig Exp $");
+MAKE_RCSID("$NetBSD: for.c,v 1.148 2021/12/05 11:40:03 rillig Exp $");
 
 
 /* One of the variables to the left of the "in" in a .for loop. */
@@ -70,7 +70,7 @@ typedef struct ForVar {
 typedef struct ForLoop {
 	Buffer body;		/* Unexpanded body of the loop */
 	Vector /* of ForVar */ vars; /* Iteration variables */
-	Words items;		/* Substitution items */
+	SubstringWords items;	/* Substitution items */
 	Buffer curBody;		/* Expanded body of the current iteration */
 	unsigned int sub_next;	/* Where to continue iterating */
 } ForLoop;
@@ -87,8 +87,7 @@ ForLoop_New(void)
 
 	Buf_Init(&f->body);
 	Vector_Init(&f->vars, sizeof(ForVar));
-	f->items.words = NULL;
-	f->items.freeIt = NULL;
+	SubstringWords_Init(&f->items);
 	Buf_Init(&f->curBody);
 	f->sub_next = 0;
 
@@ -106,7 +105,7 @@ ForLoop_Free(ForLoop *f)
 	}
 	Vector_Done(&f->vars);
 
-	Words_Free(f->items);
+	SubstringWords_Free(f->items);
 	Buf_Done(&f->curBody);
 
 	free(f);
@@ -171,10 +170,10 @@ ForLoop_ParseItems(ForLoop *f, const cha
 		return false;
 	}
 
-	f->items = Str_Words(items, false);
+	f->items = Substring_Words(items, false);
 	free(items);
 
-	if (f->items.len == 1 && f->items.words[0][0] == '\0')
+	if (f->items.len == 1 && Substring_IsEmpty(f->items.words[0]))
 		f->items.len = 0; /* .for var in ${:U} */
 
 	if (f->items.len != 0 && f->items.len % f->vars.len != 0) {
@@ -278,17 +277,16 @@ For_Accum(const char *line)
 
 
 static size_t
-ExprLen(const char *expr)
+ExprLen(const char *s, const char *e)
 {
-	char ch, expr_open, expr_close;
+	char expr_open, expr_close;
 	int depth;
-	size_t len;
+	const char *p;
 
-	expr_open = expr[0];
-	if (expr_open == '\0')
-		/* just escape the $ */
-		return 0;
+	if (s == e)
+		return 0;	/* just escape the '$' */
 
+	expr_open = s[0];
 	if (expr_open == '(')
 		expr_close = ')';
 	else if (expr_open == '{')
@@ -297,11 +295,11 @@ ExprLen(const char *expr)
 		return 1;	/* Single char variable */
 
 	depth = 1;
-	for (len = 1; (ch = expr[len++]) != '\0';) {
-		if (ch == expr_open)
+	for (p = s + 1; p != e; p++) {
+		if (*p == expr_open)
 			depth++;
-		else if (ch == expr_close && --depth == 0)
-			return len;
+		else if (*p == expr_close && --depth == 0)
+			return (size_t)(p + 1 - s);
 	}
 
 	/* Expression end not found, escape the $ */
@@ -313,11 +311,11 @@ ExprLen(const char *expr)
  * that characters that break this syntax must be backslash-escaped.
  */
 static bool
-NeedsEscapes(const char *value, char endc)
+NeedsEscapes(Substring value, char endc)
 {
 	const char *p;
 
-	for (p = value; *p != '\0'; p++) {
+	for (p = value.start; p != value.end; p++) {
 		if (*p == ':' || *p == '$' || *p == '\\' || *p == endc ||
 		    *p == '\n')
 			return true;
@@ -332,27 +330,29 @@ NeedsEscapes(const char *value, char end
  * The result is later unescaped by ApplyModifier_Defined.
  */
 static void
-Buf_AddEscaped(Buffer *cmds, const char *item, char endc)
+Buf_AddEscaped(Buffer *cmds, Substring item, char endc)
 {
+	const char *p;
 	char ch;
 
 	if (!NeedsEscapes(item, endc)) {
-		Buf_AddStr(cmds, item);
+		Buf_AddBytesBetween(cmds, item.start, item.end);
 		return;
 	}
 
 	/* Escape ':', '$', '\\' and 'endc' - these will be removed later by
 	 * :U processing, see ApplyModifier_Defined. */
-	while ((ch = *item++) != '\0') {
+	for (p = item.start; p != item.end; p++) {
+		ch = *p;
 		if (ch == '$') {
-			size_t len = ExprLen(item);
+			size_t len = ExprLen(p + 1, item.end);
 			if (len != 0) {
 				/*
 				 * XXX: Should a '\' be added here?
 				 * See directive-for-escape.mk, ExprLen.
 				 */
-				Buf_AddBytes(cmds, item - 1, len + 1);
-				item += len;
+				Buf_AddBytes(cmds, p, 1 + len);
+				p += len;
 				continue;
 			}
 			Buf_AddByte(cmds, '\\');

Index: src/usr.bin/make/str.h
diff -u src/usr.bin/make/str.h:1.9 src/usr.bin/make/str.h:1.10
--- src/usr.bin/make/str.h:1.9	Sun May 30 21:16:54 2021
+++ src/usr.bin/make/str.h	Sun Dec  5 11:40:03 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: str.h,v 1.9 2021/05/30 21:16:54 rillig Exp $	*/
+/*	$NetBSD: str.h,v 1.10 2021/12/05 11:40:03 rillig Exp $	*/
 
 /*
  Copyright (c) 2021 Roland Illig <ril...@netbsd.org>
@@ -353,6 +353,14 @@ Words_Free(Words w)
 SubstringWords Substring_Words(const char *, bool);
 
 MAKE_INLINE void
+SubstringWords_Init(SubstringWords *w)
+{
+	w->words = NULL;
+	w->len = 0;
+	w->freeIt = NULL;
+}
+
+MAKE_INLINE void
 SubstringWords_Free(SubstringWords w)
 {
 	free(w.words);

Index: src/usr.bin/make/unit-tests/directive-for-escape.mk
diff -u src/usr.bin/make/unit-tests/directive-for-escape.mk:1.11 src/usr.bin/make/unit-tests/directive-for-escape.mk:1.12
--- src/usr.bin/make/unit-tests/directive-for-escape.mk:1.11	Thu Sep  2 07:02:08 2021
+++ src/usr.bin/make/unit-tests/directive-for-escape.mk	Sun Dec  5 11:40:03 2021
@@ -1,4 +1,4 @@
-# $NetBSD: directive-for-escape.mk,v 1.11 2021/09/02 07:02:08 rillig Exp $
+# $NetBSD: directive-for-escape.mk,v 1.12 2021/12/05 11:40:03 rillig Exp $
 #
 # Test escaping of special characters in the iteration values of a .for loop.
 # These values get expanded later using the :U variable modifier, and this
@@ -13,8 +13,8 @@
 ASCII=	!"\#$$%&'()*+,-./0-9:;<=>?@A-Z[\]_^a-z{|}~
 
 # XXX: As of 2020-12-31, the '#' is not preserved in the expanded body of
-# the loop since it would not need only the escaping for the :U variable
-# modifier but also the escaping for the line-end comment.
+# the loop.  Not only would it need the escaping for the variable modifier
+# ':U' but also the escaping for the line-end comment.
 .for chars in ${ASCII}
 .  info ${chars}
 .endfor
@@ -34,7 +34,7 @@ ASCII.2020-12-31=	!"\\\#$$%&'()*+,-./0-9
 # XXX: It is unexpected that the variable V gets expanded in the loop body.
 # The double '$$' should intuitively prevent exactly this.  Probably nobody
 # was adventurous enough to use literal dollar signs in the values of a .for
-# loop.
+# loop, allowing this edge case to go unnoticed for years.
 #
 # See for.c, function ExprLen.
 V=		value

Reply via email to