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