Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions doc/contribute/coding_guidelines/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1284,6 +1284,7 @@ Description
:header: Function,Source
:widths: auto

`fnmatch()`_, POSIX.1-2008
`gmtime_r()`_,POSIX.1-2001
`strnlen()`_,POSIX.1-2008
`strtok_r()`_,POSIX.1-2001
Expand All @@ -1309,6 +1310,7 @@ Rationale
toolchains that come with their own C standard libraries.

.. _main Zephyr repository: https://github.com/zephyrproject-rtos/zephyr
.. _fnmatch(): https://pubs.opengroup.org/onlinepubs/9699919799/functions/fnmatch.html
.. _gmtime_r(): https://pubs.opengroup.org/onlinepubs/9699919799/functions/gmtime_r.html
.. _strnlen(): https://pubs.opengroup.org/onlinepubs/9699919799/functions/strlen.html
.. _strtok_r(): https://pubs.opengroup.org/onlinepubs/9699919799/functions/strtok.html
61 changes: 7 additions & 54 deletions include/zephyr/posix/fnmatch.h
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please undo the changes to this file

Original file line number Diff line number Diff line change
@@ -1,59 +1,12 @@
/* SPDX-License-Identifier: BSD-3-Clause */

/* $NetBSD: fnmatch.h,v 1.12.50.1 2011/02/08 16:18:55 bouyer Exp $ */

/*-
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
/*
* Copyright (c) 2025 The Zephyr Project Contributors
*
* @(#)fnmatch.h 8.1 (Berkeley) 6/2/93
* SPDX-License-Identifier: Apache-2.0
*/

#ifndef _FNMATCH_H_
#define _FNMATCH_H_

#define FNM_NOMATCH 1 /* Match failed. */
#define FNM_NOSYS 2 /* Function not implemented. */
#define FNM_NORES 3 /* Out of resources */

#define FNM_NOESCAPE 0x01 /* Disable backslash escaping. */
#define FNM_PATHNAME 0x02 /* Slash must be matched by slash. */
#define FNM_PERIOD 0x04 /* Period must be matched by period. */
#define FNM_CASEFOLD 0x08 /* Pattern is matched case-insensitive */
#define FNM_LEADING_DIR 0x10 /* Ignore /<tail> after Imatch. */

#ifdef __cplusplus
extern "C" {
#endif

int fnmatch(const char *, const char *, int);
#ifndef ZEPHYR_INCLUDE_POSIX_FNMATCH_H_
#define ZEPHYR_INCLUDE_POSIX_FNMATCH_H_

#ifdef __cplusplus
}
#endif
#include_next <fnmatch.h>

#endif /* !_FNMATCH_H_ */
#endif /* ZEPHYR_INCLUDE_POSIX_FNMATCH_H_ */
4 changes: 4 additions & 0 deletions lib/libc/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ config MINIMAL_LIBC
imply COMPILER_FREESTANDING
select COMMON_LIBC_ABORT
select COMMON_LIBC_STRNLEN
select COMMON_LIBC_FNMATCH
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
select COMMON_LIBC_FNMATCH

imply COMMON_LIBC_MALLOC
imply COMMON_LIBC_CALLOC
imply COMMON_LIBC_REALLOCARRAY
Expand Down Expand Up @@ -119,6 +120,7 @@ config NEWLIB_LIBC
depends on NEWLIB_LIBC_SUPPORTED
select NEED_LIBC_MEM_PARTITION
select TC_PROVIDES_POSIX_C_LANG_SUPPORT_R
select COMMON_LIBC_FNMATCH
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

newlib should provide this function.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
select COMMON_LIBC_FNMATCH
select TC_PROVIDES_POSIX_C_LIB_EXT

imply POSIX_DEVICE_IO_ALIAS_CLOSE
imply POSIX_DEVICE_IO_ALIAS_OPEN
imply POSIX_DEVICE_IO_ALIAS_READ
Expand All @@ -137,6 +139,7 @@ config ARCMWDT_LIBC
depends on "$(ZEPHYR_TOOLCHAIN_VARIANT)" = "arcmwdt"
select STATIC_INIT_GNU
select LIBC_ALLOW_LESS_THAN_64BIT_TIME
select COMMON_LIBC_FNMATCH
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
select COMMON_LIBC_FNMATCH

