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