Module Name:    src
Committed By:   rillig
Date:           Fri Aug 20 06:36:10 UTC 2021

Modified Files:
        src/tests/usr.bin/mkdep: Makefile t_findcc.sh
        src/usr.bin/mkdep: findcc.c

Log Message:
mkdep: avoid memory allocation in findcc

This change takes the idea of handling strings as pairs in the form
(start, len) by Robert Elz from
https://mail-index.netbsd.org/source-changes-d/2021/08/20/msg013427.html
and expands it by avoiding one more memory allocation, for iterating the
PATH environment variable.

No functional change.


To generate a diff of this commit:
cvs rdiff -u -r1.2 -r1.3 src/tests/usr.bin/mkdep/Makefile \
    src/tests/usr.bin/mkdep/t_findcc.sh
cvs rdiff -u -r1.9 -r1.10 src/usr.bin/mkdep/findcc.c

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

Modified files:

Index: src/tests/usr.bin/mkdep/Makefile
diff -u src/tests/usr.bin/mkdep/Makefile:1.2 src/tests/usr.bin/mkdep/Makefile:1.3
--- src/tests/usr.bin/mkdep/Makefile:1.2	Wed Aug 11 20:42:26 2021
+++ src/tests/usr.bin/mkdep/Makefile	Fri Aug 20 06:36:10 2021
@@ -1,4 +1,4 @@
-# $NetBSD: Makefile,v 1.2 2021/08/11 20:42:26 rillig Exp $
+# $NetBSD: Makefile,v 1.3 2021/08/20 06:36:10 rillig Exp $
 
 .include <bsd.own.mk>
 
@@ -13,5 +13,6 @@ PROG=		h_findcc
 SRCS=		h_findcc.c findcc.c
 CPPFLAGS+=	-I${NETBSDSRCDIR}/usr.bin/mkdep
 MAN.h_findcc=	# none
+WARNS=		6
 
 .include <bsd.test.mk>
Index: src/tests/usr.bin/mkdep/t_findcc.sh
diff -u src/tests/usr.bin/mkdep/t_findcc.sh:1.2 src/tests/usr.bin/mkdep/t_findcc.sh:1.3
--- src/tests/usr.bin/mkdep/t_findcc.sh:1.2	Fri Aug 20 05:45:19 2021
+++ src/tests/usr.bin/mkdep/t_findcc.sh	Fri Aug 20 06:36:10 2021
@@ -1,4 +1,4 @@
-# $NetBSD: t_findcc.sh,v 1.2 2021/08/20 05:45:19 rillig Exp $
+# $NetBSD: t_findcc.sh,v 1.3 2021/08/20 06:36:10 rillig Exp $
 #
 # Copyright (c) 2021 The NetBSD Foundation, Inc.
 # All rights reserved.
@@ -51,6 +51,31 @@ base_found_body() {
 		"$(atf_get_srcdir)"/h_findcc 'echo'
 }
 
+# A plain program name is searched in the PATH and, in this example, it is
+# found in '/bin', which comes second in the PATH.
+#
+atf_test_case base_found_second
+base_found_second_body() {
+	atf_check -o "inline:/bin/echo$n" \
+	    env -i PATH='/nonexistent:/bin' \
+		"$(atf_get_srcdir)"/h_findcc 'echo'
+}
+
+# A plain program name is searched in the PATH and, in this example, it is
+# found in './bin', a relative path in the PATH, which is rather unusual in
+# practice.
+#
+atf_test_case base_found_reldir
+base_found_reldir_body() {
+	mkdir bin
+	echo '#! /bin/sh' > 'bin/reldir-echo'
+	chmod +x 'bin/reldir-echo'
+
+	atf_check -o "inline:bin/reldir-echo$n" \
+	    env -i PATH='/nonexistent:bin' \
+		"$(atf_get_srcdir)"/h_findcc 'reldir-echo'
+}
+
 # The C compiler can be specified as a program with one or more arguments.
 # If the program name is a plain name without any slash, the argument is
 # discarded.
