1199767fToomas Soome/*
2199767fToomas Soome * Copyright (c) 1998 Michael Smith.
3199767fToomas Soome * All rights reserved.
4199767fToomas Soome *
5199767fToomas Soome * Redistribution and use in source and binary forms, with or without
6199767fToomas Soome * modification, are permitted provided that the following conditions
7199767fToomas Soome * are met:
8199767fToomas Soome * 1. Redistributions of source code must retain the above copyright
9199767fToomas Soome *    notice, this list of conditions and the following disclaimer.
10199767fToomas Soome * 2. Redistributions in binary form must reproduce the above copyright
11199767fToomas Soome *    notice, this list of conditions and the following disclaimer in the
12199767fToomas Soome *    documentation and/or other materials provided with the distribution.
13199767fToomas Soome *
14199767fToomas Soome * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15199767fToomas Soome * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16199767fToomas Soome * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17199767fToomas Soome * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18199767fToomas Soome * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19199767fToomas Soome * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20199767fToomas Soome * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21199767fToomas Soome * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22199767fToomas Soome * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23199767fToomas Soome * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24199767fToomas Soome * SUCH DAMAGE.
25199767fToomas Soome */
26199767fToomas Soome
27199767fToomas Soome#include <sys/cdefs.h>
28199767fToomas Soome__FBSDID("$FreeBSD$");
29199767fToomas Soome
30199767fToomas Soome/*
31199767fToomas Soome * Manage an environment-like space in which string variables may be stored.
32199767fToomas Soome * Provide support for some method-like operations for setting/retrieving
33199767fToomas Soome * variables in order to allow some type strength.
34199767fToomas Soome */
35199767fToomas Soome
36199767fToomas Soome#include "stand.h"
37199767fToomas Soome
38199767fToomas Soome#include <string.h>
39199767fToomas Soome
40199767fToomas Soomestatic void	env_discard(struct env_var *ev);
41199767fToomas Soome
42199767fToomas Soomestruct env_var	*environ = NULL;
43199767fToomas Soome
44199767fToomas Soome/*
45199767fToomas Soome * Look up (name) and return it's env_var structure.
46199767fToomas Soome */
47199767fToomas Soomestruct env_var	*
48199767fToomas Soomeenv_getenv(const char *name)
49199767fToomas Soome{
50199767fToomas Soome    struct env_var	*ev;
51199767fToomas Soome
52199767fToomas Soome    for (ev = environ; ev != NULL; ev = ev->ev_next)
53199767fToomas Soome	if (!strcmp(ev->ev_name, name))
54199767fToomas Soome	    break;
55199767fToomas Soome    return(ev);
56199767fToomas Soome}
57199767fToomas Soome
58199767fToomas Soome/*
59199767fToomas Soome * Some notes:
60199767fToomas Soome *
61199767fToomas Soome * If the EV_VOLATILE flag is set, a copy of the variable is made.
62199767fToomas Soome * If EV_DYNAMIC is set, the variable has been allocated with
63199767fToomas Soome * malloc and ownership transferred to the environment.
64199767fToomas Soome * If (value) is NULL, the variable is set but has no value.
65199767fToomas Soome */
66199767fToomas Soomeint
67199767fToomas Soomeenv_setenv(const char *name, int flags, const void *value,
68199767fToomas Soome	   ev_sethook_t sethook, ev_unsethook_t unsethook)
69199767fToomas Soome{
70199767fToomas Soome    struct env_var	*ev, *curr, *last;
71199767fToomas Soome
72199767fToomas Soome    if ((ev = env_getenv(name)) != NULL) {
73199767fToomas Soome	/*
74199767fToomas Soome	 * If there's a set hook, let it do the work (unless we are working
75199767fToomas Soome	 * for one already.
76199767fToomas Soome	 */
77199767fToomas Soome	if ((ev->ev_sethook != NULL) && !(flags & EV_NOHOOK))
78199767fToomas Soome	    return (ev->ev_sethook(ev, flags, value));
79199767fToomas Soome
80199767fToomas Soome	/* If there is data in the variable, discard it. */
81199767fToomas Soome	if (ev->ev_value != NULL && (ev->ev_flags & EV_DYNAMIC) != 0)
82199767fToomas Soome	    free(ev->ev_value);
83199767fToomas Soome	ev->ev_value = NULL;
84199767fToomas Soome	ev->ev_flags &= ~EV_DYNAMIC;
85199767fToomas Soome
86199767fToomas Soome    } else {
87199767fToomas Soome
88199767fToomas Soome	/*
89199767fToomas Soome	 * New variable; create and sort into list
90199767fToomas Soome	 */
91199767fToomas Soome	ev = malloc(sizeof(struct env_var));
92199767fToomas Soome	ev->ev_name = strdup(name);
93199767fToomas Soome	ev->ev_value = NULL;
94199767fToomas Soome	ev->ev_flags = 0;
95199767fToomas Soome	/* hooks can only be set when the variable is instantiated */
96199767fToomas Soome	ev->ev_sethook = sethook;
97199767fToomas Soome	ev->ev_unsethook = unsethook;
98199767fToomas Soome
99199767fToomas Soome	/* Sort into list */
100199767fToomas Soome	ev->ev_prev = NULL;
101199767fToomas Soome	ev->ev_next = NULL;
102199767fToomas Soome	/* Search for the record to insert before */
103199767fToomas Soome	for (last = NULL, curr = environ;
104199767fToomas Soome	     curr != NULL;
105199767fToomas Soome	     last = curr, curr = curr->ev_next) {
106199767fToomas Soome
107199767fToomas Soome	    if (strcmp(ev->ev_name, curr->ev_name) < 0) {
108199767fToomas Soome		if (curr->ev_prev) {
109199767fToomas Soome		    curr->ev_prev->ev_next = ev;
110199767fToomas Soome		} else {
111199767fToomas Soome		    environ = ev;
112199767fToomas Soome		}
113199767fToomas Soome		ev->ev_next = curr;
114199767fToomas Soome		ev->ev_prev = curr->ev_prev;
115199767fToomas Soome		curr->ev_prev = ev;
116199767fToomas Soome		break;
117199767fToomas Soome	    }
118199767fToomas Soome	}
119199767fToomas Soome	if (curr == NULL) {
120199767fToomas Soome	    if (last == NULL) {
121199767fToomas Soome		environ = ev;
122199767fToomas Soome	    } else {
123199767fToomas Soome		last->ev_next = ev;
124199767fToomas Soome		ev->ev_prev = last;
125199767fToomas Soome	    }
126199767fToomas Soome	}
127199767fToomas Soome    }
128199767fToomas Soome
129199767fToomas Soome    /* If we have a new value, use it */
130199767fToomas Soome    if (flags & EV_VOLATILE) {
131199767fToomas Soome	ev->ev_value = strdup(value);
132199767fToomas Soome	ev->ev_flags |= EV_DYNAMIC;
133199767fToomas Soome    } else {
134199767fToomas Soome	ev->ev_value = (char *)value;
135199767fToomas Soome	ev->ev_flags |= flags & EV_DYNAMIC;
136199767fToomas Soome    }
137199767fToomas Soome
138199767fToomas Soome    return(0);
139199767fToomas Soome}
140199767fToomas Soome
141199767fToomas Soomechar *
142199767fToomas Soomegetenv(const char *name)
143199767fToomas Soome{
144199767fToomas Soome    struct env_var	*ev;
145199767fToomas Soome
146199767fToomas Soome    /* Set but no value gives empty string */
147199767fToomas Soome    if ((ev = env_getenv(name)) != NULL) {
148199767fToomas Soome	if (ev->ev_value != NULL)
149199767fToomas Soome	    return(ev->ev_value);
150199767fToomas Soome	return("");
151199767fToomas Soome    }
152199767fToomas Soome    return(NULL);
153199767fToomas Soome}
154199767fToomas Soome
155199767fToomas Soomeint
156199767fToomas Soomesetenv(const char *name, const char *value, int overwrite)
157199767fToomas Soome{
158199767fToomas Soome    /* No guarantees about state, always assume volatile */
159199767fToomas Soome    if (overwrite || (env_getenv(name) == NULL))
160199767fToomas Soome	return(env_setenv(name, EV_VOLATILE, value, NULL, NULL));
161199767fToomas Soome    return(0);
162199767fToomas Soome}
163199767fToomas Soome
164199767fToomas Soomeint
165199767fToomas Soomeputenv(const char *string)
166199767fToomas Soome{
167199767fToomas Soome    char	*value, *copy;
168199767fToomas Soome    int		result;
169199767fToomas Soome
170199767fToomas Soome    copy = strdup(string);
171199767fToomas Soome    if ((value = strchr(copy, '=')) != NULL)
172199767fToomas Soome	*(value++) = 0;
173199767fToomas Soome    result = setenv(copy, value, 1);
174199767fToomas Soome    free(copy);
175199767fToomas Soome    return(result);
176199767fToomas Soome}
177199767fToomas Soome
178199767fToomas Soomeint
179199767fToomas Soomeunsetenv(const char *name)
180199767fToomas Soome{
181199767fToomas Soome    struct env_var	*ev;
182199767fToomas Soome    int			err;
183199767fToomas Soome
184199767fToomas Soome    err = 0;
185199767fToomas Soome    if ((ev = env_getenv(name)) == NULL) {
186199767fToomas Soome	err = ENOENT;
187199767fToomas Soome    } else {
188199767fToomas Soome	if (ev->ev_unsethook != NULL)
189199767fToomas Soome	    err = ev->ev_unsethook(ev);
190199767fToomas Soome	if (err == 0) {
191199767fToomas Soome	    env_discard(ev);
192199767fToomas Soome	}
193199767fToomas Soome    }
194199767fToomas Soome    return(err);
195199767fToomas Soome}
196199767fToomas Soome
197199767fToomas Soomestatic void
198199767fToomas Soomeenv_discard(struct env_var *ev)
199199767fToomas Soome{
200199767fToomas Soome    if (ev->ev_prev)
201199767fToomas Soome	ev->ev_prev->ev_next = ev->ev_next;
202199767fToomas Soome    if (ev->ev_next)
203199767fToomas Soome	ev->ev_next->ev_prev = ev->ev_prev;
204199767fToomas Soome    if (environ == ev)
205199767fToomas Soome	environ = ev->ev_next;
206199767fToomas Soome    free(ev->ev_name);
207199767fToomas Soome    if (ev->ev_value != NULL && (ev->ev_flags & EV_DYNAMIC) != 0)
208199767fToomas Soome	free(ev->ev_value);
209199767fToomas Soome    free(ev);
210199767fToomas Soome}
211199767fToomas Soome
212199767fToomas Soomeint
213199767fToomas Soomeenv_noset(struct env_var *ev __unused, int flags __unused,
214199767fToomas Soome    const void *value __unused)
215199767fToomas Soome{
216199767fToomas Soome    return(EPERM);
217199767fToomas Soome}
218199767fToomas Soome
219199767fToomas Soomeint
220199767fToomas Soomeenv_nounset(struct env_var *ev __unused)
221199767fToomas Soome{
222199767fToomas Soome    return(EPERM);
223199767fToomas Soome}
224