K&R style function removal. Update functions to ANSI style.
[dragonfly.git] / usr.bin / vgrind / vgrindefs.c
1 /*
2  * Copyright (c) 1980, 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  * @(#)vgrindefs.c      8.1 (Berkeley) 6/6/93
34  *
35  * $DragonFly: src/usr.bin/vgrind/vgrindefs.c,v 1.3 2003/10/04 20:36:54 hmp Exp $
36  */
37
38 #define BUFSIZ  1024
39 #define MAXHOP  32      /* max number of tc= indirections */
40
41 #include <ctype.h>
42 /*
43  * grindcap - routines for dealing with the language definitions data base
44  *      (code stolen almost totally from termcap)
45  *
46  * BUG:         Should use a "last" pointer in tbuf, so that searching
47  *              for capabilities alphabetically would not be a n**2/2
48  *              process when large numbers of capabilities are given.
49  * Note:        If we add a last pointer now we will screw up the
50  *              tc capability. We really should compile termcap.
51  *
52  * Essentially all the work here is scanning and decoding escapes
53  * in string capabilities.  We don't use stdio because the editor
54  * doesn't, and because living w/o it is not hard.
55  */
56
57 static  char *tbuf;
58 static  char *filename;
59 static  int hopcount;   /* detect infinite loops in termcap, init 0 */
60 char    *tskip();
61 char    *tgetstr();
62 char    *tdecode();
63 char    *getenv();
64
65 /*
66  * Get an entry for terminal name in buffer bp,
67  * from the termcap file.  Parse is very rudimentary;
68  * we just notice escaped newlines.
69  */
70 int
71 tgetent(char *bp, char *name, char *file)
72 {
73         register char *cp;
74         register int c;
75         register int i = 0, cnt = 0;
76         char ibuf[BUFSIZ];
77         char *cp2;
78         int tf;
79
80         tbuf = bp;
81         tf = 0;
82         filename = file;
83         tf = open(filename, 0);
84         if (tf < 0)
85                 return (-1);
86         for (;;) {
87                 cp = bp;
88                 for (;;) {
89                         if (i == cnt) {
90                                 cnt = read(tf, ibuf, BUFSIZ);
91                                 if (cnt <= 0) {
92                                         close(tf);
93                                         return (0);
94                                 }
95                                 i = 0;
96                         }
97                         c = ibuf[i++];
98                         if (c == '\n') {
99                                 if (cp > bp && cp[-1] == '\\'){
100                                         cp--;
101                                         continue;
102                                 }
103                                 break;
104                         }
105                         if (cp >= bp+BUFSIZ) {
106                                 write(2,"Vgrind entry too long\n", 23);
107                                 break;
108                         } else
109                                 *cp++ = c;
110                 }
111                 *cp = 0;
112
113                 /*
114                  * The real work for the match.
115                  */
116                 if (tnamatch(name)) {
117                         close(tf);
118                         return(tnchktc());
119                 }
120         }
121 }
122
123 /*
124  * tnchktc: check the last entry, see if it's tc=xxx. If so,
125  * recursively find xxx and append that entry (minus the names)
126  * to take the place of the tc=xxx entry. This allows termcap
127  * entries to say "like an HP2621 but doesn't turn on the labels".
128  * Note that this works because of the left to right scan.
129  */
130 int
131 tnchktc(void)
132 {
133         register char *p, *q;
134         char tcname[16];        /* name of similar terminal */
135         char tcbuf[BUFSIZ];
136         char *holdtbuf = tbuf;
137         int l;
138
139         p = tbuf + strlen(tbuf) - 2;    /* before the last colon */
140         while (*--p != ':')
141                 if (p<tbuf) {
142                         write(2, "Bad vgrind entry\n", 18);
143                         return (0);
144                 }
145         p++;
146         /* p now points to beginning of last field */
147         if (p[0] != 't' || p[1] != 'c')
148                 return(1);
149         strcpy(tcname,p+3);
150         q = tcname;
151         while (q && *q != ':')
152                 q++;
153         *q = 0;
154         if (++hopcount > MAXHOP) {
155                 write(2, "Infinite tc= loop\n", 18);
156                 return (0);
157         }
158         if (tgetent(tcbuf, tcname, filename) != 1)
159                 return(0);
160         for (q=tcbuf; *q != ':'; q++)
161                 ;
162         l = p - holdtbuf + strlen(q);
163         if (l > BUFSIZ) {
164                 write(2, "Vgrind entry too long\n", 23);
165                 q[BUFSIZ - (p-tbuf)] = 0;
166         }
167         strcpy(p, q+1);
168         tbuf = holdtbuf;
169         return(1);
170 }
171
172 /*
173  * Tnamatch deals with name matching.  The first field of the termcap
174  * entry is a sequence of names separated by |'s, so we compare
175  * against each such name.  The normal : terminator after the last
176  * name (before the first field) stops us.
177  */
178 int
179 tnamatch(char *np)
180 {
181         register char *Np, *Bp;
182
183         Bp = tbuf;
184         if (*Bp == '#')
185                 return(0);
186         for (;;) {
187                 for (Np = np; *Np && *Bp == *Np; Bp++, Np++)
188                         continue;
189                 if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0))
190                         return (1);
191                 while (*Bp && *Bp != ':' && *Bp != '|')
192                         Bp++;
193                 if (*Bp == 0 || *Bp == ':')
194                         return (0);
195                 Bp++;
196         }
197 }
198
199 /*
200  * Skip to the next field.  Notice that this is very dumb, not
201  * knowing about \: escapes or any such.  If necessary, :'s can be put
202  * into the termcap file in octal.
203  */
204 static char *
205 tskip(register char *bp)
206 {
207
208         while (*bp && *bp != ':')
209                 bp++;
210         if (*bp == ':')
211                 bp++;
212         return (bp);
213 }
214
215 /*
216  * Return the (numeric) option id.
217  * Numeric options look like
218  *      li#80
219  * i.e. the option string is separated from the numeric value by
220  * a # character.  If the option is not found we return -1.
221  * Note that we handle octal numbers beginning with 0.
222  */
223 int
224 tgetnum(char *id)
225 {
226         register int i, base;
227         register char *bp = tbuf;
228
229         for (;;) {
230                 bp = tskip(bp);
231                 if (*bp == 0)
232                         return (-1);
233                 if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
234                         continue;
235                 if (*bp == '@')
236                         return(-1);
237                 if (*bp != '#')
238                         continue;
239                 bp++;
240                 base = 10;
241                 if (*bp == '0')
242                         base = 8;
243                 i = 0;
244                 while (isdigit(*bp))
245                         i *= base, i += *bp++ - '0';
246                 return (i);
247         }
248 }
249
250 /*
251  * Handle a flag option.
252  * Flag options are given "naked", i.e. followed by a : or the end
253  * of the buffer.  Return 1 if we find the option, or 0 if it is
254  * not given.
255  */
256 int
257 tgetflag(char *id)
258 {
259         register char *bp = tbuf;
260
261         for (;;) {
262                 bp = tskip(bp);
263                 if (!*bp)
264                         return (0);
265                 if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) {
266                         if (!*bp || *bp == ':')
267                                 return (1);
268                         else if (*bp == '@')
269                                 return(0);
270                 }
271         }
272 }
273
274 /*
275  * Get a string valued option.
276  * These are given as
277  *      cl=^Z
278  * Much decoding is done on the strings, and the strings are
279  * placed in area, which is a ref parameter which is updated.
280  * No checking on area overflow.
281  */
282 char *
283 tgetstr(char *id, char **area)
284 {
285         register char *bp = tbuf;
286
287         for (;;) {
288                 bp = tskip(bp);
289                 if (!*bp)
290                         return (0);
291                 if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
292                         continue;
293                 if (*bp == '@')
294                         return(0);
295                 if (*bp != '=')
296                         continue;
297                 bp++;
298                 return (tdecode(bp, area));
299         }
300 }
301
302 /*
303  * Tdecode does the grung work to decode the
304  * string capability escapes.
305  */
306 static char *
307 tdecode(register char *str, char **area)
308 {
309         register char *cp;
310         register int c;
311         int i;
312
313         cp = *area;
314         while (c = *str++) {
315             if (c == ':' && *(cp-1) != '\\')
316                 break;
317             *cp++ = c;
318         }
319         *cp++ = 0;
320         str = *area;
321         *area = cp;
322         return (str);
323 }