diff options
Diffstat (limited to 'gl/setenv.c')
| -rw-r--r-- | gl/setenv.c | 97 |
1 files changed, 93 insertions, 4 deletions
diff --git a/gl/setenv.c b/gl/setenv.c index 9e2e9e2f..ef301d41 100644 --- a/gl/setenv.c +++ b/gl/setenv.c | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* Copyright (C) 1992, 1995-2003, 2005-2024 Free Software Foundation, Inc. | 1 | /* Copyright (C) 1992, 1995-2003, 2005-2025 Free Software Foundation, Inc. |
| 2 | This file is part of the GNU C Library. | 2 | This file is part of the GNU C Library. |
| 3 | 3 | ||
| 4 | This file is free software: you can redistribute it and/or modify | 4 | This file is free software: you can redistribute it and/or modify |
| @@ -38,11 +38,23 @@ | |||
| 38 | # include <unistd.h> | 38 | # include <unistd.h> |
| 39 | #endif | 39 | #endif |
| 40 | 40 | ||
| 41 | #if defined _WIN32 && ! defined __CYGWIN__ | ||
| 42 | # define WIN32_LEAN_AND_MEAN | ||
| 43 | # include <windows.h> | ||
| 44 | #endif | ||
| 45 | |||
| 41 | #if !_LIBC | 46 | #if !_LIBC |
| 42 | # include "malloca.h" | 47 | # include "malloca.h" |
| 43 | #endif | 48 | #endif |
| 44 | 49 | ||
| 50 | #if defined _WIN32 && ! defined __CYGWIN__ | ||
| 51 | /* Don't assume that UNICODE is not defined. */ | ||
| 52 | # undef SetEnvironmentVariable | ||
| 53 | # define SetEnvironmentVariable SetEnvironmentVariableA | ||
| 54 | #endif | ||
| 55 | |||
| 45 | #if _LIBC || !HAVE_SETENV | 56 | #if _LIBC || !HAVE_SETENV |
| 57 | #if !HAVE_DECL__PUTENV | ||
| 46 | 58 | ||
| 47 | #if !_LIBC | 59 | #if !_LIBC |
| 48 | # define __environ environ | 60 | # define __environ environ |
| @@ -215,8 +227,7 @@ __add_to_environ (const char *name, const char *value, const char *combined, | |||
| 215 | } | 227 | } |
| 216 | 228 | ||
| 217 | if (__environ != last_environ) | 229 | if (__environ != last_environ) |
| 218 | memcpy ((char *) new_environ, (char *) __environ, | 230 | memcpy (new_environ, __environ, size * sizeof (char *)); |
| 219 | size * sizeof (char *)); | ||
| 220 | 231 | ||
| 221 | new_environ[size + 1] = NULL; | 232 | new_environ[size + 1] = NULL; |
| 222 | 233 | ||
| @@ -343,6 +354,84 @@ weak_alias (__setenv, setenv) | |||
| 343 | weak_alias (__clearenv, clearenv) | 354 | weak_alias (__clearenv, clearenv) |
| 344 | #endif | 355 | #endif |
| 345 | 356 | ||
| 357 | #else /* HAVE_DECL__PUTENV */ | ||
| 358 | /* Native Windows */ | ||
| 359 | |||
| 360 | int | ||
| 361 | setenv (const char *name, const char *value, int replace) | ||
| 362 | { | ||
| 363 | if (name == NULL || *name == '\0' || strchr (name, '=') != NULL) | ||
| 364 | { | ||
| 365 | errno = EINVAL; | ||
| 366 | return -1; | ||
| 367 | } | ||
| 368 | |||
| 369 | /* The Microsoft documentation | ||
| 370 | <https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/putenv-wputenv> | ||
| 371 | says: | ||
| 372 | "Don't change an environment entry directly: instead, | ||
| 373 | use _putenv or _wputenv to change it." | ||
| 374 | Note: Microsoft's _putenv updates not only the contents of _environ but | ||
| 375 | also the contents of _wenviron, so that both are in kept in sync. */ | ||
| 376 | const char *existing_value = getenv (name); | ||
| 377 | if (existing_value != NULL) | ||
| 378 | { | ||
| 379 | if (replace) | ||
| 380 | { | ||
| 381 | if (strcmp (existing_value, value) == 0) | ||
| 382 | /* No need to allocate memory. */ | ||
| 383 | return 0; | ||
| 384 | } | ||
| 385 | else | ||
| 386 | /* Keep the existing value. */ | ||
| 387 | return 0; | ||
| 388 | } | ||
| 389 | /* Allocate a new environment entry in the heap. */ | ||
| 390 | /* _putenv ("NAME=") unsets NAME, so if VALUE is the empty string, invoke | ||
| 391 | _putenv ("NAME= ") and fix up the result afterwards. */ | ||
| 392 | const char *value_ = (value[0] == '\0' ? " " : value); | ||
| 393 | size_t name_len = strlen (name); | ||
| 394 | size_t value_len = strlen (value_); | ||
| 395 | char *string = (char *) malloc (name_len + 1 + value_len + 1); | ||
| 396 | if (string == NULL) | ||
| 397 | return -1; | ||
| 398 | memcpy (string, name, name_len); | ||
| 399 | string[name_len] = '='; | ||
| 400 | memcpy (&string[name_len + 1], value_, value_len + 1); | ||
| 401 | /* Use _putenv. */ | ||
| 402 | if (_putenv (string) < 0) | ||
| 403 | return -1; | ||
| 404 | if (value[0] == '\0') | ||
| 405 | { | ||
| 406 | /* Fix up the result. */ | ||
| 407 | char *new_value = getenv (name); | ||
| 408 | if (new_value != NULL && new_value[0] == ' ' && new_value[1] == '\0') | ||
| 409 | new_value[0] = '\0'; | ||
| 410 | # if defined _WIN32 && ! defined __CYGWIN__ | ||
| 411 | /* _putenv propagated "NAME= " into the subprocess environment; | ||
| 412 | fix that by calling SetEnvironmentVariable directly. */ | ||
| 413 | /* Documentation: | ||
| 414 | <https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-setenvironmentvariable> */ | ||
| 415 | if (!SetEnvironmentVariable (name, "")) | ||
| 416 | { | ||
| 417 | switch (GetLastError ()) | ||
| 418 | { | ||
| 419 | case ERROR_NOT_ENOUGH_MEMORY: | ||
| 420 | case ERROR_OUTOFMEMORY: | ||
| 421 | errno = ENOMEM; | ||
| 422 | break; | ||
| 423 | default: | ||
| 424 | errno = EINVAL; | ||
| 425 | break; | ||
| 426 | } | ||
| 427 | return -1; | ||
| 428 | } | ||
| 429 | # endif | ||
| 430 | } | ||
| 431 | return 0; | ||
| 432 | } | ||
| 433 | |||
| 434 | #endif /* HAVE_DECL__PUTENV */ | ||
| 346 | #endif /* _LIBC || !HAVE_SETENV */ | 435 | #endif /* _LIBC || !HAVE_SETENV */ |
| 347 | 436 | ||
| 348 | /* The rest of this file is called into use when replacing an existing | 437 | /* The rest of this file is called into use when replacing an existing |
| @@ -360,7 +449,7 @@ int | |||
| 360 | rpl_setenv (const char *name, const char *value, int replace) | 449 | rpl_setenv (const char *name, const char *value, int replace) |
| 361 | { | 450 | { |
| 362 | int result; | 451 | int result; |
| 363 | if (!name || !*name || strchr (name, '=')) | 452 | if (name == NULL || *name == '\0' || strchr (name, '=') != NULL) |
| 364 | { | 453 | { |
| 365 | errno = EINVAL; | 454 | errno = EINVAL; |
| 366 | return -1; | 455 | return -1; |
