attribute: Improve documentation.
[gnulib.git] / lib / unsetenv.c
blob5e989968c1e987c1b3fdea28d21a2899e35c031b
1 /* Copyright (C) 1992, 1995-2002, 2005-2024 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2.1 of the
7 License, or (at your option) any later version.
9 This file is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17 /* Don't use __attribute__ __nonnull__ in this compilation unit. Otherwise gcc
18 optimizes away the name == NULL test below. */
19 #define _GL_ARG_NONNULL(params)
21 #include <config.h>
23 /* Specification. */
24 #include <stdlib.h>
26 #include <errno.h>
27 #if !_LIBC
28 # define __set_errno(ev) ((errno) = (ev))
29 #endif
31 #include <string.h>
32 #include <unistd.h>
34 #if !_LIBC
35 # define __environ environ
36 #endif
38 #if _LIBC
39 /* This lock protects against simultaneous modifications of 'environ'. */
40 # include <bits/libc-lock.h>
41 __libc_lock_define_initialized (static, envlock)
42 # define LOCK __libc_lock_lock (envlock)
43 # define UNLOCK __libc_lock_unlock (envlock)
44 #else
45 # define LOCK
46 # define UNLOCK
47 #endif
49 /* In the GNU C library we must keep the namespace clean. */
50 #ifdef _LIBC
51 # define unsetenv __unsetenv
52 #endif
54 #if _LIBC || !HAVE_UNSETENV
56 int
57 unsetenv (const char *name)
59 size_t len;
61 if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
63 __set_errno (EINVAL);
64 return -1;
67 len = strlen (name);
69 #if HAVE_DECL__PUTENV /* native Windows */
70 /* The Microsoft documentation
71 <https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/putenv-wputenv>
72 says:
73 "Don't change an environment entry directly: instead,
74 use _putenv or _wputenv to change it."
75 Note: Microsoft's _putenv updates not only the contents of _environ but
76 also the contents of _wenviron, so that both are in kept in sync.
78 The way to remove an environment variable is to pass to _putenv a string
79 of the form "NAME=". (NB: This is a different convention than with glibc
80 putenv, which expects a string of the form "NAME"!) */
82 int putenv_result;
83 char *name_ = malloc (len + 2);
84 if (name_ == NULL)
85 return -1;
86 memcpy (name_, name, len);
87 name_[len] = '=';
88 name_[len + 1] = 0;
89 putenv_result = _putenv (name_);
90 /* In this particular case it is OK to free() the argument passed to
91 _putenv. */
92 free (name_);
93 return putenv_result;
95 #else
97 LOCK;
99 char **ep = __environ;
100 while (*ep != NULL)
101 if (!strncmp (*ep, name, len) && (*ep)[len] == '=')
103 /* Found it. Remove this pointer by moving later ones back. */
104 char **dp = ep;
107 dp[0] = dp[1];
108 while (*dp++);
109 /* Continue the loop in case NAME appears again. */
111 else
112 ++ep;
114 UNLOCK;
116 return 0;
117 #endif
120 #ifdef _LIBC
121 # undef unsetenv
122 weak_alias (__unsetenv, unsetenv)
123 #endif
125 #else /* HAVE_UNSETENV */
127 # undef unsetenv
128 # if !HAVE_DECL_UNSETENV
129 # if VOID_UNSETENV
130 extern void unsetenv (const char *);
131 # else
132 extern int unsetenv (const char *);
133 # endif
134 # endif
136 /* Call the underlying unsetenv, in case there is hidden bookkeeping
137 that needs updating beyond just modifying environ. */
139 rpl_unsetenv (const char *name)
141 int result = 0;
142 if (!name || !*name || strchr (name, '='))
144 errno = EINVAL;
145 return -1;
147 while (getenv (name))
148 # if !VOID_UNSETENV
149 result =
150 # endif
151 unsetenv (name);
152 return result;
155 #endif /* HAVE_UNSETENV */