]> Savannah Git Hosting - gnulib.git/commitdiff
wgetcwd-lgpl: New module.
authorBruno Haible <bruno@clisp.org>
Sat, 30 Sep 2023 14:20:14 +0000 (16:20 +0200)
committerBruno Haible <bruno@clisp.org>
Sat, 30 Sep 2023 17:31:32 +0000 (19:31 +0200)
* 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
lib/wchar.in.h
lib/wgetcwd-lgpl.c [new file with mode: 0644]
m4/wchar_h.m4
modules/wchar
modules/wgetcwd-lgpl [new file with mode: 0644]

index f8082c30a9f99460d166f145ea5687916c64909c..cde3af62050d93824860ed941c96fb4c267f1a25 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2023-09-30  Bruno Haible  <bruno@clisp.org>
+
+       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  <bruno@clisp.org>
 
        getcwd-lgpl: Tweaks.
index f1bbff6b94305e477356ea5e8693ef89fec07ab6..f114bce3f1e540ac5fbc55956ed528b042ab6811 100644 (file)
@@ -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 (file)
index 0000000..922e0fb
--- /dev/null
@@ -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 <https://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+/* Specification */
+#include <wchar.h>
+
+#include <errno.h>
+#include <stdlib.h>
+
+#if defined _WIN32 && !defined __CYGWIN__
+
+wchar_t *
+wgetcwd (wchar_t *buf, size_t size)
+{
+  wchar_t *result;
+
+  /* Uses _wgetcwd.
+     Documentation:
+     <https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/getcwd-wgetcwd>
+     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
index 31f5b0794d97805247af77e91600024d406e1316..8d622936467528c8140032527cef237bb3099436 100644 (file)
@@ -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])
   ])
index ebdd0ece614c65e5e48a8768e9b0ae5804c5f430..393b2b18370126557f404fbd5761753449bae789 100644 (file)
@@ -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 (file)
index 0000000..ed33406
--- /dev/null
@@ -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:
+<wchar.h>
+
+License:
+LGPLv2+
+
+Maintainer:
+all