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