update copyright date
[gnulib.git] / lib / setenv.c
1 /* Copyright (C) 1992, 1995, 2000 Free Software Foundation, Inc.
2
3 NOTE: The canonical source of this file is maintained with the GNU C Library.
4 Bugs can be reported to bug-glibc@prep.ai.mit.edu.
5
6 This program is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
9 later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
19 USA.  */
20
21 #ifdef HAVE_CONFIG_H
22 # include <config.h>
23 #endif
24
25 #include <errno.h>
26
27 #if _LIBC || HAVE_STDLIB_H
28 # include <stdlib.h>
29 #endif
30 #if _LIBC || HAVE_STRING_H
31 # include <string.h>
32 #endif
33 #if _LIBC || HAVE_UNISTD_H
34 # include <unistd.h>
35 #endif
36
37 #ifndef HAVE_GNU_LD
38 # define __environ      environ
39 #endif
40
41 int
42 setenv (name, value, replace)
43      const char *name;
44      const char *value;
45      int replace;
46 {
47   register char **ep;
48   register size_t size;
49   const size_t namelen = strlen (name);
50   const size_t vallen = strlen (value) + 1;
51
52   size = 0;
53   for (ep = __environ; *ep != NULL; ++ep)
54     if (!strncmp (*ep, name, namelen) && (*ep)[namelen] == '=')
55       break;
56     else
57       ++size;
58
59   if (*ep == NULL)
60     {
61       static char **last_environ;
62       char **new_environ;
63       if (__environ == last_environ)
64         /* We allocated this space; we can extend it.  */
65         new_environ = (char **) realloc (last_environ,
66                                          (size + 2) * sizeof (char *));
67       else
68         new_environ = (char **) malloc ((size + 2) * sizeof (char *));
69
70       if (new_environ == NULL)
71         return -1;
72
73       new_environ[size] = malloc (namelen + 1 + vallen);
74       if (new_environ[size] == NULL)
75         {
76           free ((char *) new_environ);
77           errno = ENOMEM;
78           return -1;
79         }
80
81       if (__environ != last_environ)
82         memcpy ((char *) new_environ, (char *) __environ,
83                 size * sizeof (char *));
84
85       memcpy (new_environ[size], name, namelen);
86       new_environ[size][namelen] = '=';
87       memcpy (&new_environ[size][namelen + 1], value, vallen);
88
89       new_environ[size + 1] = NULL;
90
91       last_environ = __environ = new_environ;
92     }
93   else if (replace)
94     {
95       size_t len = strlen (*ep);
96       if (len + 1 < namelen + 1 + vallen)
97         {
98           /* The existing string is too short; malloc a new one.  */
99           char *new = malloc (namelen + 1 + vallen);
100           if (new == NULL)
101             return -1;
102           *ep = new;
103         }
104       memcpy (*ep, name, namelen);
105       (*ep)[namelen] = '=';
106       memcpy (&(*ep)[namelen + 1], value, vallen);
107     }
108
109   return 0;
110 }
111
112 void
113 unsetenv (name)
114      const char *name;
115 {
116   const size_t len = strlen (name);
117   char **ep;
118
119   for (ep = __environ; *ep; ++ep)
120     if (!strncmp (*ep, name, len) && (*ep)[len] == '=')
121       {
122         /* Found it.  Remove this pointer by moving later ones back.  */
123         char **dp = ep;
124         do
125           dp[0] = dp[1];
126         while (*dp++);
127         /* Continue the loop in case NAME appears again.  */
128       }
129 }