Re: [PATCH] exclude: new function, excluded_file_name_ext

Paul Eggert <[email protected]>
Newsgroups gmane.comp.lib.gnulib.bugs
Organization UCLA Computer Science Department
Message-ID <[email protected]>
On 2026-08-17 01:48, Sergey Poznyakoff wrote:
> I'm OK with it either way, the
> most important thing is being able to tell how excluded_file_name
> took the decision: using a matching entry or because nothing matched
> the file name.

OK, thanks, I installed the attached into Gnulib; if this won't do please let us know.
0001-exclude-new-function-excluded_file_name_status.patch (text/x-patch, 8.9 KB)
From a50726598270147223685f91ac9761ce8a052a0e Mon Sep 17 00:00:00 2001
From: Paul Eggert <[email protected]>
Date: Tue, 18 Aug 2026 01:20:04 -0700
Subject: [PATCH] exclude: new function excluded_file_name_status

From a suggestion by Sergey Poznyakoff in:
https://lists.gnu.org/r/bug-gnulib/2026-08/msg00217.html
* lib/exclude.c (EXCLUDE_INLINE): New macro.
(excluded_file_name_status): New function, extending
excluded_file_name which is now in exclude.h.
* lib/exclude.h (EXCLUDE_INLINE, EXCLUDED_EXCLUDED, EXCLUDED_MATCHED):
New macros.
(excluded_file_name): New function.
* tests/test-exclude.c (main): Test new function too.
All test scripts changed.
---
 ChangeLog              | 14 ++++++++++++++
 lib/exclude.c          | 24 +++++++++++++-----------
 lib/exclude.h          | 22 +++++++++++++++++++++-
 tests/test-exclude.c   |  6 ++++--
 tests/test-exclude1.sh | 12 ++++++------
 tests/test-exclude2.sh | 12 ++++++------
 tests/test-exclude3.sh | 12 ++++++------
 tests/test-exclude4.sh |  2 +-
 tests/test-exclude5.sh |  8 ++++----
 tests/test-exclude6.sh |  4 ++--
 tests/test-exclude7.sh |  4 ++--
 tests/test-exclude8.sh |  6 +++---
 12 files changed, 82 insertions(+), 44 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 752464e397..30ad4d78e8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2026-08-18  Paul Eggert  <[email protected]>
+
+	exclude: new function excluded_file_name_status
+	From a suggestion by Sergey Poznyakoff in:
+	https://lists.gnu.org/r/bug-gnulib/2026-08/msg00217.html
+	* lib/exclude.c (EXCLUDE_INLINE): New macro.
+	(excluded_file_name_status): New function, extending
+	excluded_file_name which is now in exclude.h.
+	* lib/exclude.h (EXCLUDE_INLINE, EXCLUDED_EXCLUDED, EXCLUDED_MATCHED):
+	New macros.
+	(excluded_file_name): New function.
+	* tests/test-exclude.c (main): Test new function too.
+	All test scripts changed.
+
 2026-08-17  Bruno Haible  <[email protected]>
 
 	Depend on 'bool' for use of 'false' or 'true'.
diff --git a/lib/exclude.c b/lib/exclude.c
index 6a8604ec1b..0519ffec8e 100644
--- a/lib/exclude.c
+++ b/lib/exclude.c
@@ -21,6 +21,7 @@
    Thanks to Phil Proudman <[email protected]>
    for improvement suggestions. */
 
+#define EXCLUDE_INLINE _GL_EXTERN_INLINE
 #include <config.h>
 
 #include <ctype.h>
@@ -455,17 +456,18 @@ file_name_matches (struct exclude_segment const *seg, char const *f,
   return false;
 }
 
-/* Return true if EX excludes F.  */
+/* Return the status of whether EX excludes F.  */
 
