source: trunk/athena/bin/lpr/printcap.c @ 3564

Revision 3564, 10.2 KB checked in by epeisach, 34 years ago (diff)
Don't redefine BUFSIZ
Line 
1/*
2 * Copyright (c) 1983 Regents of the University of California.
3 * All rights reserved.  The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 */
6
7#ifndef lint
8static char sccsid[] = "@(#)printcap.c  5.1 (Berkeley) 6/6/85";
9#endif not lint
10
11#define MAXHOP  32      /* max number of tc= indirections */
12
13#include <ctype.h>
14#include <stdio.h>
15#ifdef HESIOD
16#include <hesiod.h>
17#include "lp.local.h"
18#endif
19#ifndef BUFSIZ
20#define BUFSIZ  1024
21#endif
22
23/*
24 * termcap - routines for dealing with the terminal capability data base
25 *
26 * BUG:         Should use a "last" pointer in tbuf, so that searching
27 *              for capabilities alphabetically would not be a n**2/2
28 *              process when large numbers of capabilities are given.
29 * Note:        If we add a last pointer now we will screw up the
30 *              tc capability. We really should compile termcap.
31 *
32 * Essentially all the work here is scanning and decoding escapes
33 * in string capabilities.  We don't use stdio because the editor
34 * doesn't, and because living w/o it is not hard.
35 *
36 * 4/13/87      Modified to use Hesiod name server iff HESIOD
37 * SDyer        is defined.  If no printer capability is found in the
38 * Athena       /etc/printcap file, Hesiod is queried for an alias for
39 *              the given printer name and its capability.  In looking
40 *              up the alias, Hesiod may also be queried for the host's
41 *              cluster name.
42 */
43
44#define PRINTCAP
45
46#ifdef PRINTCAP
47#define tgetent pgetent
48#define tskip   pskip
49#define tgetstr pgetstr
50#define tdecode pdecode
51#define tgetnum pgetnum
52#define tgetflag pgetflag
53#define tdecode pdecode
54#define tnchktc pnchktc
55#define tnamatch pnamatch
56#ifdef E_TERMCAP
57#undef E_TERMCAP
58#endif
59#define E_TERMCAP "/etc/printcap"
60#define V6
61#endif
62
63static  FILE *pfp = NULL;       /* printcap data base file pointer */
64static  char *tbuf;
65static  int hopcount;           /* detect infinite loops in termcap, init 0 */
66char    *tskip();
67char    *tgetstr();
68char    *tdecode();
69char    *getenv();
70
71#ifdef HESIOD
72/* Ask Hesiod if printer name is an alias.  If so,
73 * put new name in "name" and return 1.  If not, return 0.
74 * format:  -Pprinter[.cluster]
75 */
76
77int pralias(buf, name)
78        char buf[];             /* buffer to put printer alias in */
79        char *name;             /* name of printer to look up */
80{
81        char *e, temp[BUFSIZ/2];
82#ifdef OLD_DEFAULT_ALIAS
83        char **hv;
84#endif
85        char *getclus();
86       
87        strcpy(temp, name);
88        /* If printer name == "default" then lookup based on LPR cluster info*/
89        if(!strcmp(name, DEFLP)) {
90            if ((e = getclus()) != NULL) {
91                strcpy(buf, e);
92                return(1);
93            }
94        }
95
96#ifdef OLD_DEFAULT_ALIAS
97        /* if not in "printer.cluster" format, look up cluster and append */
98        if (index(name, '.') == NULL)
99                if ((e = getenv("LPR")) != NULL) {
100                        strcat(temp, ".");
101                        strcat(temp, e);
102                } else if ((e = getclus()) != NULL) {
103                        strcat(temp, ".");
104                        strcat(temp, e);
105                }
106        if ((hv = hes_resolve(temp, "lpralias")) != NULL &&
107            strlen(*hv) < BUFSIZ/2) {
108                strcpy(buf, *hv);
109                return(1);
110        }
111#endif
112        return (0);
113}
114
115/* Find this host's cluster name */
116char *
117getclus()
118{
119        static char cluster[BUFSIZ/2];
120        char host[32];
121        char **hv;
122        int len = 4;  /* length of string "lpr " */
123
124        gethostname(host, sizeof (host));
125        if ((hv = hes_resolve(host, "cluster")) == NULL)
126                return NULL;
127        while (*hv) {
128                if (strncmp(*hv, "lpr ", len) == NULL) {
129                        strcpy(cluster, *hv + len);
130                        return cluster;
131                        }
132                ++hv;
133        }
134        return NULL;
135}
136       
137/*
138 * Look for printer capability in Hesiod.
139 * If eventually found, copy into "line" and return 1, otherwise
140 * return 0.
141 */
142
143hpgetent(line, print)
144        char *line;
145        char *print;
146{
147        register char **hv;
148        char **hes_resolve();
149
150        tbuf = line;
151        if ( (hv = hes_resolve(print, "pcap")) != NULL) {
152                strcpy(line, *hv);
153                return(tnchktc());
154        }
155        return 0;
156}
157
158#endif HESIOD
159
160/*
161 * Similar to tgetent except it returns the next entry instead of
162 * doing a lookup.
163 */
164getprent(bp)
165        register char *bp;
166{
167        register int c, skip = 0;
168
169        if (pfp == NULL && (pfp = fopen(E_TERMCAP, "r")) == NULL)
170                return(-1);
171        tbuf = bp;
172        for (;;) {
173                switch (c = getc(pfp)) {
174                case EOF:
175                        fclose(pfp);
176                        pfp = NULL;
177                        return(0);
178                case '\n':
179                        if (bp == tbuf) {
180                                skip = 0;
181                                continue;
182                        }
183                        if (bp[-1] == '\\') {
184                                bp--;
185                                continue;
186                        }
187                        *bp = '\0';
188                        return(1);
189                case '#':
190                        if (bp == tbuf)
191                                skip++;
192                default:
193                        if (skip)
194                                continue;
195                        if (bp >= tbuf+BUFSIZ) {
196                                write(2, "Termcap entry too long\n", 23);
197                                *bp = '\0';
198                                return(1);
199                        }
200                        *bp++ = c;
201                }
202        }
203}
204
205endprent()
206{
207        if (pfp != NULL)
208                fclose(pfp);
209        pfp = NULL;
210}
211
212/*
213 * Get an entry for terminal name in buffer bp,
214 * from the termcap file.  Parse is very rudimentary;
215 * we just notice escaped newlines.
216 */
217
218tgetent(bp, name)
219        char *bp, *name;
220{
221        register char *cp;
222        register int c;
223        register int i = 0, cnt = 0;
224        char ibuf[BUFSIZ];
225#ifndef V6
226        char *cp2;
227#endif
228        int tf;
229
230        tbuf = bp;
231        tf = 0;
232#ifndef V6
233        cp = getenv("TERMCAP");
234        /*
235         * TERMCAP can have one of two things in it. It can be the
236         * name of a file to use instead of /etc/termcap. In this
237         * case it better start with a "/". Or it can be an entry to
238         * use so we don't have to read the file. In this case it
239         * has to already have the newlines crunched out.
240         */
241        if (cp && *cp) {
242                if (*cp!='/') {
243                        cp2 = getenv("TERM");
244                        if (cp2==(char *) 0 || strcmp(name,cp2)==0) {
245                                strcpy(bp,cp);
246                                return(tnchktc());
247                        } else {
248                                tf = open(E_TERMCAP, 0);
249                        }
250                } else
251                        tf = open(cp, 0);
252        }
253        if (tf==0)
254                tf = open(E_TERMCAP, 0);
255#else
256        tf = open(E_TERMCAP, 0);
257#endif
258        if (tf < 0)
259                return (-1);
260        for (;;) {
261                cp = bp;
262                for (;;) {
263                        if (i == cnt) {
264                                cnt = read(tf, ibuf, BUFSIZ);
265                                if (cnt <= 0) {
266                                        close(tf);
267                                        return (0);
268                                }
269                                i = 0;
270                        }
271                        c = ibuf[i++];
272                        if (c == '\n') {
273                                if (cp > bp && cp[-1] == '\\'){
274                                        cp--;
275                                        continue;
276                                }
277                                break;
278                        }
279                        if (cp >= bp+BUFSIZ) {
280                                write(2,"Termcap entry too long\n", 23);
281                                break;
282                        } else
283                                *cp++ = c;
284                }
285                *cp = 0;
286
287                /*
288                 * The real work for the match.
289                 */
290                if (tnamatch(name)) {
291                        close(tf);
292                        return(tnchktc());
293                }
294        }
295}
296
297/*
298 * tnchktc: check the last entry, see if it's tc=xxx. If so,
299 * recursively find xxx and append that entry (minus the names)
300 * to take the place of the tc=xxx entry. This allows termcap
301 * entries to say "like an HP2621 but doesn't turn on the labels".
302 * Note that this works because of the left to right scan.
303 */
304tnchktc()
305{
306        register char *p, *q;
307        char tcname[16];        /* name of similar terminal */
308        char tcbuf[BUFSIZ];
309        char *holdtbuf = tbuf;
310        int l;
311
312        p = tbuf + strlen(tbuf) - 2;    /* before the last colon */
313        while (*--p != ':')
314                if (p<tbuf) {
315                        write(2, "Bad termcap entry\n", 18);
316                        return (0);
317                }
318        p++;
319        /* p now points to beginning of last field */
320        if (p[0] != 't' || p[1] != 'c')
321                return(1);
322        strcpy(tcname,p+3);
323        q = tcname;
324        while (*q && *q != ':')/* was while (q && ... *//* SPD Athena 4/15/87 */
325                q++;
326        *q = 0;
327        if (++hopcount > MAXHOP) {
328                write(2, "Infinite tc= loop\n", 18);
329                return (0);
330        }
331#ifdef HESIOD
332        if (hpgetent(tcbuf, tcname) != 1)
333#else
334        if (tgetent(tcbuf, tcname) != 1)
335#endif
336                return(0);
337        for (q=tcbuf; *q != ':'; q++)
338                ;
339        l = p - holdtbuf + strlen(q);
340        if (l > BUFSIZ) {
341                write(2, "Termcap entry too long\n", 23);
342                q[BUFSIZ - (p-tbuf)] = 0;
343        }
344        strcpy(p, q+1);
345        tbuf = holdtbuf;
346        return(1);
347}
348
349/*
350 * Tnamatch deals with name matching.  The first field of the termcap
351 * entry is a sequence of names separated by |'s, so we compare
352 * against each such name.  The normal : terminator after the last
353 * name (before the first field) stops us.
354 */
355tnamatch(np)
356        char *np;
357{
358        register char *Np, *Bp;
359
360        Bp = tbuf;
361        if (*Bp == '#')
362                return(0);
363        for (;;) {
364                for (Np = np; *Np && *Bp == *Np; Bp++, Np++)
365                        continue;
366                if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0))
367                        return (1);
368                while (*Bp && *Bp != ':' && *Bp != '|')
369                        Bp++;
370                if (*Bp == 0 || *Bp == ':')
371                        return (0);
372                Bp++;
373        }
374}
375
376/*
377 * Skip to the next field.  Notice that this is very dumb, not
378 * knowing about \: escapes or any such.  If necessary, :'s can be put
379 * into the termcap file in octal.
380 */
381static char *
382tskip(bp)
383        register char *bp;
384{
385
386        while (*bp && *bp != ':')
387                bp++;
388        if (*bp == ':')
389                bp++;
390        return (bp);
391}
392
393/*
394 * Return the (numeric) option id.
395 * Numeric options look like
396 *      li#80
397 * i.e. the option string is separated from the numeric value by
398 * a # character.  If the option is not found we return -1.
399 * Note that we handle octal numbers beginning with 0.
400 */
401tgetnum(id)
402        char *id;
403{
404        register int i, base;
405        register char *bp = tbuf;
406
407        for (;;) {
408                bp = tskip(bp);
409                if (*bp == 0)
410                        return (-1);
411                if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
412                        continue;
413                if (*bp == '@')
414                        return(-1);
415                if (*bp != '#')
416                        continue;
417                bp++;
418                base = 10;
419                if (*bp == '0')
420                        base = 8;
421                i = 0;
422                while (isdigit(*bp))
423                        i *= base, i += *bp++ - '0';
424                return (i);
425        }
426}
427
428/*
429 * Handle a flag option.
430 * Flag options are given "naked", i.e. followed by a : or the end
431 * of the buffer.  Return 1 if we find the option, or 0 if it is
432 * not given.
433 */
434tgetflag(id)
435        char *id;
436{
437        register char *bp = tbuf;
438
439        for (;;) {
440                bp = tskip(bp);
441                if (!*bp)
442                        return (0);
443                if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) {
444                        if (!*bp || *bp == ':')
445                                return (1);
446                        else if (*bp == '@')
447                                return(0);
448                }
449        }
450}
451
452/*
453 * Get a string valued option.
454 * These are given as
455 *      cl=^Z
456 * Much decoding is done on the strings, and the strings are
457 * placed in area, which is a ref parameter which is updated.
458 * No checking on area overflow.
459 */
460char *
461tgetstr(id, area)
462        char *id, **area;
463{
464        register char *bp = tbuf;
465       
466        for (;;) {
467                bp = tskip(bp);
468                if (!*bp)
469                        return (0);
470                if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
471                        continue;
472                if (*bp == '@')
473                        return(0);
474                if (*bp != '=')
475                        continue;
476                bp++;
477                return (tdecode(bp, area));
478        }
479}
480
481/*
482 * Tdecode does the grung work to decode the
483 * string capability escapes.
484 */
485static char *
486tdecode(str, area)
487        register char *str;
488        char **area;
489{
490        register char *cp;
491        register int c;
492        register char *dp;
493        int i;
494
495        cp = *area;
496        while ((c = *str++) && c != ':') {
497                switch (c) {
498
499                case '^':
500                        c = *str++ & 037;
501                        break;
502
503                case '\\':
504                        dp = "E\033^^\\\\::n\nr\rt\tb\bf\f";
505                        c = *str++;
506nextc:
507                        if (*dp++ == c) {
508                                c = *dp++;
509                                break;
510                        }
511                        dp++;
512                        if (*dp)
513                                goto nextc;
514                        if (isdigit(c)) {
515                                c -= '0', i = 2;
516                                do
517                                        c <<= 3, c |= *str++ - '0';
518                                while (--i && isdigit(*str));
519                        }
520                        break;
521                }
522                *cp++ = c;
523        }
524        *cp++ = 0;
525        str = *area;
526        *area = cp;
527        return (str);
528}
Note: See TracBrowser for help on using the repository browser.