This is an automated email from the ASF dual-hosted git repository.

xiaoxiang781216 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit 88b3005af5b5edaac68df1ae900fdec104e6a526
Author: Marco Casaroli <[email protected]>
AuthorDate: Tue Oct 20 18:27:54 2026 +0200

    libs/libc/fnmatch: Add FNM_CASEFOLD and FNM_LEADING_DIR.
    
    Programs use two flags of fnmatch() that POSIX does not have, but other
    C libraries do: FNM_CASEFOLD ignores the case, and FNM_LEADING_DIR lets
    the pattern match the string up to a '/'.  <fnmatch.h> did not define
    them, so these programs did not compile.
    
    Define them with the values that the other C libraries use (8 and 16),
    and the aliases FNM_IGNORECASE and FNM_FILE_NAME.  With FNM_CASEFOLD,
    fnmatch() compares the characters and the members of a set without
    case; a range matches if the character in either case is in it.  With
    FNM_LEADING_DIR, a match ends at a '/' in the string as at its end.
    
    Assisted-by: Claude Code:claude-opus-5-5
    Signed-off-by: Marco Casaroli <[email protected]>
---
 include/fnmatch.h            | 10 +++++++
 libs/libc/misc/lib_fnmatch.c | 66 +++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 72 insertions(+), 4 deletions(-)

diff --git a/include/fnmatch.h b/include/fnmatch.h
index b83c32b278a..8afe3a416ba 100644
--- a/include/fnmatch.h
+++ b/include/fnmatch.h
@@ -37,6 +37,11 @@
 #define FNM_PATHNAME            0x01
 #define FNM_PERIOD              0x02
 #define FNM_NOESCAPE            0x04
+#define FNM_LEADING_DIR         0x08  /* Match up to a '/' in the string */
+#define FNM_CASEFOLD            0x10  /* Ignore the case */
+
+#define FNM_FILE_NAME           FNM_PATHNAME
+#define FNM_IGNORECASE          FNM_CASEFOLD
 
 #define FNM_NOMATCH             1
 #define FNM_NOSYS               -1
@@ -91,6 +96,11 @@ extern "C"
  *   If FNM_PERIOD is not set, then no special restrictions are placed on
  *   matching a period.
  *
+ *   Two flags are extensions, as in other C libraries.  With FNM_CASEFOLD
+ *   (or FNM_IGNORECASE), upper and lower case letters are the same.  With
+ *   FNM_LEADING_DIR, the pattern can match the string up to a slash, so
+ *   that "usr/lib" matches "usr/lib/x".
+ *
  * Returned Value:
  *   If string matches the pattern specified by pattern, then fnmatch()
  *   shall return 0. If there is no match, fnmatch() shall return
diff --git a/libs/libc/misc/lib_fnmatch.c b/libs/libc/misc/lib_fnmatch.c
index 9a00d4c94a7..77f0fc4d043 100644
--- a/libs/libc/misc/lib_fnmatch.c
+++ b/libs/libc/misc/lib_fnmatch.c
@@ -35,6 +35,7 @@
  * Included Files
  ****************************************************************************/
 
+#include <ctype.h>
 #include <fnmatch.h>
 #include <string.h>
 
@@ -42,6 +43,56 @@
  * Private Functions
  ****************************************************************************/
 
+/****************************************************************************
+ * Name: fnmatch_eq
+ *
+ * Description:
+ *   Compare one character of the pattern with one of the string.  With
+ *   FNM_CASEFOLD, upper and lower case are the same.
+ *
+ ****************************************************************************/
+
+static inline int fnmatch_eq(char p, char c, int flags)
+{
+  if (p == c)
+    {
+      return 1;
+    }
+
+  return (flags & FNM_CASEFOLD) != 0 &&
+         tolower((unsigned char)p) == tolower((unsigned char)c);
+}
+
+/****************************************************************************
+ * Name: fnmatch_range
+ *
+ * Description:
+ *   Return non-zero if c is in the range first-last.  With FNM_CASEFOLD,
+ *   the other case of c also matches.
+ *
+ ****************************************************************************/
+
+static inline int fnmatch_range(char first, char last, char c,
+                                int flags)
+{
+  char lc;
+  char uc;
+
+  if (c >= first && c <= last)
+    {
+      return 1;
+    }
+
+  if ((flags & FNM_CASEFOLD) == 0)
+    {
+      return 0;
+    }
+
+  lc = tolower((unsigned char)c);
+  uc = toupper((unsigned char)c);
+  return (lc >= first && lc <= last) || (uc >= first && uc <= last);
+}
+
 /****************************************************************************
  * Name: fnmatch_one
  *
@@ -81,14 +132,14 @@ static int fnmatch_one(FAR const char *pattern, int patlen,
               first = *p++;
               if (*p == '-' && p[1] != ']' && p[1] != '\0')
                 {
-                  if (*string >= first && *string <= p[1])
+                  if (fnmatch_range(first, p[1], *string, flags))
                     {
                       i = 1;
                     }
 
                   p += 2;
                 }
-              else if (*string == first)
+              else if (fnmatch_eq(first, *string, flags))
                 {
                   i = 1;
                 }
@@ -131,13 +182,16 @@ static int fnmatch_one(FAR const char *pattern, int 
patlen,
           return FNM_NOMATCH;
         }
 
-      if (*p != *string)
+      if (!fnmatch_eq(*p, *string, flags))
         {
           return FNM_NOMATCH;
         }
     }
 
-  if (*string == '\0')
+  /* With FNM_LEADING_DIR, the pattern can match the string up to a '/' */
+
+  if (*string == '\0' ||
+      ((flags & FNM_LEADING_DIR) != 0 && *string == '/'))
     {
       return 0;
     }
@@ -158,6 +212,10 @@ static int fnmatch_one(FAR const char *pattern, int patlen,
  *   '?', '*', '**', sets like [a-zA-z], and multiple  patterns separated
  *   by '|'.
  *
+ *   Of the flags, it handles FNM_CASEFOLD (upper and lower case are the
+ *   same) and FNM_LEADING_DIR (the pattern can match the string up to a
+ *   '/').
+ *
  * Returned Value:
  *   Returns 0 (match) or 1 (no-match).
  *

Reply via email to