@@ -143,6 +168,8 @@ abs_arg_found_body() {
 atf_init_test_cases() {
 	atf_add_test_case base_not_found
 	atf_add_test_case base_found
+	atf_add_test_case base_found_second
+	atf_add_test_case base_found_reldir
 	atf_add_test_case base_arg_found
 
 	atf_add_test_case rel_not_found

Index: src/usr.bin/mkdep/findcc.c
diff -u src/usr.bin/mkdep/findcc.c:1.9 src/usr.bin/mkdep/findcc.c:1.10
--- src/usr.bin/mkdep/findcc.c:1.9	Fri Aug 20 05:45:19 2021
+++ src/usr.bin/mkdep/findcc.c	Fri Aug 20 06:36:10 2021
@@ -1,4 +1,4 @@
-/* $NetBSD: findcc.c,v 1.9 2021/08/20 05:45:19 rillig Exp $ */
+/* $NetBSD: findcc.c,v 1.10 2021/08/20 06:36:10 rillig Exp $ */
 
 /*-
  * Copyright (c) 1999 The NetBSD Foundation, Inc.
@@ -37,7 +37,7 @@
 #if !defined(lint)
 __COPYRIGHT("@(#) Copyright (c) 1999 The NetBSD Foundation, Inc.\
  All rights reserved.");
-__RCSID("$NetBSD: findcc.c,v 1.9 2021/08/20 05:45:19 rillig Exp $");
+__RCSID("$NetBSD: findcc.c,v 1.10 2021/08/20 06:36:10 rillig Exp $");
 #endif /* not lint */
 
 #include <sys/param.h>
@@ -49,47 +49,40 @@ __RCSID("$NetBSD: findcc.c,v 1.9 2021/08
 #include "findcc.h"
 
 char *
-findcc(const char *cc_command)
+findcc(const char *progname)
 {
-	char   *progname, *path, *dir, *next;
-	char   buffer[MAXPATHLEN];
-
-	if ((progname = strdup(cc_command)) == NULL)
-		return NULL;
-
-	if ((next = strchr(progname, ' ')) != NULL)
-		*next = '\0';
-
-	if (strchr(progname, '/') != NULL) {
-		if (access(progname, X_OK) == 0)
-			return progname;
-		free(progname);
+	char *cc;
+	const char *path, *dir;
+	char buffer[MAXPATHLEN];
+	size_t progname_len, dir_len;
+
+	progname_len = strcspn(progname, " ");
+
+	if (memchr(progname, '/', progname_len) != NULL) {
+		if ((cc = strndup(progname, progname_len)) == NULL)
+			return NULL;
+		if (access(cc, X_OK) == 0)
+			return cc;
+		free(cc);
 		return NULL;
 	}
 
-	if (((path = getenv("PATH")) == NULL) ||
-	    ((path = strdup(path)) == NULL)) {
-		free(progname);
+	if ((path = getenv("PATH")) == NULL)
 		return NULL;
-	}
 
-	dir = path;
-	while (dir != NULL) {
-		if ((next = strchr(dir, ':')) != NULL)
-			*next++ = '\0';
-
-		if (snprintf(buffer, sizeof(buffer),
-		    "%s/%s", dir, progname) < (int)sizeof(buffer)) {
-			if (access(buffer, X_OK) == 0) {
-				free(path);
-				free(progname);
-				return strdup(buffer);
-			}
-		}
-		dir = next;
+	for (dir = path; *dir != '\0'; ) {
+		dir_len = strcspn(dir, ":");
+
+		if ((size_t)snprintf(buffer, sizeof(buffer), "%.*s/%.*s",
+			(int)dir_len, dir, (int)progname_len, progname)
+		    < sizeof(buffer)
+		    && access(buffer, X_OK) == 0)
+			return strdup(buffer);
+
+		dir += dir_len;
+		if (*dir == ':')
+			dir++;
 	}
 
-	free(path);
-	free(progname);
 	return NULL;
 }

Reply via email to