environment.c revision 64185
155714Skris/*
255714Skris * Copyright (c) 1998 Michael Smith.
355714Skris * All rights reserved.
455714Skris *
555714Skris * Redistribution and use in source and binary forms, with or without
655714Skris * modification, are permitted provided that the following conditions
755714Skris * are met:
8296465Sdelphij * 1. Redistributions of source code must retain the above copyright
955714Skris *    notice, this list of conditions and the following disclaimer.
1055714Skris * 2. Redistributions in binary form must reproduce the above copyright
1155714Skris *    notice, this list of conditions and the following disclaimer in the
1255714Skris *    documentation and/or other materials provided with the distribution.
1355714Skris *
1455714Skris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15296465Sdelphij * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1655714Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1755714Skris * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1855714Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1955714Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2055714Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2155714Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22296465Sdelphij * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2355714Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2455714Skris * SUCH DAMAGE.
2555714Skris *
2655714Skris * $FreeBSD: head/lib/libstand/environment.c 64185 2000-08-03 09:08:29Z jhb $
2755714Skris *
2855714Skris */
2955714Skris
3055714Skris/*
3155714Skris * Manage an environment-like space in which string variables may be stored.
3255714Skris * Provide support for some method-like operations for setting/retrieving
3355714Skris * variables in order to allow some type strength.
3455714Skris */
3555714Skris
3655714Skris#include "stand.h"
37296465Sdelphij
3855714Skris#include <string.h>
3955714Skris
40296465Sdelphijstatic void	env_discard(struct env_var *ev);
4155714Skris
4255714Skrisstruct env_var	*environ = NULL;
4355714Skris
4455714Skris/*
4555714Skris * Look up (name) and return it's env_var structure.
4655714Skris */
4755714Skrisstruct env_var	*
4855714Skrisenv_getenv(const char *name)
4955714Skris{
5055714Skris    struct env_var	*ev;
5155714Skris
52296465Sdelphij    for (ev = environ; ev != NULL; ev = ev->ev_next)
5355714Skris	if (!strcmp(ev->ev_name, name))
5455714Skris	    break;
5555714Skris    return(ev);
5655714Skris}
5755714Skris
5855714Skris/*
5955714Skris * Some notes:
6055714Skris *
6155714Skris * If the EV_VOLATILE flag is set, a copy of the variable is made.
6255714Skris * If EV_DYNAMIC is set, the the variable has been allocated with
6355714Skris * malloc and ownership transferred to the environment.
6455714Skris * If (value) is NULL, the variable is set but has no value.
65109998Smarkm */
66296465Sdelphijint
67296465Sdelphijenv_setenv(const char *name, int flags, const void *value,
68296465Sdelphij	   ev_sethook_t sethook, ev_unsethook_t unsethook)
6955714Skris{
70296465Sdelphij    struct env_var	*ev, *curr, *last;
71296465Sdelphij
72296465Sdelphij    if ((ev = env_getenv(name)) != NULL) {
73296465Sdelphij	/*
74109998Smarkm	 * If there's a set hook, let it do the work (unless we are working
75296465Sdelphij	 * for one already.
76296465Sdelphij	 */
77296465Sdelphij	if ((ev->ev_sethook != NULL) && !(flags & EV_NOHOOK))
78296465Sdelphij	    return(ev->ev_sethook(ev, flags, value));
79109998Smarkm    } else {
80296465Sdelphij
81296465Sdelphij	/*
82296465Sdelphij	 * New variable; create and sort into list
83296465Sdelphij	 */
84296465Sdelphij	ev = malloc(sizeof(struct env_var));
85296465Sdelphij	ev->ev_name = strdup(name);
86296465Sdelphij	ev->ev_value = NULL;
87296465Sdelphij	/* hooks can only be set when the variable is instantiated */
88296465Sdelphij	ev->ev_sethook = sethook;
89296465Sdelphij	ev->ev_unsethook = unsethook;
90296465Sdelphij
91296465Sdelphij	/* Sort into list */
92296465Sdelphij	ev->ev_prev = NULL;
93296465Sdelphij	ev->ev_next = NULL;
9455714Skris	/* Search for the record to insert before */
95109998Smarkm	for (last = NULL, curr = environ;
96296465Sdelphij	     curr != NULL;
97296465Sdelphij	     last = curr, curr = curr->ev_next) {
98296465Sdelphij
99	    if (strcmp(ev->ev_name, curr->ev_name) < 0) {
100		if (curr->ev_prev) {
101		    curr->ev_prev->ev_next = ev;
102		} else {
103		    environ = ev;
104		}
105		ev->ev_next = curr;
106		ev->ev_prev = curr->ev_prev;
107		curr->ev_prev = ev;
108		break;
109	    }
110	}
111	if (curr == NULL) {
112	    if (last == NULL) {
113		environ = ev;
114	    } else {
115		last->ev_next = ev;
116		ev->ev_prev = last;
117	    }
118	}
119    }
120
121    /* If there is data in the variable, discard it */
122    if (ev->ev_value != NULL)
123	free(ev->ev_value);
124
125    /* If we have a new value, use it */
126    if (flags & EV_VOLATILE) {
127	ev->ev_value = strdup(value);
128    } else {
129	ev->ev_value = value;
130    }
131
132    /* Keep the flag components that are relevant */
133    ev->ev_flags = flags & (EV_DYNAMIC);
134
135    return(0);
136}
137
138char *
139getenv(const char *name)
140{
141    struct env_var	*ev;
142
143    /* Set but no value gives empty string */
144    if ((ev = env_getenv(name)) != NULL) {
145	if (ev->ev_value != NULL)
146	    return(ev->ev_value);
147	return("");
148    }
149    return(NULL);
150}
151
152int
153setenv(const char *name, const char *value, int overwrite)
154{
155    /* No guarantees about state, always assume volatile */
156    if (overwrite || (env_getenv(name) == NULL))
157	return(env_setenv(name, EV_VOLATILE, value, NULL, NULL));
158    return(0);
159}
160
161int
162putenv(const char *string)
163{
164    char	*value, *copy;
165    int		result;
166
167    copy = strdup(string);
168    if ((value = strchr(copy, '=')) != NULL)
169	*(value++) = 0;
170    result = setenv(copy, value, 1);
171    free(copy);
172    return(result);
173}
174
175int
176unsetenv(const char *name)
177{
178    struct env_var	*ev;
179    int			err;
180
181    err = 0;
182    if ((ev = env_getenv(name)) == NULL) {
183	err = ENOENT;
184    } else {
185	if (ev->ev_unsethook != NULL)
186	    err = ev->ev_unsethook(ev);
187	if (err == 0) {
188	    env_discard(ev);
189	}
190    }
191    return(err);
192}
193
194static void
195env_discard(struct env_var *ev)
196{
197    if (ev->ev_prev)
198	ev->ev_prev->ev_next = ev->ev_next;
199    if (ev->ev_next)
200	ev->ev_next->ev_prev = ev->ev_prev;
201    if (environ == ev)
202	environ = ev->ev_next;
203    free(ev->ev_name);
204    if (ev->ev_flags & EV_DYNAMIC)
205	free(ev->ev_value);
206    free(ev);
207}
208
209int
210env_noset(struct env_var *ev, int flags, void *value)
211{
212    return(EPERM);
213}
214
215int
216env_nounset(struct env_var *ev)
217{
218    return(EPERM);
219}
220