1/* getenv.c - get environment variable value from the shell's variable
2	      list. */
3
4/* Copyright (C) 1997-2002 Free Software Foundation, Inc.
5
6   This file is part of GNU Bash, the Bourne Again SHell.
7
8   Bash is free software; you can redistribute it and/or modify it under
9   the terms of the GNU General Public License as published by the Free
10   Software Foundation; either version 2, or (at your option) any later
11   version.
12
13   Bash is distributed in the hope that it will be useful, but WITHOUT ANY
14   WARRANTY; without even the implied warranty of MERCHANTABILITY or
15   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16   for more details.
17
18   You should have received a copy of the GNU General Public License along
19   with Bash; see the file COPYING.  If not, write to the Free Software
20   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA */
21
22#include <config.h>
23
24#if defined (CAN_REDEFINE_GETENV)
25
26#if defined (HAVE_UNISTD_H)
27#  include <unistd.h>
28#endif
29
30#include <bashansi.h>
31#include <errno.h>
32#include <shell.h>
33
34#ifndef errno
35extern int errno;
36#endif
37
38extern char **environ;
39
40/* We supply our own version of getenv () because we want library
41   routines to get the changed values of exported variables. */
42
43/* The NeXT C library has getenv () defined and used in the same file.
44   This screws our scheme.  However, Bash will run on the NeXT using
45   the C library getenv (), since right now the only environment variable
46   that we care about is HOME, and that is already defined.  */
47static char *last_tempenv_value = (char *)NULL;
48
49char *
50getenv (name)
51     const char *name;
52{
53  SHELL_VAR *var;
54
55  if (name == 0 || *name == '\0')
56    return ((char *)NULL);
57
58  var = find_tempenv_variable ((char *)name);
59  if (var)
60    {
61      FREE (last_tempenv_value);
62
63      last_tempenv_value = value_cell (var) ? savestring (value_cell (var)) : (char *)NULL;
64      return (last_tempenv_value);
65    }
66  else if (shell_variables)
67    {
68      var = find_variable ((char *)name);
69      if (var && exported_p (var))
70	return (value_cell (var));
71    }
72  else
73    {
74      register int i, len;
75
76      /* In some cases, s5r3 invokes getenv() before main(); BSD systems
77	 using gprof also exhibit this behavior.  This means that
78	 shell_variables will be 0 when this is invoked.  We look up the
79	 variable in the real environment in that case. */
80
81      for (i = 0, len = strlen (name); environ[i]; i++)
82	{
83	  if ((STREQN (environ[i], name, len)) && (environ[i][len] == '='))
84	    return (environ[i] + len + 1);
85	}
86    }
87
88  return ((char *)NULL);
89}
90
91/* Some versions of Unix use _getenv instead. */
92char *
93_getenv (name)
94     const char *name;
95{
96  return (getenv (name));
97}
98
99/* SUSv3 says argument is a `char *'; BSD implementations disagree */
100int
101putenv (str)
102#ifndef HAVE_STD_PUTENV
103     const char *str;
104#else
105     char *str;
106#endif
107{
108  SHELL_VAR *var;
109  char *name, *value;
110  int offset;
111
112  if (str == 0 || *str == '\0')
113    {
114      errno = EINVAL;
115      return -1;
116    }
117
118  offset = assignment (str, 0);
119  if (str[offset] != '=')
120    {
121      errno = EINVAL;
122      return -1;
123    }
124  name = savestring (str);
125  name[offset] = 0;
126
127  value = name + offset + 1;
128
129  /* XXX - should we worry about readonly here? */
130  var = bind_variable (name, value, 0);
131  if (var == 0)
132    {
133      errno = EINVAL;
134      return -1;
135    }
136
137  VUNSETATTR (var, att_invisible);
138  VSETATTR (var, att_exported);
139
140  return 0;
141}
142
143#if 0
144int
145_putenv (name)
146#ifndef HAVE_STD_PUTENV
147     const char *name;
148#else
149     char *name;
150#endif
151{
152  return putenv (name);
153}
154#endif
155
156int
157setenv (name, value, rewrite)
158     const char *name;
159     const char *value;
160     int rewrite;
161{
162  SHELL_VAR *var;
163  char *v;
164
165  if (name == 0 || *name == '\0' || strchr (name, '=') != 0)
166    {
167      errno = EINVAL;
168      return -1;
169    }
170
171  var = 0;
172  v = (char *)value;	/* some compilers need explicit cast */
173  /* XXX - should we worry about readonly here? */
174  if (rewrite == 0)
175    var = find_variable (name);
176
177  if (var == 0)
178    var = bind_variable (name, v, 0);
179
180  if (var == 0)
181    return -1;
182
183  VUNSETATTR (var, att_invisible);
184  VSETATTR (var, att_exported);
185
186  return 0;
187}
188
189#if 0
190int
191_setenv (name, value, rewrite)
192     const char *name;
193     const char *value;
194     int rewrite;
195{
196  return setenv (name, value, rewrite);
197}
198#endif
199
200/* SUSv3 says unsetenv returns int; existing implementations (BSD) disagree. */
201
202#ifdef HAVE_STD_UNSETENV
203#define UNSETENV_RETURN(N)	return(N)
204#define UNSETENV_RETTYPE	int
205#else
206#define UNSETENV_RETURN(N)	return
207#define UNSETENV_RETTYPE	void
208#endif
209
210UNSETENV_RETTYPE
211unsetenv (name)
212     const char *name;
213{
214  if (name == 0 || *name == '\0' || strchr (name, '=') != 0)
215    {
216      errno = EINVAL;
217      UNSETENV_RETURN(-1);
218    }
219
220  /* XXX - should we just remove the export attribute here? */
221#if 1
222  unbind_variable (name);
223#else
224  SHELL_VAR *v;
225
226  v = find_variable (name);
227  if (v)
228    VUNSETATTR (v, att_exported);
229#endif
230
231  UNSETENV_RETURN(0);
232}
233#endif /* CAN_REDEFINE_GETENV */
234