help
C library provided by ARC MWDT toolchain.

Expand All @@ -151,6 +154,7 @@ config IAR_LIBC
depends on "$(ZEPHYR_TOOLCHAIN_VARIANT)" = "iar"
select COMMON_LIBC_STRNLEN
select COMMON_LIBC_TIME
select COMMON_LIBC_FNMATCH
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
select COMMON_LIBC_FNMATCH

help
Use the full IAR Compiler runtime libraries.
A reduced Zephyr minimal libc will be used for library functionality
Expand Down
6 changes: 6 additions & 0 deletions lib/libc/common/CMakeLists.txt
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please undo the changes to this file.

Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_CTIME source/time/ctime.c)
zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_TIME source/time/time.c)
zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_MALLOC source/stdlib/malloc.c)
zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_STRNLEN source/string/strnlen.c)

if(CONFIG_COMMON_LIBC_FNMATCH)
zephyr_library_sources(source/fnmatch/fnmatch.c)
zephyr_include_directories(source/fnmatch/include)
endif()

zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_THRD
source/thrd/cnd.c
source/thrd/mtx.c
Expand Down
5 changes: 5 additions & 0 deletions lib/libc/common/Kconfig
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For C libraries that provide POSIX_C_LIB_EXT, please add select TC_PROVIDES_POSIX_C_LIB_EXT.

If there are problems doing so, then those issues should be solved in advance.

Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,11 @@ config COMMON_LIBC_STRNLEN
help
common implementation of strnlen().

config COMMON_LIBC_FNMATCH
bool
help
common implementation of fnmatch().

Comment on lines +107 to +111
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove

config COMMON_LIBC_THRD
bool "C11 <threads.h> API support"
depends on DYNAMIC_THREAD
Expand Down
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please move this file back to its original location.

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* SPDX-License-Identifier: BSD-3-Clause */

Check warning on line 1 in lib/libc/common/source/fnmatch/fnmatch.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

License may not be allowed

lib/libc/common/source/fnmatch/fnmatch.c:1 License file for 'BSD-3-Clause' not found in /LICENSES. Please check https://docs.zephyrproject.org/latest/contribute/guidelines.html#components-using-other-licenses.

Check warning on line 1 in lib/libc/common/source/fnmatch/fnmatch.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

License may not be allowed

lib/libc/common/source/fnmatch/fnmatch.c:1 License file for 'BSD-3-Clause' not found in /LICENSES. Please check https://docs.zephyrproject.org/latest/contribute/guidelines.html#components-using-other-licenses.

Check warning on line 1 in lib/libc/common/source/fnmatch/fnmatch.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

License may not be allowed

lib/libc/common/source/fnmatch/fnmatch.c:1 License file for 'BSD-3-Clause' not found in /LICENSES. Please check https://docs.zephyrproject.org/latest/contribute/guidelines.html#components-using-other-licenses.

/* $NetBSD: fnmatch.c,v 1.26 2014/10/12 22:32:33 christos Exp $ */

Expand Down Expand Up @@ -39,11 +39,13 @@
* Compares a filename or pathname to a pattern.
*/

#define _GNU_SOURCE

Check failure on line 42 in lib/libc/common/source/fnmatch/fnmatch.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

API_DEFINE

lib/libc/common/source/fnmatch/fnmatch.c:42 do not specify non-standard feature test macros for embedded code

Check failure on line 42 in lib/libc/common/source/fnmatch/fnmatch.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

API_DEFINE

lib/libc/common/source/fnmatch/fnmatch.c:42 do not specify non-standard feature test macros for embedded code

Check failure on line 42 in lib/libc/common/source/fnmatch/fnmatch.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

API_DEFINE

lib/libc/common/source/fnmatch/fnmatch.c:42 do not specify non-standard feature test macros for embedded code

#include <ctype.h>
#include <stdbool.h>
#include <string.h>

#include <zephyr/posix/fnmatch.h>
#include <fnmatch.h>
Copy link
Member

@cfriedt cfriedt Nov 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should really only be done after #97855 is merged (although, I guess it is part of that PR already).

#include <zephyr/toolchain.h>

