1/*	$NetBSD: value.c,v 1.13 2006/04/03 04:53:58 christos Exp $	*/
2
3/*
4 * Copyright (c) 1983, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#include <sys/cdefs.h>
33#ifndef lint
34#if 0
35static char sccsid[] = "@(#)value.c	8.1 (Berkeley) 6/6/93";
36#endif
37__RCSID("$NetBSD: value.c,v 1.13 2006/04/03 04:53:58 christos Exp $");
38#endif /* not lint */
39
40#include "tip.h"
41
42#define MIDDLE	35
43
44static int col = 0;
45
46static	int	vaccess(int, int);
47static	void	vassign(value_t *, char *);
48static	value_t *vlookup(const char *);
49static	void	vprint(value_t *);
50static	void	vtoken(char *);
51
52/*
53 * Variable manipulation
54 */
55void
56vinit(void)
57{
58	value_t *p;
59	char *cp;
60	FILE *f;
61	char file[MAXPATHLEN];
62
63	for (p = vtable; p->v_name != NULL; p++) {
64		if (p->v_type&ENVIRON)
65			if ((cp = getenv(p->v_name)) != NULL)
66				p->v_value = cp;
67		if (p->v_type&IREMOTE)
68			setnumber(p->v_value, *address(p->v_value));
69	}
70	/*
71	 * Read the .tiprc file in the HOME directory
72	 *  for sets
73	 */
74	(void)snprintf(file, sizeof(file), "%s/.tiprc", (char *)value(HOME));
75	if ((f = fopen(file, "r")) != NULL) {
76		char *tp;
77
78		while (fgets(file, sizeof(file)-1, f) != NULL) {
79			if (vflag)
80				(void)printf("set %s", file);
81			if ((tp = strrchr(file, '\n')) != NULL)
82				*tp = '\0';
83			vlex(file);
84		}
85		(void)fclose(f);
86	}
87	/*
88	 * To allow definition of exception prior to fork
89	 */
90	vtable[EXCEPTIONS].v_access &= ~(WRITE<<PUBLIC);
91}
92
93void
94vassign(value_t *p, char *v)
95{
96
97	if (!vaccess(p->v_access, (unsigned int)WRITE)) {
98		(void)printf("access denied\r\n");
99		return;
100	}
101	switch (p->v_type&TMASK) {
102
103	case STRING:
104		if (p->v_value && equal(p->v_value, v))
105			return;
106		if (!(p->v_type&(ENVIRON|INIT)))
107			free(p->v_value);
108		if ((p->v_value = strdup(v)) == NULL) {
109			(void)printf("out of core\r\n");
110			return;
111		}
112		p->v_type &= ~(ENVIRON|INIT);
113		break;
114
115	case NUMBER:
116		if (number(p->v_value) == number(v))
117			return;
118		setnumber(p->v_value, number(v));
119		break;
120
121	case BOOL:
122		if (boolean(p->v_value) == (*v != '!'))
123			return;
124		setboolean(p->v_value, (*v != '!'));
125		break;
126
127	case CHAR:
128		if (character(p->v_value) == *v)
129			return;
130		setcharacter(p->v_value, *v);
131	}
132	p->v_access |= CHANGED;
133}
134
135void
136vlex(char *s)
137{
138	value_t *p;
139
140	if (equal(s, "all")) {
141		for (p = vtable; p->v_name; p++)
142			if (vaccess(p->v_access, READ))
143				vprint(p);
144	} else {
145		char *cp;
146
147		do {
148			if ((cp = vinterp(s, ' ')) != NULL)
149				cp++;
150			vtoken(s);
151			s = cp;
152		} while (s);
153	}
154	if (col > 0) {
155		(void)printf("\r\n");
156		col = 0;
157	}
158}
159
160static void
161vtoken(char *s)
162{
163	value_t *p;
164	char *cp;
165
166	if ((cp = strchr(s, '=')) != NULL) {
167		*cp = '\0';
168		if ((p = vlookup(s)) != NULL) {
169			cp++;
170			if (p->v_type&NUMBER)
171				vassign(p, (char *)(long)atoi(cp));
172			else {
173				if (strcmp(s, "record") == 0)
174					cp = expand(cp);
175				vassign(p, cp);
176			}
177			return;
178		}
179	} else if ((cp = strchr(s, '?')) != NULL) {
180		*cp = '\0';
181		if ((p = vlookup(s)) && vaccess(p->v_access, READ)) {
182			vprint(p);
183			return;
184		}
185	} else {
186		if (*s != '!')
187			p = vlookup(s);
188		else
189			p = vlookup(s+1);
190		if (p != NULL) {
191			vassign(p, s);
192			return;
193		}
194	}
195	(void)printf("%s: unknown variable\r\n", s);
196}
197
198static void
199vprint(value_t *p)
200{
201	char *cp;
202
203	if (col > 0 && col < MIDDLE)
204		while (col++ < MIDDLE)
205			(void)putchar(' ');
206	col += strlen(p->v_name);
207	switch (p->v_type&TMASK) {
208
209	case BOOL:
210		if (boolean(p->v_value) == FALSE) {
211			col++;
212			(void)putchar('!');
213		}
214		(void)printf("%s", p->v_name);
215		break;
216
217	case STRING:
218		(void)printf("%s=", p->v_name);
219		col++;
220		if (p->v_value) {
221			cp = interp(p->v_value);
222			col += strlen(cp);
223			(void)printf("%s", cp);
224		}
225		break;
226
227	case NUMBER:
228		col += 6;
229		(void)printf("%s=%-5d", p->v_name, (int)number(p->v_value));
230		break;
231
232	case CHAR:
233		(void)printf("%s=", p->v_name);
234		col++;
235		if (p->v_value) {
236			cp = ctrl(character(p->v_value));
237			col += strlen(cp);
238			(void)printf("%s", cp);
239		}
240		break;
241	}
242	if (col >= MIDDLE) {
243		col = 0;
244		(void)printf("\r\n");
245		return;
246	}
247}
248
249
250static int
251vaccess(int mode, int rw)
252{
253
254	if (mode & (rw<<PUBLIC))
255		return (1);
256	if (mode & (rw<<PRIVATE))
257		return (1);
258	return ((mode & (rw<<ROOT)) && getuid() == 0);
259}
260
261static value_t *
262vlookup(const char *s)
263{
264	value_t *p;
265
266	for (p = vtable; p->v_name; p++)
267		if (equal(p->v_name, s) || (p->v_abrev && equal(p->v_abrev, s)))
268			return (p);
269	return (NULL);
270}
271
272char *
273vinterp(char *s, char stp)
274{
275	char *p = s, c;
276	int num;
277
278	while ((c = *s++) && c != stp)
279		switch (c) {
280
281		case '^':
282			if (*s)
283				*p++ = *s++ - 0100;
284			else
285				*p++ = c;
286			break;
287
288		case '\\':
289			num = 0;
290			c = *s++;
291			if (c >= '0' && c <= '7')
292				num = (num<<3)+(c-'0');
293			else {
294				const char *q = "n\nr\rt\tb\bf\f";
295
296				for (; *q; q++)
297					if (c == *q++) {
298						*p++ = *q;
299						goto cont;
300					}
301				*p++ = c;
302			cont:
303				break;
304			}
305			if ((c = *s++) >= '0' && c <= '7') {
306				num = (num<<3)+(c-'0');
307				if ((c = *s++) >= '0' && c <= '7')
308					num = (num<<3)+(c-'0');
309				else
310					s--;
311			} else
312				s--;
313			*p++ = num;
314			break;
315
316		default:
317			*p++ = c;
318		}
319	*p = '\0';
320	return (c == stp ? s-1 : NULL);
321}
322
323/*
324 * assign variable s with value v (for NUMBER or STRING or CHAR types)
325 */
326
327int
328vstring(const char *s, char *v)
329{
330	value_t *p;
331
332	p = vlookup(s);
333	if (p == 0)
334		return (1);
335	if (p->v_type&NUMBER)
336		vassign(p, (char *)(long)atoi(v));
337	else {
338		if (strcmp(s, "record") == 0)
339			v = expand(v);
340		vassign(p, v);
341	}
342	return (0);
343}
344