environment.c revision 38451
138451Smsmith/*
238451Smsmith * Copyright (c) 1998 Michael Smith.
338451Smsmith * All rights reserved.
438451Smsmith *
538451Smsmith * Redistribution and use in source and binary forms, with or without
638451Smsmith * modification, are permitted provided that the following conditions
738451Smsmith * are met:
838451Smsmith * 1. Redistributions of source code must retain the above copyright
938451Smsmith *    notice, this list of conditions and the following disclaimer.
1038451Smsmith * 2. Redistributions in binary form must reproduce the above copyright
1138451Smsmith *    notice, this list of conditions and the following disclaimer in the
1238451Smsmith *    documentation and/or other materials provided with the distribution.
1338451Smsmith *
1438451Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1538451Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1638451Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1738451Smsmith * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1838451Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1938451Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2038451Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2138451Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2238451Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2338451Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2438451Smsmith * SUCH DAMAGE.
2538451Smsmith *
2638451Smsmith *	$Id$
2738451Smsmith *
2838451Smsmith */
2938451Smsmith
3038451Smsmith/*
3138451Smsmith * Manage an environment-like space in which string variables may be stored.
3238451Smsmith * Provide support for some method-like operations for setting/retrieving
3338451Smsmith * variables in order to allow some type strength.
3438451Smsmith */
3538451Smsmith
3638451Smsmith#include "stand.h"
3738451Smsmith
3838451Smsmith#include <string.h>
3938451Smsmith
4038451Smsmithstatic void	env_discard(struct env_var *ev);
4138451Smsmith
4238451Smsmithstruct env_var	*environ = NULL;
4338451Smsmith
4438451Smsmith/*
4538451Smsmith * Look up (name) and return it's env_var structure.
4638451Smsmith */
4738451Smsmithstruct env_var	*
4838451Smsmithenv_getenv(const char *name)
4938451Smsmith{
5038451Smsmith    struct env_var	*ev;
5138451Smsmith
5238451Smsmith    for (ev = environ; ev != NULL; ev = ev->ev_next)
5338451Smsmith	if (!strcmp(ev->ev_name, name))
5438451Smsmith	    break;
5538451Smsmith    return(ev);
5638451Smsmith}
5738451Smsmith
5838451Smsmith/*
5938451Smsmith * Some notes:
6038451Smsmith *
6138451Smsmith * If the EV_VOLATILE flag is set, a copy of the variable is made.
6238451Smsmith * If EV_DYNAMIC is set, the the variable has been allocated with
6338451Smsmith * malloc and ownership transferred to the environment.
6438451Smsmith * If (value) is NULL, the variable is set but has no value.
6538451Smsmith */
6638451Smsmithint
6738451Smsmithenv_setenv(const char *name, int flags, void *value, ev_sethook_t sethook,
6838451Smsmith	   ev_unsethook_t unsethook)
6938451Smsmith{
7038451Smsmith    struct env_var	*ev, *curr, *last;
7138451Smsmith
7238451Smsmith    if ((ev = env_getenv(name)) != NULL) {
7338451Smsmith
7438451Smsmith	/*
7538451Smsmith	 * If there's a set hook, let it do the work (unless we are working
7638451Smsmith	 * for one already.
7738451Smsmith	 */
7838451Smsmith	if ((ev->ev_sethook != NULL) && !(flags & EV_NOHOOK))
7938451Smsmith	    return(ev->ev_sethook(ev, flags, value));
8038451Smsmith    } else {
8138451Smsmith	ev = malloc(sizeof(struct env_var));
8238451Smsmith	ev->ev_name = strdup(name);
8338451Smsmith	ev->ev_value = NULL;
8438451Smsmith	/* hooks can only be set when the variable is instantiated */
8538451Smsmith	ev->ev_sethook = sethook;
8638451Smsmith	ev->ev_unsethook = unsethook;
8738451Smsmith    }
8838451Smsmith
8938451Smsmith    /* If there is data in the variable, discard it */
9038451Smsmith    if (ev->ev_value != NULL)
9138451Smsmith	free(ev->ev_value);
9238451Smsmith
9338451Smsmith    /* If we have a new value, use it */
9438451Smsmith    if (flags & EV_VOLATILE) {
9538451Smsmith	ev->ev_value = strdup(value);
9638451Smsmith    } else {
9738451Smsmith	ev->ev_value = value;
9838451Smsmith    }
9938451Smsmith
10038451Smsmith    /* Keep the flag components that are relevant */
10138451Smsmith    ev->ev_flags = flags & (EV_DYNAMIC);
10238451Smsmith
10338451Smsmith    /* Sort into list */
10438451Smsmith    ev->ev_prev = NULL;
10538451Smsmith    ev->ev_next = NULL;
10638451Smsmith
10738451Smsmith    /* Search for the record to insert before */
10838451Smsmith    for (last = NULL, curr = environ;
10938451Smsmith	 curr != NULL;
11038451Smsmith	 last = curr, curr = curr->ev_next) {
11138451Smsmith
11238451Smsmith	if (strcmp(ev->ev_name, curr->ev_name) < 0) {
11338451Smsmith	    if (curr->ev_prev) {
11438451Smsmith		curr->ev_prev->ev_next = ev;
11538451Smsmith	    } else {
11638451Smsmith		environ = ev;
11738451Smsmith	    }
11838451Smsmith	    ev->ev_next = curr;
11938451Smsmith	    ev->ev_prev = curr->ev_prev;
12038451Smsmith	    curr->ev_prev = ev;
12138451Smsmith	    break;
12238451Smsmith	}
12338451Smsmith    }
12438451Smsmith    if (curr == NULL) {
12538451Smsmith	if (last == NULL) {
12638451Smsmith	    environ = ev;
12738451Smsmith	} else {
12838451Smsmith	    last->ev_next = ev;
12938451Smsmith	    ev->ev_prev = last;
13038451Smsmith	}
13138451Smsmith    }
13238451Smsmith    return(0);
13338451Smsmith}
13438451Smsmith
13538451Smsmithchar *
13638451Smsmithgetenv(const char *name)
13738451Smsmith{
13838451Smsmith    struct env_var	*ev;
13938451Smsmith
14038451Smsmith    /* Set but no value gives empty string */
14138451Smsmith    if ((ev = env_getenv(name)) != NULL) {
14238451Smsmith	if (ev->ev_value != NULL)
14338451Smsmith	    return(ev->ev_value);
14438451Smsmith	return("");
14538451Smsmith    }
14638451Smsmith    return(NULL);
14738451Smsmith}
14838451Smsmith
14938451Smsmithint
15038451Smsmithsetenv(const char *name, char *value, int overwrite)
15138451Smsmith{
15238451Smsmith    /* No guarantees about state, always assume volatile */
15338451Smsmith    if (overwrite || (env_getenv(name) == NULL))
15438451Smsmith	return(env_setenv(name, EV_VOLATILE, value, NULL, NULL));
15538451Smsmith    return(0);
15638451Smsmith}
15738451Smsmith
15838451Smsmithint
15938451Smsmithputenv(const char *string)
16038451Smsmith{
16138451Smsmith    char	*value;
16238451Smsmith
16338451Smsmith    if ((value = strchr(string, '=')) != NULL)
16438451Smsmith	*(value++) = 0;
16538451Smsmith    return(setenv(string, value, 1));
16638451Smsmith}
16738451Smsmith
16838451Smsmithint
16938451Smsmithunsetenv(const char *name)
17038451Smsmith{
17138451Smsmith    struct env_var	*ev;
17238451Smsmith    int			err;
17338451Smsmith
17438451Smsmith    err = 0;
17538451Smsmith    if ((ev = env_getenv(name)) == NULL) {
17638451Smsmith	err = ENOENT;
17738451Smsmith    } else {
17838451Smsmith	if (ev->ev_unsethook != NULL)
17938451Smsmith	    err = ev->ev_unsethook(ev);
18038451Smsmith	if (err == 0) {
18138451Smsmith	    env_discard(ev);
18238451Smsmith	}
18338451Smsmith    }
18438451Smsmith    return(err);
18538451Smsmith}
18638451Smsmith
18738451Smsmithstatic void
18838451Smsmithenv_discard(struct env_var *ev)
18938451Smsmith{
19038451Smsmith    if (ev->ev_prev)
19138451Smsmith	ev->ev_prev->ev_next = ev->ev_next;
19238451Smsmith    if (ev->ev_next)
19338451Smsmith	ev->ev_next->ev_prev = ev->ev_prev;
19438451Smsmith    if (environ == ev)
19538451Smsmith	environ = ev->ev_next;
19638451Smsmith    free(ev->ev_name);
19738451Smsmith    if (ev->ev_flags & EV_DYNAMIC)
19838451Smsmith	free(ev->ev_value);
19938451Smsmith    free(ev);
20038451Smsmith}
20138451Smsmith
20238451Smsmithint
20338451Smsmithenv_noset(struct env_var *ev, int flags, void *value)
20438451Smsmith{
20538451Smsmith    return(EPERM);
20638451Smsmith}
20738451Smsmith
20838451Smsmithint
20938451Smsmithenv_nounset(struct env_var *ev)
21038451Smsmith{
21138451Smsmith    return(EPERM);
21238451Smsmith}
213