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