d0573c69f144b8b21c272e69b961b29d4461ad8a
[gnulib.git] / lib / putenv.c
1 /* Copyright (C) 1991, 1994, 1997-1998, 2000, 2003-2008
2    Free Software Foundation, Inc.
3
4    NOTE: The canonical source of this file is maintained with the GNU C
5    Library.  Bugs can be reported to bug-glibc@prep.ai.mit.edu.
6
7    This program is free software: you can redistribute it and/or modify it
8    under the terms of the GNU General Public License as published by the
9    Free Software Foundation; either version 3 of the License, or any
10    later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
19
20 #include <config.h>
21
22 /* Specification.  */
23 #include <stdlib.h>
24
25 #include <stddef.h>
26
27 /* Include errno.h *after* sys/types.h to work around header problems
28    on AIX 3.2.5.  */
29 #include <errno.h>
30 #ifndef __set_errno
31 # define __set_errno(ev) ((errno) = (ev))
32 #endif
33
34 #include <stdlib.h>
35 #include <string.h>
36 #include <unistd.h>
37
38 #if HAVE_GNU_LD
39 # define environ __environ
40 #else
41 extern char **environ;
42 #endif
43
44 #if _LIBC
45 /* This lock protects against simultaneous modifications of `environ'.  */
46 # include <bits/libc-lock.h>
47 __libc_lock_define_initialized (static, envlock)
48 # define LOCK   __libc_lock_lock (envlock)
49 # define UNLOCK __libc_lock_unlock (envlock)
50 #else
51 # define LOCK
52 # define UNLOCK
53 #endif
54
55 static int
56 _unsetenv (const char *name)
57 {
58   size_t len;
59   char **ep;
60
61   if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
62     {
63       __set_errno (EINVAL);
64       return -1;
65     }
66
67   len = strlen (name);
68
69   LOCK;
70
71   ep = environ;
72   while (*ep != NULL)
73     if (!strncmp (*ep, name, len) && (*ep)[len] == '=')
74       {
75         /* Found it.  Remove this pointer by moving later ones back.  */
76         char **dp = ep;
77
78         do
79           dp[0] = dp[1];
80         while (*dp++);
81         /* Continue the loop in case NAME appears again.  */
82       }
83     else
84       ++ep;
85
86   UNLOCK;
87
88   return 0;
89 }
90
91
92 /* Put STRING, which is of the form "NAME=VALUE", in the environment.
93    If STRING contains no `=', then remove STRING from the environment.  */
94 int
95 putenv (char *string)
96 {
97   const char *const name_end = strchr (string, '=');
98   register size_t size;
99   register char **ep;
100
101   if (name_end == NULL)
102     {
103       /* Remove the variable from the environment.  */
104       return _unsetenv (string);
105     }
106
107   size = 0;
108   for (ep = environ; *ep != NULL; ++ep)
109     if (!strncmp (*ep, string, name_end - string) &&
110         (*ep)[name_end - string] == '=')
111       break;
112     else
113       ++size;
114
115   if (*ep == NULL)
116     {
117       static char **last_environ = NULL;
118       char **new_environ = (char **) malloc ((size + 2) * sizeof (char *));
119       if (new_environ == NULL)
120         return -1;
121       (void) memcpy ((void *) new_environ, (void *) environ,
122                      size * sizeof (char *));
123       new_environ[size] = (char *) string;
124       new_environ[size + 1] = NULL;
125       free (last_environ);
126       last_environ = new_environ;
127       environ = new_environ;
128     }
129   else
130     *ep = string;
131
132   return 0;
133 }