/* Copyright (C) 2011-2024 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