summaryrefslogtreecommitdiffstats
path: root/lib/libc
diff options
context:
space:
mode:
authorache <ache@FreeBSD.org>2007-04-30 16:56:18 +0000
committerache <ache@FreeBSD.org>2007-04-30 16:56:18 +0000
commitd85104099ad40c33148426adb779741c366c2f19 (patch)
tree0f48274fab3bf61e5379abd241da2f704d7da652 /lib/libc
parentb5d028a647a14c0c4d23e84788a75778dfd9a05e (diff)
downloadFreeBSD-src-d85104099ad40c33148426adb779741c366c2f19.zip
FreeBSD-src-d85104099ad40c33148426adb779741c366c2f19.tar.gz
Make putenv() fully conforms to Open Group specs Issue 6
(also IEEE Std 1003.1-2001) The specs explicitly says that altering passed string should change the environment, i.e. putenv() directly puts its arg into environment (unlike setenv() which just copies it there). It means that putenv() can't be implemented via setenv() (like we have before) at all. Putenv() value lives (allows modifying) up to the next putenv() or setenv() call.
Diffstat (limited to 'lib/libc')
-rw-r--r--lib/libc/stdlib/getenv.319
-rw-r--r--lib/libc/stdlib/getenv.c7
-rw-r--r--lib/libc/stdlib/putenv.c46
-rw-r--r--lib/libc/stdlib/setenv.c12
4 files changed, 58 insertions, 26 deletions
diff --git a/lib/libc/stdlib/getenv.3 b/lib/libc/stdlib/getenv.3
index 1882ba2..7445b47 100644
--- a/lib/libc/stdlib/getenv.3
+++ b/lib/libc/stdlib/getenv.3
@@ -88,11 +88,17 @@ to the given
.Pp
The
.Fn putenv
-function takes an argument of the form ``name=value'' and is
-equivalent to:
-.Bd -literal -offset indent
-setenv(name, value, 1);
-.Ed
+function takes an argument of the form ``name=value'' and
+puts it directly into the current environment.
+If the variable
+.Fa name
+does not exist in the list,
+it is inserted with the given
+.Fa value .
+If the variable
+.Fa name
+does exist, it is reset to the given
+.Fa value .
.Pp
The
.Fn unsetenv
@@ -145,7 +151,8 @@ The
function conforms to
.St -isoC .
The
-.Fn setenv
+.Fn setenv ,
+.Fn putenv
and
.Fn unsetenv
functions conforms to
diff --git a/lib/libc/stdlib/getenv.c b/lib/libc/stdlib/getenv.c
index 73ac407..9ff18d8 100644
--- a/lib/libc/stdlib/getenv.c
+++ b/lib/libc/stdlib/getenv.c
@@ -43,7 +43,8 @@ inline char *__findenv(const char *, int *);
* __findenv --
* Returns pointer to value associated with name, if any, else NULL.
* Sets offset to be the offset of the name/value combination in the
- * environmental array, for use by setenv(3) and unsetenv(3).
+ * environmental array, for use by putenv(3), setenv(3) and unsetenv(3).
+ * Explicitly removes '=' in argument name.
*
* This routine *should* be a static; don't use it.
*/
@@ -59,7 +60,9 @@ __findenv(name, offset)
if (environ == NULL)
return (NULL);
- len = strlen(name);
+ for (np = name; *np && *np != '='; ++np)
+ continue;
+ len = np - name;
for (p = environ; (cp = *p) != NULL; ++p) {
for (np = name, i = len; i && *cp; i--)
if (*cp++ != *np++)
diff --git a/lib/libc/stdlib/putenv.c b/lib/libc/stdlib/putenv.c
index b6c7ccb..56b78cf 100644
--- a/lib/libc/stdlib/putenv.c
+++ b/lib/libc/stdlib/putenv.c
@@ -37,24 +37,46 @@ __FBSDID("$FreeBSD$");
#include <stdlib.h>
#include <string.h>
+extern char **__alloced; /* if allocated space before */
+
+char *__findenv(const char *, int *);
+
int
putenv(str)
char *str;
{
- char *p, *equal;
- int rval, serrno;
+ extern char **environ;
+ char *eq;
+ int offset;
- if ((p = strdup(str)) == NULL)
- return (-1);
- if ((equal = index(p, '=')) == NULL) {
- (void)free(p);
+ if (str == NULL || (eq = strchr(str, '=')) == NULL || eq == str) {
errno = EINVAL;
return (-1);
}
- *equal = '\0';
- rval = setenv(p, equal + 1, 1);
- serrno = errno;
- (void)free(p);
- errno = serrno;
- return (rval);
+
+ /* Trimmed version of setenv(3). */
+ if (__findenv(str, &offset) == NULL) {
+ int cnt;
+ char **p;
+
+ for (p = environ, cnt = 0; *p; ++p, ++cnt);
+ if (__alloced == environ) { /* just increase size */
+ p = (char **)realloc((char *)environ,
+ (size_t)(sizeof(char *) * (cnt + 2)));
+ if (!p)
+ return (-1);
+ }
+ else { /* get new space */
+ /* copy old entries into it */
+ p = (char **)malloc((size_t)(sizeof(char *) * (cnt + 2)));
+ if (!p)
+ return (-1);
+ bcopy(environ, p, cnt * sizeof(char *));
+ }
+ __alloced = environ = p;
+ environ[cnt + 1] = NULL;
+ offset = cnt;
+ }
+ environ[offset] = str;
+ return (0);
}
diff --git a/lib/libc/stdlib/setenv.c b/lib/libc/stdlib/setenv.c
index 2695af7..5725733 100644
--- a/lib/libc/stdlib/setenv.c
+++ b/lib/libc/stdlib/setenv.c
@@ -38,6 +38,8 @@ __FBSDID("$FreeBSD$");
#include <stdlib.h>
#include <string.h>
+char **__alloced; /* if allocated space before */
+
char *__findenv(const char *, int *);
/*
@@ -52,7 +54,6 @@ setenv(name, value, rewrite)
int rewrite;
{
extern char **environ;
- static char **alloced; /* if allocated space before */
char *c;
int l_value, offset;
@@ -74,26 +75,25 @@ setenv(name, value, rewrite)
char **p;
for (p = environ, cnt = 0; *p; ++p, ++cnt);
- if (alloced == environ) { /* just increase size */
+ if (__alloced == environ) { /* just increase size */
p = (char **)realloc((char *)environ,
(size_t)(sizeof(char *) * (cnt + 2)));
if (!p)
return (-1);
- alloced = environ = p;
}
else { /* get new space */
/* copy old entries into it */
- p = malloc((size_t)(sizeof(char *) * (cnt + 2)));
+ p = (char **)malloc((size_t)(sizeof(char *) * (cnt + 2)));
if (!p)
return (-1);
bcopy(environ, p, cnt * sizeof(char *));
- alloced = environ = p;
}
+ __alloced = environ = p;
environ[cnt + 1] = NULL;
offset = cnt;
}
if (!(environ[offset] = /* name + `=' + value */
- malloc((size_t)(strlen(name) + l_value + 2))))
+ (char *)malloc((size_t)(strlen(name) + l_value + 2))))
return (-1);
for (c = environ[offset]; (*c = *name++) && *c != '='; ++c);
for (*c++ = '='; (*c++ = *value++); );
OpenPOWER on IntegriCloud