#define EOS '\0'
Expand Down
62 changes: 62 additions & 0 deletions lib/libc/common/source/fnmatch/include/fnmatch.h
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please move this header back to its original location.

Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/* SPDX-License-Identifier: BSD-3-Clause */

Check warning on line 1 in lib/libc/common/source/fnmatch/include/fnmatch.h

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

License may not be allowed

lib/libc/common/source/fnmatch/include/fnmatch.h:1 License file for 'BSD-3-Clause' not found in /LICENSES. Please check https://docs.zephyrproject.org/latest/contribute/guidelines.html#components-using-other-licenses.

Check warning on line 1 in lib/libc/common/source/fnmatch/include/fnmatch.h

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

License may not be allowed

lib/libc/common/source/fnmatch/include/fnmatch.h:1 License file for 'BSD-3-Clause' not found in /LICENSES. Please check https://docs.zephyrproject.org/latest/contribute/guidelines.html#components-using-other-licenses.

Check warning on line 1 in lib/libc/common/source/fnmatch/include/fnmatch.h

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

License may not be allowed

lib/libc/common/source/fnmatch/include/fnmatch.h:1 License file for 'BSD-3-Clause' not found in /LICENSES. Please check https://docs.zephyrproject.org/latest/contribute/guidelines.html#components-using-other-licenses.

/* $NetBSD: fnmatch.h,v 1.12.50.1 2011/02/08 16:18:55 bouyer Exp $ */

/*-
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)fnmatch.h 8.1 (Berkeley) 6/2/93
*/

#ifndef _ZEPHYR_LIB_LIBC_COMMON_SOURCE_FNMATCH_INCLUDE_FNMATCH_H_
#define _ZEPHYR_LIB_LIBC_COMMON_SOURCE_FNMATCH_INCLUDE_FNMATCH_H_

#define FNM_NOMATCH 1 /* Match failed. */
#define FNM_NOSYS 2 /* Function not implemented. */
#define FNM_NORES 3 /* Out of resources */

#define FNM_NOESCAPE 0x01 /* Disable backslash escaping. */
#define FNM_PATHNAME 0x02 /* Slash must be matched by slash. */
#define FNM_PERIOD 0x04 /* Period must be matched by period. */

#if defined(_GNU_SOURCE)
#define FNM_CASEFOLD 0x08 /* Pattern is matched case-insensitive */
#define FNM_LEADING_DIR 0x10 /* Ignore /<tail> after Imatch. */
#endif /* _GNU_SOURCE */

#ifdef __cplusplus
extern "C" {
#endif

int fnmatch(const char *, const char *, int);

#ifdef __cplusplus
}
#endif

#endif /* !_ZEPHYR_LIB_LIBC_COMMON_SOURCE_FNMATCH_INCLUDE_FNMATCH_H_ */
1 change: 0 additions & 1 deletion lib/posix/c_lib_ext/CMakeLists.txt
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please undo the changes to this file

Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ endif()

