1/*
2 * Copyright 2000 Sun Microsystems, Inc.  All rights reserved.
3 * Use is subject to license terms.
4 */
5
6/*
7 * Copyright (c) 1983 Regents of the University of California.
8 * All rights reserved. The Berkeley software License Agreement
9 * specifies the terms and conditions for redistribution.
10 */
11
12#pragma ident	"%Z%%M%	%I%	%E% SMI"
13
14#include "tip.h"
15
16#define	MIDDLE	35
17
18static value_t *vlookup(char *);
19static int col = 0;
20
21extern char	*interp(char *);
22
23static void	vtoken(char *);
24static void	vprint(value_t *);
25static int	vaccess(unsigned, unsigned);
26
27/*
28 * Variable manipulation
29 */
30void
31vinit(void)
32{
33	value_t *p;
34	char *cp;
35	FILE *f;
36	char file[1024];
37
38	for (p = vtable; p->v_name != NULL; p++) {
39		if (p->v_type&ENVIRON)
40			if (cp = getenv(p->v_name))
41				p->v_value = cp;
42		if (p->v_type&IREMOTE)
43			number(p->v_value) = *address(p->v_value);
44	}
45	/*
46	 * Read the .tiprc file in the HOME directory
47	 *  for sets
48	 */
49	if ((cp = value(HOME)) == NULL)
50		cp = "";
51	(void) strlcpy(file, cp, sizeof (file));
52	(void) strlcat(file, "/.tiprc", sizeof (file));
53	if ((f = fopen(file, "r")) != NULL) {
54		char *tp;
55
56		while (fgets(file, sizeof (file)-1, f) != NULL) {
57			if (file[0] == '#')
58				continue;
59			if (vflag)
60				(void) printf("set %s", file);
61			if (tp = strrchr(file, '\n'))
62				*tp = '\0';
63			vlex(file);
64		}
65		(void) fclose(f);
66	}
67	/*
68	 * To allow definition of exception prior to fork
69	 */
70	vtable[EXCEPTIONS].v_access &= ~(WRITE<<PUBLIC);
71}
72
73/*VARARGS1*/
74void
75vassign(value_t *p, char *v)
76{
77
78	if (!vaccess(p->v_access, WRITE)) {
79		(void) printf("access denied\r\n");
80		return;
81	}
82	switch (p->v_type&TMASK) {
83
84	case STRING:
85		if (p->v_value != (char *)NULL) {
86			if (equal(p->v_value, v))
87				return;
88			if (!(p->v_type&(ENVIRON|INIT)))
89				free(p->v_value);
90		}
91		if ((p->v_value = malloc(strlen(v)+1)) == NOSTR) {
92			(void) printf("out of core\r\n");
93			return;
94		}
95		p->v_type &= ~(ENVIRON|INIT);
96		(void) strcpy(p->v_value, v);
97		break;
98
99	case NUMBER:
100		if (number(p->v_value) == number(v))
101			return;
102		number(p->v_value) = number(v);
103		break;
104
105	case BOOL:
106		if (boolean(p->v_value) == (*v != '!'))
107			return;
108		boolean(p->v_value) = (*v != '!');
109		break;
110
111	case CHAR:
112		if (character(p->v_value) == *v)
113			return;
114		character(p->v_value) = *v;
115	}
116	p->v_access |= CHANGED;
117}
118
119void
120vlex(char *s)
121{
122	value_t *p;
123
124	if (equal(s, "all")) {
125		for (p = vtable; p->v_name; p++)
126			if (vaccess(p->v_access, READ))
127				vprint(p);
128	} else {
129		char *cp;
130
131		do {
132			if (cp = vinterp(s, ' '))
133				cp++;
134			vtoken(s);
135			s = cp;
136		} while (s);
137	}
138	if (col > 0) {
139		(void) printf("\r\n");
140		col = 0;
141	}
142}
143
144static void
145vtoken(char *s)
146{
147	value_t *p;
148	char *cp, *cp2;
149
150	if (cp = strchr(s, '=')) {
151		*cp = '\0';
152		if (p = vlookup(s)) {
153			cp++;
154			if (p->v_type&NUMBER)
155				vassign(p, (char *)atoi(cp));
156			else {
157				if (strcmp(s, "record") == 0)
158					if ((cp2 = expand(cp)) != NOSTR)
159						cp = cp2;
160				vassign(p, cp);
161			}
162			return;
163		}
164	} else if (cp = strchr(s, '?')) {
165		*cp = '\0';
166		if ((p = vlookup(s)) != NULL && vaccess(p->v_access, READ)) {
167			vprint(p);
168			return;
169		}
170	} else {
171		if (*s != '!')
172			p = vlookup(s);
173		else
174			p = vlookup(s+1);
175		if (p != NOVAL) {
176			if (p->v_type&BOOL)
177				vassign(p, s);
178			else
179				(void) printf("%s: no value specified\r\n", s);
180			return;
181		}
182	}
183	(void) printf("%s: unknown variable\r\n", s);
184}
185
186static void
187vprint(value_t *p)
188{
189	char *cp;
190
191	if (col > 0 && col < MIDDLE)
192		while (col++ < MIDDLE)
193			(void) putchar(' ');
194	col += strlen(p->v_name);
195	switch (p->v_type&TMASK) {
196
197	case BOOL:
198		if (boolean(p->v_value) == FALSE) {
199			col++;
200			(void) putchar('!');
201		}
202		(void) printf("%s", p->v_name);
203		break;
204
205	case STRING:
206		(void) printf("%s=", p->v_name);
207		col++;
208		if (p->v_value) {
209			cp = interp(p->v_value);
210			col += strlen(cp);
211			(void) printf("%s", cp);
212		}
213		break;
214
215	case NUMBER:
216		col += 6;
217		(void) printf("%s=%-5d", p->v_name, number(p->v_value));
218		break;
219
220	case CHAR:
221		(void) printf("%s=", p->v_name);
222		col++;
223		if (p->v_value) {
224			cp = ctrl(character(p->v_value));
225			col += strlen(cp);
226			(void) printf("%s", cp);
227		}
228		break;
229	}
230	if (col >= MIDDLE) {
231		col = 0;
232		(void) printf("\r\n");
233		return;
234	}
235}
236
237
238static int
239vaccess(unsigned mode, unsigned rw)
240{
241	if (mode & (rw<<PUBLIC))
242		return (1);
243	if (mode & (rw<<PRIVATE))
244		return (1);
245	return ((mode & (rw<<ROOT)) && uid == 0);
246}
247
248static value_t *
249vlookup(char *s)
250{
251	value_t *p;
252
253	for (p = vtable; p->v_name; p++)
254		if (equal(p->v_name, s) || (p->v_abrev && equal(p->v_abrev, s)))
255			return (p);
256	return (NULL);
257}
258
259char *
260vinterp(char *s, char stop)
261{
262	char *p = s, c;
263	int num;
264
265	while ((c = *s++) != 0 && c != stop)
266		switch (c) {
267
268		case '^':
269			if (*s)
270				*p++ = *s++ - 0100;
271			else
272				*p++ = c;
273			break;
274
275		case '\\':
276			num = 0;
277			c = *s++;
278			if (c >= '0' && c <= '7')
279				num = (num<<3)+(c-'0');
280			else {
281				char *q = "n\nr\rt\tb\bf\f";
282
283				for (; *q; q++)
284					if (c == *q++) {
285						*p++ = *q;
286						goto cont;
287					}
288				*p++ = c;
289			cont:
290				break;
291			}
292			if ((c = *s++) >= '0' && c <= '7') {
293				num = (num<<3)+(c-'0');
294				if ((c = *s++) >= '0' && c <= '7')
295					num = (num<<3)+(c-'0');
296				else
297					s--;
298			} else
299				s--;
300			*p++ = num;
301			break;
302
303		default:
304			*p++ = c;
305		}
306	*p = '\0';
307	return (c == stop ? s-1 : NULL);
308}
309
310/*
311 * assign variable s with value v (for NUMBER or STRING or CHAR types)
312 */
313int
314vstring(char *s, char *v)
315{
316	value_t *p;
317	char *v2;
318
319	p = vlookup(s);
320	if (p == 0)
321		return (1);
322	if (p->v_type&NUMBER)
323		vassign(p, (char *)atoi(v));
324	else {
325		if (strcmp(s, "record") == 0)
326			if ((v2 = expand(v)) != NOSTR)
327				v = v2;
328		vassign(p, v);
329	}
330	return (0);
331}
332