From bc73de46f7134509bff08ad65c0a5f1700d55c71 Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Sat, 30 Sep 2023 16:20:14 +0200 Subject: [PATCH] wgetcwd-lgpl: New module. * lib/wchar.in.h (wgetcwd): New declaration. * lib/wgetcwd-lgpl.c: New file, based on lib/getcwd-lgpl.c. * m4/wchar_h.m4 (gl_WCHAR_H_REQUIRE_DEFAULTS): Initialize GNULIB_WGETCWD. * modules/wchar (Makefile.am): Substitute GNULIB_WGETCWD. * modules/wgetcwd-lgpl: New file. --- ChangeLog | 10 ++++ lib/wchar.in.h | 18 ++++++ lib/wgetcwd-lgpl.c | 134 +++++++++++++++++++++++++++++++++++++++++++ m4/wchar_h.m4 | 3 +- modules/wchar | 1 + modules/wgetcwd-lgpl | 25 ++++++++ 6 files changed, 190 insertions(+), 1 deletion(-) create mode 100644 lib/wgetcwd-lgpl.c create mode 100644 modules/wgetcwd-lgpl diff --git a/ChangeLog b/ChangeLog index f8082c30a9..cde3af6205 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2023-09-30 Bruno Haible + + wgetcwd-lgpl: New module. + * lib/wchar.in.h (wgetcwd): New declaration. + * lib/wgetcwd-lgpl.c: New file, based on lib/getcwd-lgpl.c. + * m4/wchar_h.m4 (gl_WCHAR_H_REQUIRE_DEFAULTS): Initialize + GNULIB_WGETCWD. + * modules/wchar (Makefile.am): Substitute GNULIB_WGETCWD. + * modules/wgetcwd-lgpl: New file. + 2023-09-30 Bruno Haible getcwd-lgpl: Tweaks. diff --git a/lib/wchar.in.h b/lib/wchar.in.h index f1bbff6b94..f114bce3f1 100644 --- a/lib/wchar.in.h +++ b/lib/wchar.in.h @@ -1684,6 +1684,24 @@ _GL_WARN_ON_USE (wcsftime, "wcsftime is unportable - " #endif +#if @GNULIB_WGETCWD@ && (defined _WIN32 && !defined __CYGWIN__) +/* Gets the name of the current working directory. + (a) If BUF is non-NULL, it is assumed to have room for SIZE wide characters. + This function stores the working directory (NUL-terminated) in BUF and + returns BUF. + (b) If BUF is NULL, an array is allocated with 'malloc'. The array is SIZE + wide characters long, unless SIZE == 0, in which case it is as big as + necessary. + If the directory couldn't be determined or SIZE was too small, this function + returns NULL and sets errno. For a directory of length LEN, SIZE should be + >= LEN + 3 in case (a) or >= LEN + 1 in case (b). + Possible errno values include: + - ERANGE if SIZE is too small. + - ENOMEM if the memory could no be allocated. */ +_GL_FUNCDECL_SYS (wgetcwd, wchar_t *, (wchar_t *buf, size_t size)); +#endif + + #endif /* _@GUARD_PREFIX@_WCHAR_H */ #endif /* _@GUARD_PREFIX@_WCHAR_H */ #endif diff --git a/lib/wgetcwd-lgpl.c b/lib/wgetcwd-lgpl.c new file mode 100644 index 0000000000..922e0fb810 --- /dev/null +++ b/lib/wgetcwd-lgpl.c @@ -0,0 +1,134 @@ +/* Copyright (C) 2011-2023 Free Software Foundation, Inc. + This file is part of gnulib. + + This file is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . */ + +#include + +/* Specification */ +#include + +#include +#include + +#if defined _WIN32 && !defined __CYGWIN__ + +wchar_t * +wgetcwd (wchar_t *buf, size_t size) +{ + wchar_t *result; + + /* Uses _wgetcwd. + Documentation: + + Note that for a directory consisting of LEN wide characters, the SIZE + argument to _wgetcwd needs to be >= LEN + 3, not only >= LEN + 1, with + some versions of the Microsoft runtime libraries. */ + + /* Handle single size operations. */ + if (buf) + { + /* Check SIZE argument. */ + if (!size) + { + errno = EINVAL; + return NULL; + } + /* Invoke _wgetcwd as-is. In this case, the caller does not expect + an ENOMEM error; therefore don't use temporary memory. */ + return _wgetcwd (buf, size); + } + + if (size) + { + /* Allocate room for two more wide characters, so that directory names + of length <= SIZE - 1 can be returned. */ + buf = malloc ((size + 2) * sizeof (wchar_t)); + if (!buf) + { + errno = ENOMEM; + return NULL; + } + result = _wgetcwd (buf, size + 2); + if (!result) + { + free (buf); + return NULL; + } + if (wcslen (result) >= size) + { + free (buf); + errno = ERANGE; + return NULL; + } + /* Shrink result before returning it. */ + wchar_t *shrinked_result = realloc (result, size * sizeof (wchar_t)); + if (shrinked_result != NULL) + result = shrinked_result; + return result; + } + + /* Flexible sizing requested. Avoid over-allocation for the common + case of a name that fits within a 4k page, minus some space for + local variables, to be sure we don't skip over a guard page. */ + { + wchar_t tmp[4032 / sizeof (wchar_t)]; + size = sizeof tmp / sizeof (wchar_t); + wchar_t *ptr = _wgetcwd (tmp, size); + if (ptr) + { + result = _wcsdup (ptr); + if (!result) + errno = ENOMEM; + return result; + } + if (errno != ERANGE) + return NULL; + } + + /* My what a large directory name we have. */ + do + { + size <<= 1; + wchar_t *ptr = realloc (buf, size * sizeof (wchar_t)); + if (ptr == NULL) + { + free (buf); + errno = ENOMEM; + return NULL; + } + buf = ptr; + result = _wgetcwd (buf, size); + } + while (!result && errno == ERANGE); + + if (!result) + free (buf); + else + { + /* Here result == buf. */ + /* Shrink result before returning it. */ + size_t actual_size = wcslen (result) + 1; + if (actual_size < size) + { + wchar_t *shrinked_result = + realloc (result, actual_size * sizeof (wchar_t)); + if (shrinked_result != NULL) + result = shrinked_result; + } + } + return result; +} + +#endif diff --git a/m4/wchar_h.m4 b/m4/wchar_h.m4 index 31f5b0794d..8d62293646 100644 --- a/m4/wchar_h.m4 +++ b/m4/wchar_h.m4 @@ -7,7 +7,7 @@ dnl with or without modifications, as long as this notice is preserved. dnl Written by Eric Blake. -# wchar_h.m4 serial 61 +# wchar_h.m4 serial 62 AC_DEFUN_ONCE([gl_WCHAR_H], [ @@ -186,6 +186,7 @@ AC_DEFUN([gl_WCHAR_H_REQUIRE_DEFAULTS], gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_WCSTOK]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_WCSWIDTH]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_WCSFTIME]) + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_WGETCWD]) dnl Support Microsoft deprecated alias function names by default. gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_WCSDUP], [1]) ]) diff --git a/modules/wchar b/modules/wchar index ebdd0ece61..393b2b1837 100644 --- a/modules/wchar +++ b/modules/wchar @@ -82,6 +82,7 @@ wchar.h: wchar.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) -e 's/@''GNULIB_WCSTOK''@/$(GNULIB_WCSTOK)/g' \ -e 's/@''GNULIB_WCSWIDTH''@/$(GNULIB_WCSWIDTH)/g' \ -e 's/@''GNULIB_WCSFTIME''@/$(GNULIB_WCSFTIME)/g' \ + -e 's/@''GNULIB_WGETCWD''@/$(GNULIB_WGETCWD)/g' \ -e 's/@''GNULIB_MDA_WCSDUP''@/$(GNULIB_MDA_WCSDUP)/g' \ -e 's/@''GNULIB_FREE_POSIX''@/$(GNULIB_FREE_POSIX)/g' \ < $(srcdir)/wchar.in.h > $@-t1 diff --git a/modules/wgetcwd-lgpl b/modules/wgetcwd-lgpl new file mode 100644 index 0000000000..ed33406737 --- /dev/null +++ b/modules/wgetcwd-lgpl @@ -0,0 +1,25 @@ +Description: +Native Windows specific wgetcwd function. Like _wgetcwd, but also ensure +that wgetcwd(NULL, 0) returns a buffer allocated by the malloc() function. + +Files: +lib/wgetcwd-lgpl.c + +Depends-on: +wchar +free-posix + +configure.ac: +gl_WCHAR_MODULE_INDICATOR([wgetcwd]) + +Makefile.am: +lib_SOURCES += wgetcwd-lgpl.c + +Include: + + +License: +LGPLv2+ + +Maintainer: +all -- 2.39.5