diff --git a/Ports/AvailablePorts.md b/Ports/AvailablePorts.md index 942fdd84ccbb60..a4018d4b535a85 100644 --- a/Ports/AvailablePorts.md +++ b/Ports/AvailablePorts.md @@ -49,7 +49,7 @@ This list is also available at [ports.serenityos.net](https://ports.serenityos.n | [`cowsay`](cowsay/) | cowsay | 3.04 | https://github.com/tnalpgge/rank-amateur-cowsay | | [`cpio`](cpio/) | GNU cpio archive utility | 2.15 | https://www.gnu.org/software/cpio/ | | [`curl`](curl/) | curl | 8.22.0 | https://curl.se/ | -| [`dash`](dash/) | DASH | 0.5.10.2 | http://gondor.apana.org.au/~herbert/dash | +| [`dash`](dash/) | DASH | 0.5.13.5 | http://gondor.apana.org.au/~herbert/dash | | [`deutex`](deutex/) | DeuTex | 5.2.3 | https://github.com/Doom-Utils/deutex | | [`DevilutionX`](DevilutionX/) | DevilutionX | 1.5.5 | https://github.com/diasurgical/DevilutionX | | [`dialog`](dialog/) | Dialog | 1.3-20260721 | https://invisible-island.net/dialog/ | diff --git a/Ports/dash/package.sh b/Ports/dash/package.sh index 530e83019172da..bce2a1be763308 100755 --- a/Ports/dash/package.sh +++ b/Ports/dash/package.sh @@ -1,9 +1,9 @@ #!/usr/bin/env -S bash ../.port_include.sh -port=dash -version=0.5.10.2 -useconfigure=true +port='dash' +version='0.5.13.5' +useconfigure='true' files=( - "http://gondor.apana.org.au/~herbert/dash/files/dash-${version}.tar.gz#3c663919dc5c66ec991da14c7cf7e0be8ad00f3db73986a987c118862b5f6071" + "http://gondor.apana.org.au/~herbert/dash/files/dash-${version}.tar.gz#40090101a2a491f13e901d3d48e90414f26634628b9bfff35ff540363c227a7d" ) configure() { diff --git a/Ports/dash/patches/0001-Replace-a-use-of-wait3-with-waitpid-in-the-job-contr.patch b/Ports/dash/patches/0001-Replace-a-use-of-wait3-with-waitpid-in-the-job-contr.patch index eb00d63f6488cd..1d410290701645 100644 --- a/Ports/dash/patches/0001-Replace-a-use-of-wait3-with-waitpid-in-the-job-contr.patch +++ b/Ports/dash/patches/0001-Replace-a-use-of-wait3-with-waitpid-in-the-job-contr.patch @@ -9,15 +9,15 @@ wait3() does not exist on serenity. 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jobs.c b/src/jobs.c -index 606d603..92ac84d 100644 +index 914b383a953d1e24c72e713ffa67d58895ea26b0..3e2f63ad60025339cf66a65c20c8cf26562a50d8 100644 --- a/src/jobs.c +++ b/src/jobs.c -@@ -1147,7 +1147,7 @@ waitproc(int block, int *status) - - do { - gotsigchld = 0; -- err = wait3(status, flags, NULL); -+ err = waitpid(-1, status, flags); - if (err || !block) - break; +@@ -1208,7 +1208,7 @@ waitproc(int block, int *status) + #ifdef HAVE_WAIT3 + err = wait3(status, flags, NULL); + #else +- err = waitpid((pid_t)-1, status, flags, NULL); ++ err = waitpid((pid_t)-1, status, flags); + #endif + while (err < 0 && errno == EINTR); diff --git a/Ports/dash/patches/0002-Skip-building-helpers-by-default.patch b/Ports/dash/patches/0002-Skip-building-helpers-by-default.patch index e0336f48d94302..902dbbb09554f4 100644 --- a/Ports/dash/patches/0002-Skip-building-helpers-by-default.patch +++ b/Ports/dash/patches/0002-Skip-building-helpers-by-default.patch @@ -9,10 +9,10 @@ Subject: [PATCH] Skip building helpers by default 2 files changed, 5 insertions(+) diff --git a/configure.ac b/configure.ac -index 4829288..9f9a155 100644 +index a247d95cc63f4434f5af3dcf741abb61170578c9..f99ba6093cdc65d8a846aa3fc7eacd5bfe87d3bf 100644 --- a/configure.ac +++ b/configure.ac -@@ -181,5 +181,8 @@ AC_ARG_ENABLE(lineno, AS_HELP_STRING(--disable-lineno, \ +@@ -228,5 +228,8 @@ AC_ARG_ENABLE(lineno, AS_HELP_STRING(--disable-lineno, \ if test "$enable_lineno" != "no"; then AC_DEFINE([WITH_LINENO], 1, [Define if you build with -DWITH_LINENO]) fi @@ -22,16 +22,16 @@ index 4829288..9f9a155 100644 AC_CONFIG_FILES([Makefile src/Makefile]) AC_OUTPUT diff --git a/src/Makefile.am b/src/Makefile.am -index 139355e..e95491a 100644 +index 173246535de4c8058a5f61ffbc3df569a44ec556..a128d0f2eb979e4a6aa0fddb2c2ee4e1bc622f76 100644 --- a/src/Makefile.am +++ b/src/Makefile.am -@@ -66,7 +66,9 @@ syntax.c syntax.h: mksyntax +@@ -64,7 +64,9 @@ syntax.c syntax.h: mksyntax signames.c: mksignames - ./$^ + $(AM_V_GEN)./$^ +if BUILD_HELPERS mksyntax: token.h $(HELPERS): %: %.c - $(COMPILE_FOR_BUILD) -o $@ $< + $(AM_V_CC)$(COMPILE_FOR_BUILD) -o $@ $< +endif diff --git a/Tests/LibC/CMakeLists.txt b/Tests/LibC/CMakeLists.txt index aa9c444bc3744b..a36ebdd976373d 100644 --- a/Tests/LibC/CMakeLists.txt +++ b/Tests/LibC/CMakeLists.txt @@ -34,6 +34,7 @@ set(TEST_SOURCES TestSnprintf.cpp TestStackSmash.cpp TestStdio.cpp + TestStpncpy.cpp TestStrlcpy.cpp TestStrtodAccuracy.cpp TestTruncate.cpp diff --git a/Tests/LibC/TestStpncpy.cpp b/Tests/LibC/TestStpncpy.cpp new file mode 100644 index 00000000000000..a7885a9acb2cca --- /dev/null +++ b/Tests/LibC/TestStpncpy.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2026, Linus Groh + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include + +#include + +TEST_CASE(src_longer_than_dest) +{ + char dest[8] = {}; + memset(dest, 'X', sizeof(dest)); + + char* result = stpncpy(dest, "Hello World!", sizeof(dest)); + EXPECT_EQ(result, dest + sizeof(dest)); + EXPECT(memcmp(dest, "Hello Wo", sizeof(dest)) == 0); +} + +TEST_CASE(src_shorter_than_dest) +{ + char dest[8] = {}; + memset(dest, 'X', sizeof(dest)); + + char* result = stpncpy(dest, "Hello", sizeof(dest)); + EXPECT_EQ(result, dest + 5); + EXPECT(memcmp(dest, "Hello\0\0\0", sizeof(dest)) == 0); +} + +TEST_CASE(dest_empty) +{ + char dest[8] = {}; + memset(dest, 'X', sizeof(dest)); + + char* result = stpncpy(dest, "Hello World!", 0); + EXPECT_EQ(result, dest); + EXPECT(memcmp(dest, "XXXXXXXX", sizeof(dest)) == 0); +} + +TEST_CASE(nul_in_src) +{ + char dest[8] = {}; + memset(dest, 'X', sizeof(dest)); + + char const src[] = { 'a', 'b', '\0', 'c', 'd' }; + char* result = stpncpy(dest, src, sizeof(dest)); + EXPECT_EQ(result, dest + 2); + EXPECT(memcmp(dest, "ab\0\0\0\0\0\0", sizeof(dest)) == 0); +} diff --git a/Userland/Libraries/LibC/string.cpp b/Userland/Libraries/LibC/string.cpp index cb30931cba729e..78b3604c3f13db 100644 --- a/Userland/Libraries/LibC/string.cpp +++ b/Userland/Libraries/LibC/string.cpp @@ -219,6 +219,18 @@ char* stpcpy(char* dest, char const* src) return dest; } +// https://pubs.opengroup.org/onlinepubs/9699919799/functions/stpncpy.html +char* stpncpy(char* dest, char const* src, size_t n) +{ + size_t i; + for (i = 0; i < n && src[i] != '\0'; ++i) + dest[i] = src[i]; + char* result = &dest[i]; + for (; i < n; ++i) + dest[i] = '\0'; + return result; +} + // https://pubs.opengroup.org/onlinepubs/9699919799/functions/strncpy.html char* strncpy(char* dest, char const* src, size_t n) { diff --git a/Userland/Libraries/LibC/string.h b/Userland/Libraries/LibC/string.h index 657aa41369a424..a648e679608e0a 100644 --- a/Userland/Libraries/LibC/string.h +++ b/Userland/Libraries/LibC/string.h @@ -48,6 +48,7 @@ __attribute__((malloc)) char* strndup(char const*, size_t); char* strcpy(char* dest, char const* src); char* stpcpy(char* dest, char const* src); char* strncpy(char* dest, char const* src, size_t); +char* stpncpy(char* dest, char const* src, size_t); __attribute__((warn_unused_result)) size_t strlcpy(char* dest, char const* src, size_t); char* strchr(char const*, int c);