zephyr_library()
zephyr_library_sources(
fnmatch.c
getentropy.c
getopt/getopt.c
getopt/getopt_common.c
Expand Down
2 changes: 0 additions & 2 deletions subsys/net/lib/http/Kconfig
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please undo the changes to this file

Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,6 @@ config HTTP_SERVER_WEBSOCKET

config HTTP_SERVER_RESOURCE_WILDCARD
bool "Allow wildcard matching of resources"
# The POSIX_C_LIB_EXT will get fnmatch() support
select POSIX_C_LIB_EXT
help
Allow user to specify wildcards when setting up resource strings.
This means that instead of specifying multiple resources with exact
Expand Down
3 changes: 2 additions & 1 deletion subsys/net/lib/http/http_server_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
* SPDX-License-Identifier: Apache-2.0
*/

#define _GNU_SOURCE /* for FNM_LEADING_DIR in fnmatch.h */

Check failure on line 8 in subsys/net/lib/http/http_server_core.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

API_DEFINE

subsys/net/lib/http/http_server_core.c:8 do not specify non-standard feature test macros for embedded code

Check failure on line 8 in subsys/net/lib/http/http_server_core.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

API_DEFINE

subsys/net/lib/http/http_server_core.c:8 do not specify non-standard feature test macros for embedded code

Check failure on line 8 in subsys/net/lib/http/http_server_core.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

API_DEFINE

subsys/net/lib/http/http_server_core.c:8 do not specify non-standard feature test macros for embedded code
#include <fnmatch.h>
Copy link
Member

@cfriedt cfriedt Nov 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should really only be done after #97855 is merged (although, I guess it is part of that PR already).

#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
Expand All @@ -21,7 +23,6 @@
#include <zephyr/net/socket.h>
#include <zephyr/net/tls_credentials.h>
#include <zephyr/posix/sys/eventfd.h>
#include <zephyr/posix/fnmatch.h>
#include <zephyr/sys/util_macro.h>

LOG_MODULE_REGISTER(net_http_server, CONFIG_NET_HTTP_SERVER_LOG_LEVEL);
Expand Down
1 change: 0 additions & 1 deletion subsys/shell/Kconfig
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please undo the changes to this file

Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,6 @@ config SHELL_ASCII_FILTER

config SHELL_WILDCARD
bool "Wildcard support in shell"
select POSIX_C_LIB_EXT
default y if !SHELL_MINIMAL
help
Enables using wildcards: * and ? in the shell.
Expand Down
3 changes: 2 additions & 1 deletion subsys/shell/shell_wildcard.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
*/

#include <string.h>
#include <zephyr/posix/fnmatch.h>
#include <fnmatch.h>

Comment on lines +8 to +9
Copy link
Member

@cfriedt cfriedt Nov 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should really only be done after #97855 is merged (although, I guess it is part of that PR already).

#include "shell_wildcard.h"
#include "shell_utils.h"
#include "shell_ops.h"
Expand Down
2 changes: 1 addition & 1 deletion subsys/testsuite/coverage/coverage.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#include <stdint.h>
#include <errno.h>
#include <string.h>
#include <zephyr/posix/fnmatch.h>
#include <fnmatch.h>
Copy link
Member

@cfriedt cfriedt Nov 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should really only be done after #97855 is merged (although, I guess it is part of that PR already).

#include "coverage.h"
#include <zephyr/arch/common/semihost.h>
#include <sys/types.h>
Expand Down
27 changes: 22 additions & 5 deletions tests/posix/c_lib_ext/src/fnmatch.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,20 @@
zassert_equal(fnmatch("a*.c", "a/x.c", FNM_PATHNAME), FNM_NOMATCH);
zassert_ok(fnmatch("*/foo", "/foo", FNM_PATHNAME));
zassert_ok(fnmatch("-O[01]", "-O1", 0));
zassert_ok(fnmatch("[[?*\\]", "\\", 0));
zassert_ok(fnmatch("[]?*\\]", "]", 0));
if (!IS_ENABLED(CONFIG_COMMON_LIBC_FNMATCH)) {
/* \\ escapes ], no bracket expr, no match */
zassert_equal(fnmatch("[[?*\\]", "\\", 0), FNM_NOMATCH);
Copy link
Member

@cfriedt cfriedt Nov 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is incorrect.

If FNM_NOESCAPE is not set in flags, a backslash character in pattern followed by any other character shall match that second character in string

https://pubs.opengroup.org/onlinepubs/9699919799/functions/fnmatch.html

In the assertion below, FNM_NOESCAPE is not set, so the \\ sequence in pattern matches the (properly escaped and singular) backslash character \. The function should return successfully. Below, pattern should be interpreted as matching any of [, ?, *, \.

zassert_ok(fnmatch("[[?*\\]", "\\", 0));

If Picolibc's implementation does not work here, it has at least one bug.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The compiler will convert \\ in the source code to a single \ in the resulting string, and that will escape the ] character. I reviewed the musl source code and it appears to have a bug here; it doesn't check to see if the ] is escaped with \. https://git.musl-libc.org/cgit/musl/tree/src/regex/fnmatch.c#n72

Copy link
Member

@cfriedt cfriedt Nov 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't looked at musl's implementation of fnmatch(), just the test data. The original implementation of fnmatch in Zephyr did not include any tests, so the tests were kind of retrofitted.

I think I misinterpreted the pattern, and I can understand why the original author of the test data probably also misinterpreted the pattern due to the wording of the spec.

zassert_ok(fnmatch("[[?*\\]", "\\", 0));

So [[?* is pretty clear, but I guess \\] is the part that probably isn't clear. So this will get compiled to char pattern[] = ['\\', ']'], which would seem like an escape of the ending square bracket (so more like "\]"), which would support the comment above \\ escapes ], no bracket expr, no match.

I think I can agree with that now, but it required a retake.

The alternative below provided in this PR seems to be more correct

zassert_ok(fnmatch("[[?*\\\\]", "\\", 0));

Ignoring the other options in the bracket expression, [?*, then the bracket expression could be simplified to "[\\\\]", or basically a single escaped backslash.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, having both the compiler and the function parsing the same escape sequences is confusing at best.

As to changing the test case, they're both "legitimate" test cases; the original one uncovers a bug in the Musl implementation which is not present in the newlib, picolibc or glibc implementations, so we should keep it. Adding your modified version is probably also reasonable (more tests == more better?).

/* \\ escapes ], no bracket expr, no match */
zassert_equal(fnmatch("[]?*\\]", "]", 0), FNM_NOMATCH);
Copy link
Member

@cfriedt cfriedt Nov 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one is a little trickier.

Just mid-release, so give me some time to revisit.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, these are just more versions of the above test -- because the ] is preceded by a single \, it will be escaped and hence the pattern doesn't actually contain a bracket expression at all.

}
/* \\ unescaped, match */
zassert_ok(fnmatch("[[?*\\]", "\\", FNM_NOESCAPE));
/* \\ escapes \\, match */
zassert_ok(fnmatch("[[?*\\\\]", "\\", 0));
/* \\ unescaped, match */
zassert_ok(fnmatch("[]?*\\]", "]", FNM_NOESCAPE));
/* \\ escapes \\, match */
zassert_ok(fnmatch("[]?*\\\\]", "]", 0));
Comment on lines +39 to +46
Copy link
Member

@cfriedt cfriedt Nov 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a little hesitant to add these, and it isn't clear to me at the moment if they add to coverage.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They test the four cases where musl and glibc differ because musl doesn't allow for an escaped ] in the pattern.
I think https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_13_01 is pretty clear on this point --fnmatch should interpret \ followed by ] as a plain character and not the end of the bracket expression.

