12aef6930SMark Murray /*
22aef6930SMark Murray * Many systems have putenv() but no setenv(). Other systems have setenv()
32aef6930SMark Murray * but no putenv() (MIPS). Still other systems have neither (NeXT). This is a
42aef6930SMark Murray * re-implementation that hopefully ends all problems.
52aef6930SMark Murray *
62aef6930SMark Murray * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
72aef6930SMark Murray */
82aef6930SMark Murray
92aef6930SMark Murray #ifndef lint
102aef6930SMark Murray static char sccsid[] = "@(#) environ.c 1.2 94/03/23 16:09:46";
112aef6930SMark Murray #endif
122aef6930SMark Murray
132aef6930SMark Murray /* System libraries. */
142aef6930SMark Murray
152aef6930SMark Murray extern char **environ;
162aef6930SMark Murray extern char *strchr();
172aef6930SMark Murray extern char *strcpy();
182aef6930SMark Murray extern char *strncpy();
192aef6930SMark Murray extern char *malloc();
202aef6930SMark Murray extern char *realloc();
212aef6930SMark Murray extern int strncmp();
222aef6930SMark Murray extern void free();
232aef6930SMark Murray
242aef6930SMark Murray #ifdef no_memcpy
252aef6930SMark Murray #define memcpy(d,s,l) bcopy(s,d,l)
262aef6930SMark Murray #else
272aef6930SMark Murray extern char *memcpy();
282aef6930SMark Murray #endif
292aef6930SMark Murray
302aef6930SMark Murray /* Local stuff. */
312aef6930SMark Murray
322aef6930SMark Murray static int addenv(); /* append entry to environment */
332aef6930SMark Murray
342aef6930SMark Murray static int allocated = 0; /* environ is, or is not, allocated */
352aef6930SMark Murray
362aef6930SMark Murray #define DO_CLOBBER 1
372aef6930SMark Murray
382aef6930SMark Murray /* namelength - determine length of name in "name=whatever" */
392aef6930SMark Murray
namelength(char * name)40*14f102eaSEd Maste static int namelength(char *name)
412aef6930SMark Murray {
422aef6930SMark Murray char *equal;
432aef6930SMark Murray
442aef6930SMark Murray equal = strchr(name, '=');
452aef6930SMark Murray return ((equal == 0) ? strlen(name) : (equal - name));
462aef6930SMark Murray }
472aef6930SMark Murray
482aef6930SMark Murray /* findenv - given name, locate name=value */
492aef6930SMark Murray
findenv(char * name,int len)50*14f102eaSEd Maste static char **findenv(char *name, int len)
512aef6930SMark Murray {
522aef6930SMark Murray char **envp;
532aef6930SMark Murray
542aef6930SMark Murray for (envp = environ; envp && *envp; envp++)
552aef6930SMark Murray if (strncmp(name, *envp, len) == 0 && (*envp)[len] == '=')
562aef6930SMark Murray return (envp);
572aef6930SMark Murray return (0);
582aef6930SMark Murray }
592aef6930SMark Murray
602aef6930SMark Murray /* getenv - given name, locate value */
612aef6930SMark Murray
getenv(char * name)62*14f102eaSEd Maste char *getenv(char *name)
632aef6930SMark Murray {
642aef6930SMark Murray int len = namelength(name);
652aef6930SMark Murray char **envp = findenv(name, len);
662aef6930SMark Murray
672aef6930SMark Murray return (envp ? *envp + len + 1 : 0);
682aef6930SMark Murray }
692aef6930SMark Murray
702aef6930SMark Murray /* putenv - update or append environment (name,value) pair */
712aef6930SMark Murray
putenv(char * nameval)72*14f102eaSEd Maste int putenv(char *nameval)
732aef6930SMark Murray {
742aef6930SMark Murray char *equal = strchr(nameval, '=');
752aef6930SMark Murray char *value = (equal ? equal : "");
762aef6930SMark Murray
772aef6930SMark Murray return (setenv(nameval, value, DO_CLOBBER));
782aef6930SMark Murray }
792aef6930SMark Murray
802aef6930SMark Murray /* unsetenv - remove variable from environment */
812aef6930SMark Murray
unsetenv(char * name)82*14f102eaSEd Maste void unsetenv(char *name)
832aef6930SMark Murray {
842aef6930SMark Murray char **envp;
852aef6930SMark Murray
862aef6930SMark Murray if ((envp = findenv(name, namelength(name))) != 0)
872aef6930SMark Murray while (envp[0] = envp[1])
882aef6930SMark Murray envp++;
892aef6930SMark Murray }
902aef6930SMark Murray
912aef6930SMark Murray /* setenv - update or append environment (name,value) pair */
922aef6930SMark Murray
setenv(char * name,char * value,int clobber)93*14f102eaSEd Maste int setenv(char *name, char *value, int clobber)
942aef6930SMark Murray {
952aef6930SMark Murray char *destination;
962aef6930SMark Murray char **envp;
972aef6930SMark Murray int l_name; /* length of name part */
982aef6930SMark Murray int l_nameval; /* length of name=value */
992aef6930SMark Murray
1002aef6930SMark Murray /* Permit name= and =value. */
1012aef6930SMark Murray
1022aef6930SMark Murray l_name = namelength(name);
1032aef6930SMark Murray envp = findenv(name, l_name);
1042aef6930SMark Murray if (envp != 0 && clobber == 0)
1052aef6930SMark Murray return (0);
1062aef6930SMark Murray if (*value == '=')
1072aef6930SMark Murray value++;
1082aef6930SMark Murray l_nameval = l_name + strlen(value) + 1;
1092aef6930SMark Murray
1102aef6930SMark Murray /*
1112aef6930SMark Murray * Use available memory if the old value is long enough. Never free an
1122aef6930SMark Murray * old name=value entry because it may not be allocated.
1132aef6930SMark Murray */
1142aef6930SMark Murray
1152aef6930SMark Murray destination = (envp != 0 && strlen(*envp) >= l_nameval) ?
1162aef6930SMark Murray *envp : malloc(l_nameval + 1);
1172aef6930SMark Murray if (destination == 0)
1182aef6930SMark Murray return (-1);
1192aef6930SMark Murray strncpy(destination, name, l_name);
1202aef6930SMark Murray destination[l_name] = '=';
1212aef6930SMark Murray strcpy(destination + l_name + 1, value);
1222aef6930SMark Murray return ((envp == 0) ? addenv(destination) : (*envp = destination, 0));
1232aef6930SMark Murray }
1242aef6930SMark Murray
1252aef6930SMark Murray /* cmalloc - malloc and copy block of memory */
1262aef6930SMark Murray
cmalloc(int new_len,char * old,int old_len)127*14f102eaSEd Maste static char *cmalloc(int new_len, char *old, int old_len)
1282aef6930SMark Murray {
1292aef6930SMark Murray char *new = malloc(new_len);
1302aef6930SMark Murray
1312aef6930SMark Murray if (new != 0)
1322aef6930SMark Murray memcpy(new, old, old_len);
1332aef6930SMark Murray return (new);
1342aef6930SMark Murray }
1352aef6930SMark Murray
1362aef6930SMark Murray /* addenv - append environment entry */
1372aef6930SMark Murray
addenv(char * nameval)138*14f102eaSEd Maste static int addenv(char *nameval)
1392aef6930SMark Murray {
1402aef6930SMark Murray char **envp;
1412aef6930SMark Murray int n_used; /* number of environment entries */
1422aef6930SMark Murray int l_used; /* bytes used excl. terminator */
1432aef6930SMark Murray int l_need; /* bytes needed incl. terminator */
1442aef6930SMark Murray
1452aef6930SMark Murray for (envp = environ; envp && *envp; envp++)
1462aef6930SMark Murray /* void */ ;
1472aef6930SMark Murray n_used = envp - environ;
1482aef6930SMark Murray l_used = n_used * sizeof(*envp);
1492aef6930SMark Murray l_need = l_used + 2 * sizeof(*envp);
1502aef6930SMark Murray
1512aef6930SMark Murray envp = allocated ?
1522aef6930SMark Murray (char **) realloc((char *) environ, l_need) :
1532aef6930SMark Murray (char **) cmalloc(l_need, (char *) environ, l_used);
1542aef6930SMark Murray if (envp == 0) {
1552aef6930SMark Murray return (-1);
1562aef6930SMark Murray } else {
1572aef6930SMark Murray allocated = 1;
1582aef6930SMark Murray environ = envp;
1592aef6930SMark Murray environ[n_used++] = nameval; /* add new entry */
1602aef6930SMark Murray environ[n_used] = 0; /* terminate list */
1612aef6930SMark Murray return (0);
1622aef6930SMark Murray }
1632aef6930SMark Murray }
1642aef6930SMark Murray
1652aef6930SMark Murray #ifdef TEST
1662aef6930SMark Murray
1672aef6930SMark Murray /*
1682aef6930SMark Murray * Stand-alone program for test purposes.
1692aef6930SMark Murray */
1702aef6930SMark Murray
1712aef6930SMark Murray /* printenv - display environment */
1722aef6930SMark Murray
printenv()1732aef6930SMark Murray static void printenv()
1742aef6930SMark Murray {
1752aef6930SMark Murray char **envp;
1762aef6930SMark Murray
1772aef6930SMark Murray for (envp = environ; envp && *envp; envp++)
1782aef6930SMark Murray printf("%s\n", *envp);
1792aef6930SMark Murray }
1802aef6930SMark Murray
main(int argc,char ** argv)181*14f102eaSEd Maste int main(int argc, char **argv)
1822aef6930SMark Murray {
1832aef6930SMark Murray char *cp;
1842aef6930SMark Murray int changed = 0;
1852aef6930SMark Murray
1862aef6930SMark Murray if (argc < 2) {
1872aef6930SMark Murray printf("usage: %s name[=value]...\n", argv[0]);
1882aef6930SMark Murray return (1);
1892aef6930SMark Murray }
1902aef6930SMark Murray while (--argc && *++argv) {
1912aef6930SMark Murray if (argv[0][0] == '-') { /* unsetenv() test */
1922aef6930SMark Murray unsetenv(argv[0] + 1);
1932aef6930SMark Murray changed = 1;
1942aef6930SMark Murray } else if (strchr(argv[0], '=') == 0) { /* getenv() test */
1952aef6930SMark Murray cp = getenv(argv[0]);
1962aef6930SMark Murray printf("%s: %s\n", argv[0], cp ? cp : "not found");
1972aef6930SMark Murray } else { /* putenv() test */
1982aef6930SMark Murray if (putenv(argv[0])) {
1992aef6930SMark Murray perror("putenv");
2002aef6930SMark Murray return (1);
2012aef6930SMark Murray }
2022aef6930SMark Murray changed = 1;
2032aef6930SMark Murray }
2042aef6930SMark Murray }
2052aef6930SMark Murray if (changed)
2062aef6930SMark Murray printenv();
2072aef6930SMark Murray return (0);
2082aef6930SMark Murray }
2092aef6930SMark Murray
2102aef6930SMark Murray #endif /* TEST */
211