summaryrefslogtreecommitdiff
path: root/environ.c
diff options
context:
space:
mode:
Diffstat (limited to 'environ.c')
-rw-r--r--environ.c224
1 files changed, 224 insertions, 0 deletions
diff --git a/environ.c b/environ.c
new file mode 100644
index 0000000..e7f846d
--- /dev/null
+++ b/environ.c
@@ -0,0 +1,224 @@
+/*
+ * Many systems have putenv() but no setenv(). Other systems have setenv()
+ * but no putenv() (MIPS). Still other systems have neither (NeXT). This is a
+ * re-implementation that hopefully ends all problems.
+ *
+ * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#) environ.c 1.2 94/03/23 16:09:46";
+#endif
+
+/* System libraries. */
+
+extern char **environ;
+extern char *strchr();
+extern char *strcpy();
+extern char *strncpy();
+extern char *malloc();
+extern char *realloc();
+extern int strncmp();
+extern void free();
+
+#ifdef no_memcpy
+#define memcpy(d,s,l) bcopy(s,d,l)
+#else
+extern char *memcpy();
+#endif
+
+/* Local stuff. */
+
+static int addenv(); /* append entry to environment */
+
+static int allocated = 0; /* environ is, or is not, allocated */
+
+#define DO_CLOBBER 1
+
+/* namelength - determine length of name in "name=whatever" */
+
+static int namelength(name)
+char *name;
+{
+ char *equal;
+
+ equal = strchr(name, '=');
+ return ((equal == 0) ? strlen(name) : (equal - name));
+}
+
+/* findenv - given name, locate name=value */
+
+static char **findenv(name, len)
+char *name;
+int len;
+{
+ char **envp;
+
+ for (envp = environ; envp && *envp; envp++)
+ if (strncmp(name, *envp, len) == 0 && (*envp)[len] == '=')
+ return (envp);
+ return (0);
+}
+
+/* getenv - given name, locate value */
+
+char *getenv(name)
+char *name;
+{
+ int len = namelength(name);
+ char **envp = findenv(name, len);
+
+ return (envp ? *envp + len + 1 : 0);
+}
+
+/* putenv - update or append environment (name,value) pair */
+
+int putenv(nameval)
+char *nameval;
+{
+ char *equal = strchr(nameval, '=');
+ char *value = (equal ? equal : "");
+
+ return (setenv(nameval, value, DO_CLOBBER));
+}
+
+/* unsetenv - remove variable from environment */
+
+void unsetenv(name)
+char *name;
+{
+ char **envp;
+
+ if ((envp = findenv(name, namelength(name))) != 0)
+ while (envp[0] = envp[1])
+ envp++;
+}
+
+/* setenv - update or append environment (name,value) pair */
+
+int setenv(name, value, clobber)
+char *name;
+char *value;
+int clobber;
+{
+ char *destination;
+ char **envp;
+ int l_name; /* length of name part */
+ int l_nameval; /* length of name=value */
+
+ /* Permit name= and =value. */
+
+ l_name = namelength(name);
+ envp = findenv(name, l_name);
+ if (envp != 0 && clobber == 0)
+ return (0);
+ if (*value == '=')
+ value++;
+ l_nameval = l_name + strlen(value) + 1;
+
+ /*
+ * Use available memory if the old value is long enough. Never free an
+ * old name=value entry because it may not be allocated.
+ */
+
+ destination = (envp != 0 && strlen(*envp) >= l_nameval) ?
+ *envp : malloc(l_nameval + 1);
+ if (destination == 0)
+ return (-1);
+ strncpy(destination, name, l_name);
+ destination[l_name] = '=';
+ strcpy(destination + l_name + 1, value);
+ return ((envp == 0) ? addenv(destination) : (*envp = destination, 0));
+}
+
+/* cmalloc - malloc and copy block of memory */
+
+static char *cmalloc(new_len, old, old_len)
+char *old;
+int old_len;
+{
+ char *new = malloc(new_len);
+
+ if (new != 0)
+ memcpy(new, old, old_len);
+ return (new);
+}
+
+/* addenv - append environment entry */
+
+static int addenv(nameval)
+char *nameval;
+{
+ char **envp;
+ int n_used; /* number of environment entries */
+ int l_used; /* bytes used excl. terminator */
+ int l_need; /* bytes needed incl. terminator */
+
+ for (envp = environ; envp && *envp; envp++)
+ /* void */ ;
+ n_used = envp - environ;
+ l_used = n_used * sizeof(*envp);
+ l_need = l_used + 2 * sizeof(*envp);
+
+ envp = allocated ?
+ (char **) realloc((char *) environ, l_need) :
+ (char **) cmalloc(l_need, (char *) environ, l_used);
+ if (envp == 0) {
+ return (-1);
+ } else {
+ allocated = 1;
+ environ = envp;
+ environ[n_used++] = nameval; /* add new entry */
+ environ[n_used] = 0; /* terminate list */
+ return (0);
+ }
+}
+
+#ifdef TEST
+
+ /*
+ * Stand-alone program for test purposes.
+ */
+
+/* printenv - display environment */
+
+static void printenv()
+{
+ char **envp;
+
+ for (envp = environ; envp && *envp; envp++)
+ printf("%s\n", *envp);
+}
+
+int main(argc, argv)
+int argc;
+char **argv;
+{
+ char *cp;
+ int changed = 0;
+
+ if (argc < 2) {
+ printf("usage: %s name[=value]...\n", argv[0]);
+ return (1);
+ }
+ while (--argc && *++argv) {
+ if (argv[0][0] == '-') { /* unsetenv() test */
+ unsetenv(argv[0] + 1);
+ changed = 1;
+ } else if (strchr(argv[0], '=') == 0) { /* getenv() test */
+ cp = getenv(argv[0]);
+ printf("%s: %s\n", argv[0], cp ? cp : "not found");
+ } else { /* putenv() test */
+ if (putenv(argv[0])) {
+ perror("putenv");
+ return (1);
+ }
+ changed = 1;
+ }
+ }
+ if (changed)
+ printenv();
+ return (0);
+}
+
+#endif /* TEST */