Copy link
Member

@cfriedt cfriedt Nov 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This first one makes sense to me
The second one makes sense to me.

The third one (below) is a bit tricky, because [] (empty bracket expressions) are undefined in POSIX.
Further clarification is in
https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap09.html#tag_09_03_05

The ( ']' ) shall lose its special meaning and represent itself in a bracket expression if it occurs first in the list (after an initial ( '^' ), if any)

So while it might be tempting to interpret []? as an empty bracket expression followed by a "maximally once" operator, the spec says not to do that.

/* \\ unescaped, match */
zassert_ok(fnmatch("[]?*\\]", "]", FNM_NOESCAPE));

The last case is similar at the beginning, and of course allows escapes, so the \\ followed by \\ is just an escaped backslash that doesn't match anything in the input.

/* \\ escapes \\, match */
zassert_ok(fnmatch("[]?*\\\\]", "]", 0));

So the third and fourth cases make sense to me too.

I would probably also say that another pattern to include in addition to the fourth case where there are 0 flags, would be below

/* \\ escapes \\, match */
zassert_ok(fnmatch("[\\]?*\\\\]", "]", 0));

Which just explicitly escapes the first ] in the bracket expression. It isn't needed, but being a bit more explicit about the interpretation of ] would be helpful for any future readers (and probably a link back to the spec would help).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This first one makes sense to me The second one makes sense to me.

The third one (below) is a bit tricky,

Tricky, but well defined -- fnmatch("[]?*\\]", "]", FNM_NOESCAPE) matches ] because the bracket expression matches any of ], ?, * or \. The latter because FNM_NOESCAPE means that the \ doesn't get interpreted as an escape for the trailing ].

I would probably also say that another pattern to include in addition to the fourth case where there are 0 flags, would be below

/* \\ escapes \\, match */
zassert_ok(fnmatch("[\\]?*\\\\]", "]", 0));

Which just explicitly escapes the first ] in the bracket expression. It isn't needed, but being a bit more explicit about the interpretation of ] would be helpful for any future readers (and probably a link back to the spec would help).

Additional annotations for the test cases is probably a good idea. Note that we want to poke the implementation in corner cases, so while I would probably write "[\\]?*\\\\]" to make my intention clear, the spec says that is equivalent to "[]?*\\\\]", so we should test both to make sure either form works.

