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