]> arthur.barton.de Git - netatalk.git/blob - etc/papd/printcap.c
implemented config.h
[netatalk.git] / etc / papd / printcap.c
1 /*
2  * Copyright (c) 1990,1994 Regents of The University of Michigan.
3  * All Rights Reserved.  See COPYRIGHT.
4  */
5
6 /*
7  * Copyright (c) 1983 Regents of the University of California.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *      This product includes software developed by the University of
21  *      California, Berkeley and its contributors.
22  * 4. Neither the name of the University nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  */
38
39 #ifdef HAVE_CONFIG_H
40 #include "config.h"
41 #endif
42
43 #ifndef lint
44 static char sccsid[] = "@(#)printcap.c  5.7 (Berkeley) 3/4/91";
45 #endif /* not lint */
46
47 #include <ctype.h>
48 #include <stdio.h>
49 #include <string.h>
50 #include <atalk/paths.h>
51
52 #ifndef BUFSIZ
53 #define BUFSIZ  1024
54 #endif
55 #define MAXHOP  32      /* max number of tc= indirections */
56
57 /*
58  * termcap - routines for dealing with the terminal capability data base
59  *
60  * BUG:         Should use a "last" pointer in tbuf, so that searching
61  *              for capabilities alphabetically would not be a n**2/2
62  *              process when large numbers of capabilities are given.
63  * Note:        If we add a last pointer now we will screw up the
64  *              tc capability. We really should compile termcap.
65  *
66  * Essentially all the work here is scanning and decoding escapes
67  * in string capabilities.  We don't use stdio because the editor
68  * doesn't, and because living w/o it is not hard.
69  */
70
71 #define PRINTCAP
72
73 #ifdef PRINTCAP
74 #define tgetent pgetent
75 #define tskip   pskip
76 #define tgetstr pgetstr
77 #define tdecode pdecode
78 #define tgetnum pgetnum
79 #define tgetflag pgetflag
80 #define tdecode pdecode
81 #define tnchktc pnchktc
82 #define tnamatch pnamatch
83 #define V6
84 #endif
85
86 static  FILE *pfp = NULL;       /* printcap data base file pointer */
87 static  char *tbuf;
88 static  int hopcount;           /* detect infinite loops in termcap, init 0 */
89 static char     *tskip();
90 char    *tgetstr();
91 static char     *tdecode();
92 char    *getenv();
93
94 /*
95  * Similar to tgetent except it returns the next entry instead of
96  * doing a lookup.
97  *
98  * Added a "cap" parameter, so we can use these calls for printcap
99  * and papd.conf.
100  */
101 getprent( cap, bp)
102         register char *cap;
103         register char *bp;
104 {
105         register int c, skip = 0;
106
107         if (pfp == NULL && (pfp = fopen( cap, "r")) == NULL)
108                 return(-1);
109         tbuf = bp;
110         for (;;) {
111                 switch (c = getc(pfp)) {
112                 case EOF:
113                         fclose(pfp);
114                         pfp = NULL;
115                         return(0);
116                 case '\n':
117                         if (bp == tbuf) {
118                                 skip = 0;
119                                 continue;
120                         }
121                         if (bp[-1] == '\\') {
122                                 bp--;
123                                 continue;
124                         }
125                         *bp = '\0';
126                         return(1);
127                 case '#':
128                         if (bp == tbuf)
129                                 skip++;
130                 default:
131                         if (skip)
132                                 continue;
133                         if (bp >= tbuf+BUFSIZ) {
134                                 write(2, "Termcap entry too long\n", 23);
135                                 *bp = '\0';
136                                 return(1);
137                         }
138                         *bp++ = c;
139                 }
140         }
141 }
142
143 endprent()
144 {
145         if (pfp != NULL)
146                 fclose(pfp);
147 }
148
149 /*
150  * Get an entry for terminal name in buffer bp,
151  * from the termcap file.  Parse is very rudimentary;
152  * we just notice escaped newlines.
153  *
154  * Added a "cap" parameter, so we can use these calls for printcap
155  * and papd.conf.
156  */
157 tgetent( cap, bp, name)
158         char *cap, *bp, *name;
159 {
160         register char *cp;
161         register int c;
162         register int i = 0, cnt = 0;
163         char ibuf[BUFSIZ];
164         int tf;
165
166         hopcount = 0;
167         tbuf = bp;
168         tf = 0;
169 #ifndef V6
170         cp = getenv("TERMCAP");
171         /*
172          * TERMCAP can have one of two things in it. It can be the
173          * name of a file to use instead of /etc/termcap. In this
174          * case it better start with a "/". Or it can be an entry to
175          * use so we don't have to read the file. In this case it
176          * has to already have the newlines crunched out.
177          */
178         if (cp && *cp) {
179                 if (*cp!='/') {
180                         cp2 = getenv("TERM");
181                         if (cp2==(char *) 0 || strcmp(name,cp2)==0) {
182                                 strcpy(bp,cp);
183                                 return(tnchktc());
184                         } else {
185                                 tf = open(cap, 0);
186                         }
187                 } else
188                         tf = open(cp, 0);
189         }
190         if (tf==0)
191                 tf = open(cap, 0);
192 #else
193         tf = open(cap, 0);
194 #endif
195         if (tf < 0)
196                 return (-1);
197         for (;;) {
198                 cp = bp;
199                 for (;;) {
200                         if (i == cnt) {
201                                 cnt = read(tf, ibuf, BUFSIZ);
202                                 if (cnt <= 0) {
203                                         close(tf);
204                                         return (0);
205                                 }
206                                 i = 0;
207                         }
208                         c = ibuf[i++];
209                         if (c == '\n') {
210                                 if (cp > bp && cp[-1] == '\\'){
211                                         cp--;
212                                         continue;
213                                 }
214                                 break;
215                         }
216                         if (cp >= bp+BUFSIZ) {
217                                 write(2,"Termcap entry too long\n", 23);
218                                 break;
219                         } else
220                                 *cp++ = c;
221                 }
222                 *cp = 0;
223
224                 /*
225                  * The real work for the match.
226                  */
227                 if (tnamatch(name)) {
228                         close(tf);
229                         return(tnchktc());
230                 }
231         }
232 }
233
234 /*
235  * tnchktc: check the last entry, see if it's tc=xxx. If so,
236  * recursively find xxx and append that entry (minus the names)
237  * to take the place of the tc=xxx entry. This allows termcap
238  * entries to say "like an HP2621 but doesn't turn on the labels".
239  * Note that this works because of the left to right scan.
240  *
241  * Added a "cap" parameter, so we can use these calls for printcap
242  * and papd.conf.
243  */
244 tnchktc( cap )
245     char *cap;
246 {
247         register char *p, *q;
248         char tcname[16];        /* name of similar terminal */
249         char tcbuf[BUFSIZ];
250         char *holdtbuf = tbuf;
251         int l;
252
253         p = tbuf + strlen(tbuf) - 2;    /* before the last colon */
254         while (*--p != ':')
255                 if (p<tbuf) {
256                         write(2, "Bad termcap entry\n", 18);
257                         return (0);
258                 }
259         p++;
260         /* p now points to beginning of last field */
261         if (p[0] != 't' || p[1] != 'c')
262                 return(1);
263         strcpy(tcname,p+3);
264         q = tcname;
265         while (q && *q != ':')
266                 q++;
267         *q = 0;
268         if (++hopcount > MAXHOP) {
269                 write(2, "Infinite tc= loop\n", 18);
270                 return (0);
271         }
272         if (tgetent( cap, tcbuf, tcname) != 1)
273                 return(0);
274         for (q=tcbuf; *q != ':'; q++)
275                 ;
276         l = p - holdtbuf + strlen(q);
277         if (l > BUFSIZ) {
278                 write(2, "Termcap entry too long\n", 23);
279                 q[BUFSIZ - (p-tbuf)] = 0;
280         }
281         strcpy(p, q+1);
282         tbuf = holdtbuf;
283         return(1);
284 }
285
286 /*
287  * Tnamatch deals with name matching.  The first field of the termcap
288  * entry is a sequence of names separated by |'s, so we compare
289  * against each such name.  The normal : terminator after the last
290  * name (before the first field) stops us.
291  */
292 tnamatch(np)
293         char *np;
294 {
295         register char *Np, *Bp;
296
297         Bp = tbuf;
298         if (*Bp == '#')
299                 return(0);
300         for (;;) {
301                 for (Np = np; *Np && *Bp == *Np; Bp++, Np++)
302                         continue;
303                 if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0))
304                         return (1);
305                 while (*Bp && *Bp != ':' && *Bp != '|')
306                         Bp++;
307                 if (*Bp == 0 || *Bp == ':')
308                         return (0);
309                 Bp++;
310         }
311 }
312
313 /*
314  * Skip to the next field.  Notice that this is very dumb, not
315  * knowing about \: escapes or any such.  If necessary, :'s can be put
316  * into the termcap file in octal.
317  */
318 static char *
319 tskip(bp)
320         register char *bp;
321 {
322
323         while (*bp && *bp != ':')
324                 bp++;
325         if (*bp == ':')
326                 bp++;
327         return (bp);
328 }
329
330 /*
331  * Return the (numeric) option id.
332  * Numeric options look like
333  *      li#80
334  * i.e. the option string is separated from the numeric value by
335  * a # character.  If the option is not found we return -1.
336  * Note that we handle octal numbers beginning with 0.
337  */
338 tgetnum(id)
339         char *id;
340 {
341         register int i, base;
342         register char *bp = tbuf;
343
344         for (;;) {
345                 bp = tskip(bp);
346                 if (*bp == 0)
347                         return (-1);
348                 if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
349                         continue;
350                 if (*bp == '@')
351                         return(-1);
352                 if (*bp != '#')
353                         continue;
354                 bp++;
355                 base = 10;
356                 if (*bp == '0')
357                         base = 8;
358                 i = 0;
359                 while (isdigit(*bp))
360                         i *= base, i += *bp++ - '0';
361                 return (i);
362         }
363 }
364
365 /*
366  * Handle a flag option.
367  * Flag options are given "naked", i.e. followed by a : or the end
368  * of the buffer.  Return 1 if we find the option, or 0 if it is
369  * not given.
370  */
371 tgetflag(id)
372         char *id;
373 {
374         register char *bp = tbuf;
375
376         for (;;) {
377                 bp = tskip(bp);
378                 if (!*bp)
379                         return (0);
380                 if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) {
381                         if (!*bp || *bp == ':')
382                                 return (1);
383                         else if (*bp == '@')
384                                 return(0);
385                 }
386         }
387 }
388
389 /*
390  * Get a string valued option.
391  * These are given as
392  *      cl=^Z
393  * Much decoding is done on the strings, and the strings are
394  * placed in area, which is a ref parameter which is updated.
395  * No checking on area overflow.
396  */
397 char *
398 tgetstr(id, area)
399         char *id, **area;
400 {
401         register char *bp = tbuf;
402
403         for (;;) {
404                 bp = tskip(bp);
405                 if (!*bp)
406                         return (0);
407                 if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
408                         continue;
409                 if (*bp == '@')
410                         return(0);
411                 if (*bp != '=')
412                         continue;
413                 bp++;
414                 return (tdecode(bp, area));
415         }
416 }
417
418 /*
419  * Tdecode does the grung work to decode the
420  * string capability escapes.
421  */
422 static char *
423 tdecode(str, area)
424         register char *str;
425         char **area;
426 {
427         register char *cp;
428         register int c;
429         register char *dp;
430         int i;
431
432         cp = *area;
433         while ((c = *str++) && c != ':') {
434                 switch (c) {
435
436                 case '^':
437                         c = *str++ & 037;
438                         break;
439
440                 case '\\':
441                         dp = "E\033^^\\\\::n\nr\rt\tb\bf\f";
442                         c = *str++;
443 nextc:
444                         if (*dp++ == c) {
445                                 c = *dp++;
446                                 break;
447                         }
448                         dp++;
449                         if (*dp)
450                                 goto nextc;
451                         if (isdigit(c)) {
452                                 c -= '0', i = 2;
453                                 do
454                                         c <<= 3, c |= *str++ - '0';
455                                 while (--i && isdigit(*str));
456                         }
457                         break;
458                 }
459                 *cp++ = c;
460         }
461         *cp++ = 0;
462         str = *area;
463         *area = cp;
464         return (str);
465 }
466
467 static char *
468 decodename(str, area)
469         register char *str;
470         char **area;
471 {
472         register char *cp;
473         register int c;
474         register char *dp;
475         int i;
476
477         cp = *area;
478         while ((c = *str++) && c != ':' && c != '|' ) {
479                 switch (c) {
480
481                 case '^':
482                         c = *str++ & 037;
483                         break;
484
485                 case '\\':
486                         dp = "E\033^^\\\\::n\nr\rt\tb\bf\f";
487                         c = *str++;
488 nextc:
489                         if (*dp++ == c) {
490                                 c = *dp++;
491                                 break;
492                         }
493                         dp++;
494                         if (*dp)
495                                 goto nextc;
496                         if (isdigit(c)) {
497                                 c -= '0', i = 2;
498                                 do
499                                         c <<= 3, c |= *str++ - '0';
500                                 while (--i && isdigit(*str));
501                         }
502                         break;
503                 }
504                 *cp++ = c;
505         }
506         *cp++ = 0;
507         str = *area;
508         *area = cp;
509         return (str);
510 }
511
512 char *
513 getpname( area )
514     char        **area;
515 {
516     return( decodename( tbuf, area ));
517 }