zassert_ok(fnmatch("[!]a-]", "b", 0));
zassert_ok(fnmatch("[]-_]", "^", 0));
zassert_ok(fnmatch("[!]-_]", "X", 0));
Expand Down Expand Up @@ -73,9 +85,14 @@
zassert_equal(fnmatch("*/*", "a/.b", FNM_PATHNAME | FNM_PERIOD), FNM_NOMATCH);
zassert_ok(fnmatch("*?*/*", "a/.b", FNM_PERIOD));
zassert_ok(fnmatch("*[.]/b", "a./b", FNM_PATHNAME | FNM_PERIOD));
/* zassert_ok(fnmatch("*[[:alpha:]]/""*[[:alnum:]]", "a/b", FNM_PATHNAME)); */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please do not remove this line. It's there intentionally.

We should wait for #97400 to be merged. I've been working with the first-time contributor for over a month to ensure the PR is ready, and I think it would be great to help them to push it past the finish line.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. This one relies on the library supporting the character class elements of the pattern. Newlib, picolibc 1.8.10 and Zephyr all lack support for these, so we will need to make fixed versions available before this test will pass though.

zassert_not_equal(fnmatch("*[![:digit:]]*/[![:d-d]", "a/b", FNM_PATHNAME), 0);
zassert_not_equal(fnmatch("*[![:digit:]]*/[[:d-d]", "a/[", FNM_PATHNAME), 0);

/* Disable tests that fail when using Zephyr's fnmatch implementation */
if (!IS_ENABLED(CONFIG_POSIX_C_LIB_EXT)) {
zassert_ok(fnmatch("*[[:alpha:]]/""*[[:alnum:]]", "a/b", FNM_PATHNAME));

Check warning on line 91 in tests/posix/c_lib_ext/src/fnmatch.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

STRING_FRAGMENTS

tests/posix/c_lib_ext/src/fnmatch.c:91 Consecutive strings are generally better as a single string

Check warning on line 91 in tests/posix/c_lib_ext/src/fnmatch.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

STRING_FRAGMENTS

tests/posix/c_lib_ext/src/fnmatch.c:91 Consecutive strings are generally better as a single string

Check warning on line 91 in tests/posix/c_lib_ext/src/fnmatch.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

STRING_FRAGMENTS

tests/posix/c_lib_ext/src/fnmatch.c:91 Consecutive strings are generally better as a single string
zassert_ok(fnmatch("*[![:digit:]]*/[![:d-d]", "a/b", FNM_PATHNAME));
zassert_ok(fnmatch("*[![:digit:]]*/[[:d-d]", "a/[", FNM_PATHNAME));
}

Comment on lines +89 to +95
Copy link
Member

@cfriedt cfriedt Nov 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These change should be reverted, and the calls should all fail, according to SUSv3. See XCU 2.13.1, XBD 9.3.5

https://git.musl-libc.org/cgit/libc-testsuite/tree/fnmatch.c#n113

I'm just taking the musl libc tester's word for it though.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The first test is pretty clearly correct, although it relies upon having character class support.

The other two tests check for patterns containing invalid character class expressions. Here, I can understand the difference between musl and glibc. Glibc (and picolibc) interpret an invalid character class expression as the characters themselves, so [![:d-d] matches the complement of the set [ : d. Musl returns an error value, indicating that the expression was ill-formed.

https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap09.html#tag_09_03_05 seems unclear on this.

It does say that [ only introduces a bracket expression if the following characters form a valid bracket expression, so patterns which contain [ and then never contain an un-escaped ] are treated as a sequence of plain characters. For character classes, equivalence classes and collating sequences, it just says that they shall be followed by a valid expression and matching terminating sequence. I think that means that the behavior of fnmatch with these expressions is undefined, so we should remove these tests.

zassert_not_equal(fnmatch("*[![:digit:]]*/[![:d-d]", "a/[", FNM_PATHNAME), 0);
zassert_ok(fnmatch("a?b", "a.b", FNM_PATHNAME | FNM_PERIOD));
zassert_ok(fnmatch("a*b", "a.b", FNM_PATHNAME | FNM_PERIOD));
Expand Down
Loading