xref: /freebsd/usr.bin/tip/tip/value.c (revision 06c3fb27)
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 "tip.h"
36 
37 #define MIDDLE	35
38 
39 static value_t *vlookup(char *);
40 static void vassign(value_t *, char *);
41 static void vtoken(char *);
42 static void vprint(value_t *);
43 static int vaccess(unsigned int, unsigned int);
44 static char *vinterp(char *, int);
45 
46 static size_t col = 0;
47 
48 /*
49  * Variable manipulation
50  */
51 void
52 vinit(void)
53 {
54 	char file[FILENAME_MAX], *cp;
55 	value_t *p;
56 	FILE *fp;
57 
58 	for (p = vtable; p->v_name != NULL; p++) {
59 		if (p->v_type&ENVIRON)
60 			if ((cp = getenv(p->v_name)))
61 				p->v_value = cp;
62 		if (p->v_type&IREMOTE) {
63 			switch (p->v_type&TMASK) {
64 			case STRING:
65 				p->v_value = *(char **)p->v_value;
66 				break;
67 			case NUMBER:
68 				setnumber(p->v_value, *(long *)p->v_value);
69 				break;
70 			case BOOL:
71 				setboolean(p->v_value, *(short *)p->v_value);
72 				break;
73 			case CHAR:
74 				setcharacter(p->v_value, *(char *)p->v_value);
75 				break;
76 			}
77 		}
78 	}
79 	/*
80 	 * Read the .tiprc file in the HOME directory
81 	 *  for sets
82 	 */
83 	cp = value(HOME);
84 	if (cp == NULL) {
85 		(void)fprintf(stderr,
86 		    "$HOME not set. Skipping check for ~/.tiprc\n");
87 	} else if (strlen(cp) + sizeof("/.tiprc") > sizeof(file)) {
88 		(void)fprintf(stderr, "Home directory path too long: %s\n",
89 		    value(HOME));
90 	} else {
91 		snprintf(file, sizeof file, "%s/.tiprc", value(HOME));
92 		if ((fp = fopen(file, "r")) != NULL) {
93 			char *tp;
94 
95 			while (fgets(file, sizeof(file)-1, fp) != NULL) {
96 				if (vflag)
97 					printf("set %s", file);
98 				if ((tp = strrchr(file, '\n')))
99 					*tp = '\0';
100 				vlex(file);
101 			}
102 			fclose(fp);
103 		}
104 	}
105 	/*
106 	 * To allow definition of exception prior to fork
107 	 */
108 	vtable[EXCEPTIONS].v_access &= ~(WRITE<<PUBLIC);
109 }
110 
111 /*VARARGS1*/
112 static void
113 vassign(value_t *p, char *v)
114 {
115 	if (!vaccess(p->v_access, WRITE)) {
116 		printf("access denied\r\n");
117 		return;
118 	}
119 
120 	switch (p->v_type&TMASK) {
121 	case STRING:
122 		if (p->v_value && equal(p->v_value, v))
123 			return;
124 		if (!(p->v_type&(ENVIRON|INIT)))
125 			free(p->v_value);
126 		if ((p->v_value = strdup(v)) == NOSTR) {
127 			printf("out of core\r\n");
128 			return;
129 		}
130 		p->v_type &= ~(ENVIRON|INIT);
131 		break;
132 	case NUMBER:
133 		if (number(p->v_value) == number(v))
134 			return;
135 		setnumber(p->v_value, number(v));
136 		break;
137 	case BOOL:
138 		if (boolean(p->v_value) == (*v != '!'))
139 			return;
140 		setboolean(p->v_value, (*v != '!'));
141 		break;
142 	case CHAR:
143 		if (character(p->v_value) == *v)
144 			return;
145 		setcharacter(p->v_value, *v);
146 	}
147 	p->v_access |= CHANGED;
148 }
149 
150 void
151 vlex(char *s)
152 {
153 	value_t *p;
154 	char *cp;
155 
156 	if (equal(s, "all")) {
157 		for (p = vtable; p->v_name; p++)
158 			if (vaccess(p->v_access, READ))
159 				vprint(p);
160 	} else {
161 		do {
162 			if ((cp = vinterp(s, ' ')))
163 				cp++;
164 			vtoken(s);
165 			s = cp;
166 		} while (s);
167 	}
168 	if (col > 0) {
169 		printf("\r\n");
170 		col = 0;
171 	}
172 }
173 
174 static void
175 vtoken(char *s)
176 {
177 	value_t *p;
178 	char *cp;
179 
180 	if ((cp = strchr(s, '='))) {
181 		*cp = '\0';
182 		if ((p = vlookup(s))) {
183 			cp++;
184 			if (p->v_type&NUMBER)
185 				vassign(p, (char *)(intptr_t)atoi(cp));
186 			else {
187 				if (strcmp(s, "record") == 0)
188 					cp = expand(cp);
189 				vassign(p, cp);
190 			}
191 			return;
192 		}
193 	} else if ((cp = strchr(s, '?'))) {
194 		*cp = '\0';
195 		if ((p = vlookup(s)) && vaccess(p->v_access, READ)) {
196 			vprint(p);
197 			return;
198 		}
199 	} else {
200 		if (*s != '!')
201 			p = vlookup(s);
202 		else
203 			p = vlookup(s+1);
204 		if (p != NOVAL) {
205 			vassign(p, s);
206 			return;
207 		}
208 	}
209 	printf("%s: unknown variable\r\n", s);
210 }
211 
212 static void
213 vprint(value_t *p)
214 {
215 	char *cp;
216 
217 	if (col > 0 && col < MIDDLE)
218 		while (col++ < MIDDLE)
219 			putchar(' ');
220 	col += size(p->v_name);
221 	switch (p->v_type&TMASK) {
222 
223 	case BOOL:
224 		if (boolean(p->v_value) == FALSE) {
225 			col++;
226 			putchar('!');
227 		}
228 		printf("%s", p->v_name);
229 		break;
230 
231 	case STRING:
232 		printf("%s=", p->v_name);
233 		col++;
234 		if (p->v_value) {
235 			cp = interp(p->v_value);
236 			col += size(cp);
237 			printf("%s", cp);
238 		}
239 		break;
240 
241 	case NUMBER:
242 		col += 6;
243 		printf("%s=%-5ld", p->v_name, number(p->v_value));
244 		break;
245 
246 	case CHAR:
247 		printf("%s=", p->v_name);
248 		col++;
249 		if (p->v_value) {
250 			cp = ctrl(character(p->v_value));
251 			col += size(cp);
252 			printf("%s", cp);
253 		}
254 		break;
255 	}
256 	if (col >= MIDDLE) {
257 		col = 0;
258 		printf("\r\n");
259 		return;
260 	}
261 }
262 
263 static int
264 vaccess(unsigned int mode, unsigned int rw)
265 {
266 	if (mode & (rw<<PUBLIC))
267 		return (1);
268 	if (mode & (rw<<PRIVATE))
269 		return (1);
270 	return ((mode & (rw<<ROOT)) && getuid() == 0);
271 }
272 
273 static value_t *
274 vlookup(char *s)
275 {
276 	value_t *p;
277 
278 	for (p = vtable; p->v_name; p++)
279 		if (equal(p->v_name, s) || (p->v_abrev && equal(p->v_abrev, s)))
280 			return (p);
281 	return (NULL);
282 }
283 
284 static char *
285 vinterp(char *s, int stop)
286 {
287 	char *p = s, c;
288 	int num;
289 
290 	while ((c = *s++) && c != stop) {
291 		switch (c) {
292 
293 		case '^':
294 			if (*s)
295 				*p++ = *s++ - 0100;
296 			else
297 				*p++ = c;
298 			break;
299 
300 		case '\\':
301 			num = 0;
302 			c = *s++;
303 			if (c >= '0' && c <= '7')
304 				num = (num<<3)+(c-'0');
305 			else {
306 				char *q = "n\nr\rt\tb\bf\f";
307 
308 				for (; *q; q++)
309 					if (c == *q++) {
310 						*p++ = *q;
311 						goto cont;
312 					}
313 				*p++ = c;
314 			cont:
315 				break;
316 			}
317 			if ((c = *s++) >= '0' && c <= '7') {
318 				num = (num<<3)+(c-'0');
319 				if ((c = *s++) >= '0' && c <= '7')
320 					num = (num<<3)+(c-'0');
321 				else
322 					s--;
323 			} else
324 				s--;
325 			*p++ = num;
326 			break;
327 
328 		default:
329 			*p++ = c;
330 		}
331 	}
332 	*p = '\0';
333 	return (c == stop ? s-1 : NULL);
334 }
335 
336 /*
337  * assign variable s with value v (for NUMBER or STRING or CHAR types)
338  */
339 int
340 vstring(char *s, char *v)
341 {
342 	value_t *p;
343 
344 	p = vlookup(s);
345 	if (p == 0)
346 		return (1);
347 	if (p->v_type&NUMBER)
348 		vassign(p, (char *)(intptr_t)atoi(v));
349 	else {
350 		if (strcmp(s, "record") == 0)
351 			v = expand(v);
352 		vassign(p, v);
353 	}
354 	return (0);
355 }
356