environment.c revision 38451
1/*
2 * Copyright (c) 1998 Michael Smith.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 *	$Id$
27 *
28 */
29
30/*
31 * Manage an environment-like space in which string variables may be stored.
32 * Provide support for some method-like operations for setting/retrieving
33 * variables in order to allow some type strength.
34 */
35
36#include "stand.h"
37
38#include <string.h>
39
40static void	env_discard(struct env_var *ev);
41
42struct env_var	*environ = NULL;
43
44/*
45 * Look up (name) and return it's env_var structure.
46 */
47struct env_var	*
48env_getenv(const char *name)
49{
50    struct env_var	*ev;
51
52    for (ev = environ; ev != NULL; ev = ev->ev_next)
53	if (!strcmp(ev->ev_name, name))
54	    break;
55    return(ev);
56}
57
58/*
59 * Some notes:
60 *
61 * If the EV_VOLATILE flag is set, a copy of the variable is made.
62 * If EV_DYNAMIC is set, the the variable has been allocated with
63 * malloc and ownership transferred to the environment.
64 * If (value) is NULL, the variable is set but has no value.
65 */
66int
67env_setenv(const char *name, int flags, void *value, ev_sethook_t sethook,
68	   ev_unsethook_t unsethook)
69{
70    struct env_var	*ev, *curr, *last;
71
72    if ((ev = env_getenv(name)) != NULL) {
73
74	/*
75	 * If there's a set hook, let it do the work (unless we are working
76	 * for one already.
77	 */
78	if ((ev->ev_sethook != NULL) && !(flags & EV_NOHOOK))
79	    return(ev->ev_sethook(ev, flags, value));
80    } else {
81	ev = malloc(sizeof(struct env_var));
82	ev->ev_name = strdup(name);
83	ev->ev_value = NULL;
84	/* hooks can only be set when the variable is instantiated */
85	ev->ev_sethook = sethook;
86	ev->ev_unsethook = unsethook;
87    }
88
89    /* If there is data in the variable, discard it */
90    if (ev->ev_value != NULL)
91	free(ev->ev_value);
92
93    /* If we have a new value, use it */
94    if (flags & EV_VOLATILE) {
95	ev->ev_value = strdup(value);
96    } else {
97	ev->ev_value = value;
98    }
99
100    /* Keep the flag components that are relevant */
101    ev->ev_flags = flags & (EV_DYNAMIC);
102
103    /* Sort into list */
104    ev->ev_prev = NULL;
105    ev->ev_next = NULL;
106
107    /* Search for the record to insert before */
108    for (last = NULL, curr = environ;
109	 curr != NULL;
110	 last = curr, curr = curr->ev_next) {
111
112	if (strcmp(ev->ev_name, curr->ev_name) < 0) {
113	    if (curr->ev_prev) {
114		curr->ev_prev->ev_next = ev;
115	    } else {
116		environ = ev;
117	    }
118	    ev->ev_next = curr;
119	    ev->ev_prev = curr->ev_prev;
120	    curr->ev_prev = ev;
121	    break;
122	}
123    }
124    if (curr == NULL) {
125	if (last == NULL) {
126	    environ = ev;
127	} else {
128	    last->ev_next = ev;
129	    ev->ev_prev = last;
130	}
131    }
132    return(0);
133}
134
135char *
136getenv(const char *name)
137{
138    struct env_var	*ev;
139
140    /* Set but no value gives empty string */
141    if ((ev = env_getenv(name)) != NULL) {
142	if (ev->ev_value != NULL)
143	    return(ev->ev_value);
144	return("");
145    }
146    return(NULL);
147}
148
149int
150setenv(const char *name, char *value, int overwrite)
151{
152    /* No guarantees about state, always assume volatile */
153    if (overwrite || (env_getenv(name) == NULL))
154	return(env_setenv(name, EV_VOLATILE, value, NULL, NULL));
155    return(0);
156}
157
158int
159putenv(const char *string)
160{
161    char	*value;
162
163    if ((value = strchr(string, '=')) != NULL)
164	*(value++) = 0;
165    return(setenv(string, value, 1));
166}
167
168int
169unsetenv(const char *name)
170{
171    struct env_var	*ev;
172    int			err;
173
174    err = 0;
175    if ((ev = env_getenv(name)) == NULL) {
176	err = ENOENT;
177    } else {
178	if (ev->ev_unsethook != NULL)
179	    err = ev->ev_unsethook(ev);
180	if (err == 0) {
181	    env_discard(ev);
182	}
183    }
184    return(err);
185}
186
187static void
188env_discard(struct env_var *ev)
189{
190    if (ev->ev_prev)
191	ev->ev_prev->ev_next = ev->ev_next;
192    if (ev->ev_next)
193	ev->ev_next->ev_prev = ev->ev_prev;
194    if (environ == ev)
195	environ = ev->ev_next;
196    free(ev->ev_name);
197    if (ev->ev_flags & EV_DYNAMIC)
198	free(ev->ev_value);
199    free(ev);
200}
201
202int
203env_noset(struct env_var *ev, int flags, void *value)
204{
205    return(EPERM);
206}
207
208int
209env_nounset(struct env_var *ev)
210{
211    return(EPERM);
212}
213