-bool
-excluded_file_name (struct exclude const *ex, char const *f)
+int
+excluded_file_name_status (struct exclude const *ex, char const *f)
 {
   /* If no patterns are given, the default is to include.  */
   if (!ex->head)
-    return false;
+    return 0;
 
   bool invert = false;
   char *filename = nullptr;
+  bool found = false;
 
   /* Scan through the segments, reporting the status of the first match.
      The segments are in reverse order, so this reports the status of
@@ -477,14 +479,13 @@ excluded_file_name (struct exclude const *ex, char const *f)
         {
           if (!filename)
             filename = xmalloc (strlen (f) + 1);
-          if (file_name_matches (seg, f, filename))
-            break;
+          found = file_name_matches (seg, f, filename);
         }
       else
-        {
-          if (file_pattern_matches (seg, f))
-            break;
-        }
+        found = file_pattern_matches (seg, f);
+
+      if (found)
+        break;
 
       if (! seg->next)
         {
@@ -500,7 +501,8 @@ excluded_file_name (struct exclude const *ex, char const *f)
     }
 
   free (filename);
-  return invert ^ ! (seg->options & EXCLUDE_INCLUDE);
+  return ((invert ^ ! (seg->options & EXCLUDE_INCLUDE) ? EXCLUDED_EXCLUDED : 0)
+          | (found ? EXCLUDED_MATCHED : 0));
 }
 
 /* Append to EX the exclusion PATTERN with OPTIONS.  */
diff --git a/lib/exclude.h b/lib/exclude.h
index c217a1e4e6..3c77493f75 100644
--- a/lib/exclude.h
+++ b/lib/exclude.h
@@ -30,6 +30,11 @@
 
 #include <stdio.h>
 
+_GL_INLINE_HEADER_BEGIN
+#ifndef EXCLUDE_INLINE
+# define EXCLUDE_INLINE _GL_INLINE
+#endif
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -54,6 +59,12 @@ extern "C" {
 /* Allocate storage for the pattern */
 #define EXCLUDE_ALLOC     (1 << 26)
 
+
+/* Return status flags for excluded_file_name_status.  */
+#define EXCLUDED_EXCLUDED (1 << 0) /* The file name was excluded.  */
+#define EXCLUDED_MATCHED  (1 << 1) /* The file name was matched.  */
+
+
 struct exclude;
 
 bool fnmatch_pattern_has_wildcards (const char *, int) _GL_ATTRIBUTE_PURE;
@@ -68,13 +79,22 @@ int add_exclude_file (void (*) (struct exclude *, char const *, int),
                       struct exclude *, char const *, int, char);
 int add_exclude_fp (void (*) (struct exclude *, char const *, int, void *),
                     struct exclude *, FILE *, int, char, void *);
-bool excluded_file_name (struct exclude const *, char const *);
+int excluded_file_name_status (struct exclude const *, char const *);
 void exclude_add_pattern_buffer (struct exclude *ex, char *buf);
 bool exclude_fnmatch (char const *, char const *, int);
 
+/* Return true if EX excludes F.  */
+EXCLUDE_INLINE bool
+excluded_file_name (struct exclude const *ex, char const *f)
+{
+  return excluded_file_name_status (ex, f) & EXCLUDED_EXCLUDED;
+}
+
 
 #ifdef __cplusplus
 }
 #endif
 
+_GL_INLINE_HEADER_END
+
 #endif /* _GL_EXCLUDE_H */
diff --git a/tests/test-exclude.c b/tests/test-exclude.c
index 17c631c02a..e57b34d232 100644
--- a/tests/test-exclude.c
+++ b/tests/test-exclude.c
@@ -118,8 +118,10 @@ main (int argc, char **argv)
   for (; argc; --argc)
     {
       char *word = *++argv;
-
-      printf ("%s: %d\n", word, excluded_file_name (exclude, word));
+      bool excluded = excluded_file_name (exclude, word);
+      int status = excluded_file_name_status (exclude, word);
+      printf ("%s: %d %d%s\n", word, excluded, !!(status & EXCLUDED_MATCHED),
+              excluded != !!(status & EXCLUDED_EXCLUDED) ? " !" : "");
     }
 
   free_exclude (exclude);
diff --git a/tests/test-exclude1.sh b/tests/test-exclude1.sh
index 0e2058915c..890da3ba43 100755
--- a/tests/test-exclude1.sh
+++ b/tests/test-exclude1.sh
@@ -28,12 +28,12 @@ Baz
 EOT
 
 cat > expected <<EOT
-foo: 0
-foo*: 1
-bar: 1
-foobar: 0
-baz: 0
-bar/qux: 0
+foo: 0 0
+foo*: 1 1
+bar: 1 1
+foobar: 0 0
+baz: 0 0
+bar/qux: 0 0
 EOT
 
 ${CHECKER} test-exclude in -- foo 'foo*' bar foobar baz bar/qux > out || exit $?
diff --git a/tests/test-exclude2.sh b/tests/test-exclude2.sh
index 25b69f4b90..c67a5d7473 100755
--- a/tests/test-exclude2.sh
+++ b/tests/test-exclude2.sh
@@ -28,12 +28,12 @@ EOT
 # Test case-insensitive literal matches
 
 cat > expected <<EOT
-foo: 0
-foo*: 1
-bar: 1
-foobar: 0
-baz: 1
-bar/qux: 0
+foo: 0 0
+foo*: 1 1
+bar: 1 1
+foobar: 0 0
+baz: 1 1
+bar/qux: 0 0
 EOT
 
 ${CHECKER} test-exclude -casefold in -- foo 'foo*' bar foobar baz bar/qux > out || exit $?
diff --git a/tests/test-exclude3.sh b/tests/test-exclude3.sh
index bfd168c21b..e3f35d8ce2 100755
--- a/tests/test-exclude3.sh
+++ b/tests/test-exclude3.sh
@@ -28,12 +28,12 @@ Baz
 EOT
 
 cat > expected <<EOT
-foo: 1
-foo*: 0
-bar: 0
-foobar: 1
-baz: 1
-bar/qux: 1
+foo: 1 0
+foo*: 0 1
+bar: 0 1
+foobar: 1 0
+baz: 1 0
+bar/qux: 1 0
 EOT
 
 ${CHECKER} test-exclude -include in -- foo 'foo*' bar foobar baz bar/qux > out || exit $?
diff --git a/tests/test-exclude4.sh b/tests/test-exclude4.sh
index 55ce8cfb86..4f250db3a8 100755
--- a/tests/test-exclude4.sh
+++ b/tests/test-exclude4.sh
@@ -28,7 +28,7 @@ Baz
 EOT
 
 cat > expected <<EOT
-foobar: 1
+foobar: 1 1
 EOT
 
 ${CHECKER} test-exclude -wildcards in -- foobar > out || exit $?
diff --git a/tests/test-exclude5.sh b/tests/test-exclude5.sh
index 6978ba4cd6..8372d9463b 100755
--- a/tests/test-exclude5.sh
+++ b/tests/test-exclude5.sh
@@ -28,10 +28,10 @@ Baz
 EOT
 
 cat > expected <<EOT
-bar: 1
-bar/qux: 1
-barz: 0
-foo/bar: 1
+bar: 1 1
+bar/qux: 1 1
+barz: 0 0
+foo/bar: 1 1
 EOT
 
 ${CHECKER} test-exclude -leading_dir in -- bar bar/qux barz foo/bar > out || exit $?
diff --git a/tests/test-exclude6.sh b/tests/test-exclude6.sh
index 240115a4f6..8b882f4e53 100755
--- a/tests/test-exclude6.sh
+++ b/tests/test-exclude6.sh
@@ -28,8 +28,8 @@ Baz
 EOT
 
 cat > expected <<EOT
-bar: 1
-foo/bar: 0
+bar: 1 1
+foo/bar: 0 0
 EOT
 
 ${CHECKER} test-exclude -anchored in -- bar foo/bar > out || exit $?
diff --git a/tests/test-exclude7.sh b/tests/test-exclude7.sh
index cb701d2c86..a8953c9d7b 100755
--- a/tests/test-exclude7.sh
+++ b/tests/test-exclude7.sh
@@ -28,8 +28,8 @@ Baz
 EOT
 
 cat > expected <<EOT
-bar: 0
-bar: 1
+bar: 0 1
+bar: 1 1
 EOT
 
 ${CHECKER} test-exclude in -include in -- bar > out || exit $?
diff --git a/tests/test-exclude8.sh b/tests/test-exclude8.sh
index 02524d6e89..e7a304ab65 100755
--- a/tests/test-exclude8.sh
+++ b/tests/test-exclude8.sh
@@ -27,9 +27,9 @@ b[a\*]r
 EOT
 
 cat > expected <<'EOT'
-f*e: 1
-file: 0
-bar: 1
+f*e: 1 1
+file: 0 0
+bar: 1 1
 EOT
 
 ${CHECKER} test-exclude -wildcards in -- 'f*e' 'file' 'bar' > out || exit $?
-- 
2.55.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.