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