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