setenv.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. /* Copyright (C) 1992-2022 Free Software Foundation, Inc.
  2. This file based on setenv.c in the GNU C Library.
  3. The GNU C Library is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU Library General Public License as
  5. published by the Free Software Foundation; either version 2 of the
  6. License, or (at your option) any later version.
  7. The GNU C Library is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  10. Library General Public License for more details.
  11. You should have received a copy of the GNU Library General Public
  12. License along with the GNU C Library; see the file COPYING.LIB. If not,
  13. write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
  14. Boston, MA 02110-1301, USA. */
  15. /*
  16. @deftypefn Supplemental int setenv (const char *@var{name}, @
  17. const char *@var{value}, int @var{overwrite})
  18. @deftypefnx Supplemental void unsetenv (const char *@var{name})
  19. @code{setenv} adds @var{name} to the environment with value
  20. @var{value}. If the name was already present in the environment,
  21. the new value will be stored only if @var{overwrite} is nonzero.
  22. The companion @code{unsetenv} function removes @var{name} from the
  23. environment. This implementation is not safe for multithreaded code.
  24. @end deftypefn
  25. */
  26. #if HAVE_CONFIG_H
  27. # include <config.h>
  28. #endif
  29. #define setenv libiberty_setenv
  30. #define unsetenv libiberty_unsetenv
  31. #include "ansidecl.h"
  32. #include <sys/types.h> /* For `size_t' */
  33. #include <stdio.h> /* For `NULL' */
  34. #include <errno.h>
  35. #if !defined(errno) && !defined(HAVE_ERRNO_DECL)
  36. extern int errno;
  37. #endif
  38. #define __set_errno(ev) ((errno) = (ev))
  39. #if HAVE_STDLIB_H
  40. # include <stdlib.h>
  41. #endif
  42. #if HAVE_STRING_H
  43. # include <string.h>
  44. #endif
  45. #if HAVE_UNISTD_H
  46. # include <unistd.h>
  47. #endif
  48. #define __environ environ
  49. #include "environ.h"
  50. #undef setenv
  51. #undef unsetenv
  52. /* LOCK and UNLOCK are defined as no-ops. This makes the libiberty
  53. * implementation MT-Unsafe. */
  54. #define LOCK
  55. #define UNLOCK
  56. /* Below this point, it's verbatim code from the glibc-2.0 implementation */
  57. /* If this variable is not a null pointer we allocated the current
  58. environment. */
  59. static char **last_environ;
  60. int
  61. setenv (const char *name, const char *value, int replace)
  62. {
  63. register char **ep = 0;
  64. register size_t size;
  65. const size_t namelen = strlen (name);
  66. const size_t vallen = strlen (value) + 1;
  67. LOCK;
  68. size = 0;
  69. if (__environ != NULL)
  70. {
  71. for (ep = __environ; *ep != NULL; ++ep)
  72. if (!strncmp (*ep, name, namelen) && (*ep)[namelen] == '=')
  73. break;
  74. else
  75. ++size;
  76. }
  77. if (__environ == NULL || *ep == NULL)
  78. {
  79. char **new_environ;
  80. if (__environ == last_environ && __environ != NULL)
  81. /* We allocated this space; we can extend it. */
  82. new_environ = (char **) realloc (last_environ,
  83. (size + 2) * sizeof (char *));
  84. else
  85. new_environ = (char **) malloc ((size + 2) * sizeof (char *));
  86. if (new_environ == NULL)
  87. {
  88. UNLOCK;
  89. return -1;
  90. }
  91. new_environ[size] = (char *) malloc (namelen + 1 + vallen);
  92. if (new_environ[size] == NULL)
  93. {
  94. free ((char *) new_environ);
  95. __set_errno (ENOMEM);
  96. UNLOCK;
  97. return -1;
  98. }
  99. if (__environ != last_environ)
  100. memcpy ((char *) new_environ, (char *) __environ,
  101. size * sizeof (char *));
  102. memcpy (new_environ[size], name, namelen);
  103. new_environ[size][namelen] = '=';
  104. memcpy (&new_environ[size][namelen + 1], value, vallen);
  105. new_environ[size + 1] = NULL;
  106. last_environ = __environ = new_environ;
  107. }
  108. else if (replace)
  109. {
  110. size_t len = strlen (*ep);
  111. if (len + 1 < namelen + 1 + vallen)
  112. {
  113. /* The existing string is too short; malloc a new one. */
  114. char *new_string = (char *) malloc (namelen + 1 + vallen);
  115. if (new_string == NULL)
  116. {
  117. UNLOCK;
  118. return -1;
  119. }
  120. *ep = new_string;
  121. }
  122. memcpy (*ep, name, namelen);
  123. (*ep)[namelen] = '=';
  124. memcpy (&(*ep)[namelen + 1], value, vallen);
  125. }
  126. UNLOCK;
  127. return 0;
  128. }
  129. void
  130. unsetenv (const char *name)
  131. {
  132. const size_t len = strlen (name);
  133. char **ep;
  134. LOCK;
  135. for (ep = __environ; *ep; ++ep)
  136. if (!strncmp (*ep, name, len) && (*ep)[len] == '=')
  137. {
  138. /* Found it. Remove this pointer by moving later ones back. */
  139. char **dp = ep;
  140. do
  141. dp[0] = dp[1];
  142. while (*dp++);
  143. /* Continue the loop in case NAME appears again. */
  144. }
  145. UNLOCK;
  146. }