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

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