144743Smarkm/*
244743Smarkm * Many systems have putenv() but no setenv(). Other systems have setenv()
344743Smarkm * but no putenv() (MIPS). Still other systems have neither (NeXT). This is a
444743Smarkm * re-implementation that hopefully ends all problems.
544743Smarkm *
644743Smarkm * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
744743Smarkm */
844743Smarkm
944743Smarkm#ifndef lint
1044743Smarkmstatic char sccsid[] = "@(#) environ.c 1.2 94/03/23 16:09:46";
1144743Smarkm#endif
1244743Smarkm
1344743Smarkm/* System libraries. */
1444743Smarkm
1544743Smarkmextern char **environ;
1644743Smarkmextern char *strchr();
1744743Smarkmextern char *strcpy();
1844743Smarkmextern char *strncpy();
1944743Smarkmextern char *malloc();
2044743Smarkmextern char *realloc();
2144743Smarkmextern int strncmp();
2244743Smarkmextern void free();
2344743Smarkm
2444743Smarkm#ifdef no_memcpy
2544743Smarkm#define memcpy(d,s,l) bcopy(s,d,l)
2644743Smarkm#else
2744743Smarkmextern char *memcpy();
2844743Smarkm#endif
2944743Smarkm
3044743Smarkm/* Local stuff. */
3144743Smarkm
3244743Smarkmstatic int addenv();			/* append entry to environment */
3344743Smarkm
3444743Smarkmstatic int allocated = 0;		/* environ is, or is not, allocated */
3544743Smarkm
3644743Smarkm#define DO_CLOBBER	1
3744743Smarkm
3844743Smarkm/* namelength - determine length of name in "name=whatever" */
3944743Smarkm
4044743Smarkmstatic int namelength(name)
4144743Smarkmchar   *name;
4244743Smarkm{
4344743Smarkm    char   *equal;
4444743Smarkm
4544743Smarkm    equal = strchr(name, '=');
4644743Smarkm    return ((equal == 0) ? strlen(name) : (equal - name));
4744743Smarkm}
4844743Smarkm
4944743Smarkm/* findenv - given name, locate name=value */
5044743Smarkm
5144743Smarkmstatic char **findenv(name, len)
5244743Smarkmchar   *name;
5344743Smarkmint     len;
5444743Smarkm{
5544743Smarkm    char  **envp;
5644743Smarkm
5744743Smarkm    for (envp = environ; envp && *envp; envp++)
5844743Smarkm	if (strncmp(name, *envp, len) == 0 && (*envp)[len] == '=')
5944743Smarkm	    return (envp);
6044743Smarkm    return (0);
6144743Smarkm}
6244743Smarkm
6344743Smarkm/* getenv - given name, locate value */
6444743Smarkm
6544743Smarkmchar   *getenv(name)
6644743Smarkmchar   *name;
6744743Smarkm{
6844743Smarkm    int     len = namelength(name);
6944743Smarkm    char  **envp = findenv(name, len);
7044743Smarkm
7144743Smarkm    return (envp ? *envp + len + 1 : 0);
7244743Smarkm}
7344743Smarkm
7444743Smarkm/* putenv - update or append environment (name,value) pair */
7544743Smarkm
7644743Smarkmint     putenv(nameval)
7744743Smarkmchar   *nameval;
7844743Smarkm{
7944743Smarkm    char   *equal = strchr(nameval, '=');
8044743Smarkm    char   *value = (equal ? equal : "");
8144743Smarkm
8244743Smarkm    return (setenv(nameval, value, DO_CLOBBER));
8344743Smarkm}
8444743Smarkm
8544743Smarkm/* unsetenv - remove variable from environment */
8644743Smarkm
8744743Smarkmvoid    unsetenv(name)
8844743Smarkmchar   *name;
8944743Smarkm{
9044743Smarkm    char  **envp;
9144743Smarkm
9244743Smarkm    if ((envp = findenv(name, namelength(name))) != 0)
9344743Smarkm	while (envp[0] = envp[1])
9444743Smarkm	    envp++;
9544743Smarkm}
9644743Smarkm
9744743Smarkm/* setenv - update or append environment (name,value) pair */
9844743Smarkm
9944743Smarkmint     setenv(name, value, clobber)
10044743Smarkmchar   *name;
10144743Smarkmchar   *value;
10244743Smarkmint     clobber;
10344743Smarkm{
10444743Smarkm    char   *destination;
10544743Smarkm    char  **envp;
10644743Smarkm    int     l_name;			/* length of name part */
10744743Smarkm    int     l_nameval;			/* length of name=value */
10844743Smarkm
10944743Smarkm    /* Permit name= and =value. */
11044743Smarkm
11144743Smarkm    l_name = namelength(name);
11244743Smarkm    envp = findenv(name, l_name);
11344743Smarkm    if (envp != 0 && clobber == 0)
11444743Smarkm	return (0);
11544743Smarkm    if (*value == '=')
11644743Smarkm	value++;
11744743Smarkm    l_nameval = l_name + strlen(value) + 1;
11844743Smarkm
11944743Smarkm    /*
12044743Smarkm     * Use available memory if the old value is long enough. Never free an
12144743Smarkm     * old name=value entry because it may not be allocated.
12244743Smarkm     */
12344743Smarkm
12444743Smarkm    destination = (envp != 0 && strlen(*envp) >= l_nameval) ?
12544743Smarkm	*envp : malloc(l_nameval + 1);
12644743Smarkm    if (destination == 0)
12744743Smarkm	return (-1);
12844743Smarkm    strncpy(destination, name, l_name);
12944743Smarkm    destination[l_name] = '=';
13044743Smarkm    strcpy(destination + l_name + 1, value);
13144743Smarkm    return ((envp == 0) ? addenv(destination) : (*envp = destination, 0));
13244743Smarkm}
13344743Smarkm
13444743Smarkm/* cmalloc - malloc and copy block of memory */
13544743Smarkm
13644743Smarkmstatic char *cmalloc(new_len, old, old_len)
13744743Smarkmchar   *old;
13844743Smarkmint     old_len;
13944743Smarkm{
14044743Smarkm    char   *new = malloc(new_len);
14144743Smarkm
14244743Smarkm    if (new != 0)
14344743Smarkm	memcpy(new, old, old_len);
14444743Smarkm    return (new);
14544743Smarkm}
14644743Smarkm
14744743Smarkm/* addenv - append environment entry */
14844743Smarkm
14944743Smarkmstatic int addenv(nameval)
15044743Smarkmchar   *nameval;
15144743Smarkm{
15244743Smarkm    char  **envp;
15344743Smarkm    int     n_used;			/* number of environment entries */
15444743Smarkm    int     l_used;			/* bytes used excl. terminator */
15544743Smarkm    int     l_need;			/* bytes needed incl. terminator */
15644743Smarkm
15744743Smarkm    for (envp = environ; envp && *envp; envp++)
15844743Smarkm	 /* void */ ;
15944743Smarkm    n_used = envp - environ;
16044743Smarkm    l_used = n_used * sizeof(*envp);
16144743Smarkm    l_need = l_used + 2 * sizeof(*envp);
16244743Smarkm
16344743Smarkm    envp = allocated ?
16444743Smarkm	(char **) realloc((char *) environ, l_need) :
16544743Smarkm	(char **) cmalloc(l_need, (char *) environ, l_used);
16644743Smarkm    if (envp == 0) {
16744743Smarkm	return (-1);
16844743Smarkm    } else {
16944743Smarkm	allocated = 1;
17044743Smarkm	environ = envp;
17144743Smarkm	environ[n_used++] = nameval;		/* add new entry */
17244743Smarkm	environ[n_used] = 0;			/* terminate list */
17344743Smarkm	return (0);
17444743Smarkm    }
17544743Smarkm}
17644743Smarkm
17744743Smarkm#ifdef TEST
17844743Smarkm
17944743Smarkm /*
18044743Smarkm  * Stand-alone program for test purposes.
18144743Smarkm  */
18244743Smarkm
18344743Smarkm/* printenv - display environment */
18444743Smarkm
18544743Smarkmstatic void printenv()
18644743Smarkm{
18744743Smarkm    char  **envp;
18844743Smarkm
18944743Smarkm    for (envp = environ; envp && *envp; envp++)
19044743Smarkm	printf("%s\n", *envp);
19144743Smarkm}
19244743Smarkm
19344743Smarkmint     main(argc, argv)
19444743Smarkmint     argc;
19544743Smarkmchar  **argv;
19644743Smarkm{
19744743Smarkm    char   *cp;
19844743Smarkm    int     changed = 0;
19944743Smarkm
20044743Smarkm    if (argc < 2) {
20144743Smarkm	printf("usage: %s name[=value]...\n", argv[0]);
20244743Smarkm	return (1);
20344743Smarkm    }
20444743Smarkm    while (--argc && *++argv) {
20544743Smarkm	if (argv[0][0] == '-') {		/* unsetenv() test */
20644743Smarkm	    unsetenv(argv[0] + 1);
20744743Smarkm	    changed = 1;
20844743Smarkm	} else if (strchr(argv[0], '=') == 0) {	/* getenv() test */
20944743Smarkm	    cp = getenv(argv[0]);
21044743Smarkm	    printf("%s: %s\n", argv[0], cp ? cp : "not found");
21144743Smarkm	} else {				/* putenv() test */
21244743Smarkm	    if (putenv(argv[0])) {
21344743Smarkm		perror("putenv");
21444743Smarkm		return (1);
21544743Smarkm	    }
21644743Smarkm	    changed = 1;
21744743Smarkm	}
21844743Smarkm    }
21944743Smarkm    if (changed)
22044743Smarkm	printenv();
22144743Smarkm    return (0);
22244743Smarkm}
22344743Smarkm
22444743Smarkm#endif /* TEST */
225