1*3678Sroot /* printcap.c 1.1 81/05/09 */ 2*3678Sroot /* Copyright (c) 1979 Regents of the University of California */ 3*3678Sroot #define BUFSIZ 512 4*3678Sroot 5*3678Sroot #include <ctype.h> 6*3678Sroot /* 7*3678Sroot * printcap - routines for dealing with the line printer capability data base 8*3678Sroot * 9*3678Sroot * BUG: Should use a "last" pointer in tbuf, so that searching 10*3678Sroot * for capabilities alphabetically would not be a n**2/2 11*3678Sroot * process when large numbers of capabilities are given. 12*3678Sroot * 13*3678Sroot * Essentially all the work here is scanning and decoding escapes 14*3678Sroot * in string capabilities. We don't use stdio because the editor 15*3678Sroot * doesn't, and because living w/o it is not hard. 16*3678Sroot */ 17*3678Sroot 18*3678Sroot static char *pbuf; 19*3678Sroot char *pskip(); 20*3678Sroot char *pgetstr(); 21*3678Sroot char *pdecode(); 22*3678Sroot 23*3678Sroot /* 24*3678Sroot * Get an entry for printer name in buffer bp, 25*3678Sroot * from the printcap file. Parse is very rudimentary; 26*3678Sroot * we just notice escaped newlines. 27*3678Sroot */ 28*3678Sroot pgetent(bp, name) 29*3678Sroot char *bp, *name; 30*3678Sroot { 31*3678Sroot register char *cp; 32*3678Sroot register int c; 33*3678Sroot register int i = 0, cnt = 0; 34*3678Sroot char ibuf[BUFSIZ]; 35*3678Sroot int tf; 36*3678Sroot 37*3678Sroot pbuf = bp; 38*3678Sroot tf = open("/etc/printcap", 0); 39*3678Sroot if (tf < 0) 40*3678Sroot return (-1); 41*3678Sroot for (;;) { 42*3678Sroot cp = bp; 43*3678Sroot for (;;) { 44*3678Sroot if (i == cnt) { 45*3678Sroot cnt = read(tf, ibuf, BUFSIZ); 46*3678Sroot if (cnt <= 0) { 47*3678Sroot close(tf); 48*3678Sroot return (0); 49*3678Sroot } 50*3678Sroot i = 0; 51*3678Sroot } 52*3678Sroot c = ibuf[i++]; 53*3678Sroot if (c == '\n') { 54*3678Sroot if (cp > bp && cp[-1] == '\\'){ 55*3678Sroot cp--; 56*3678Sroot continue; 57*3678Sroot } 58*3678Sroot break; 59*3678Sroot } 60*3678Sroot *cp++ = c; 61*3678Sroot } 62*3678Sroot *cp = 0; 63*3678Sroot 64*3678Sroot /* 65*3678Sroot * The real work for the match. 66*3678Sroot */ 67*3678Sroot if (pnamatch(name)) { 68*3678Sroot close(tf); 69*3678Sroot return (1); 70*3678Sroot } 71*3678Sroot } 72*3678Sroot } 73*3678Sroot 74*3678Sroot /* 75*3678Sroot * Tnamatch deals with name matching. The first field of the printcap 76*3678Sroot * entry is a sequence of names separated by |'s, so we compare 77*3678Sroot * against each such name. The normal : terminator after the last 78*3678Sroot * name (before the first field) stops us. 79*3678Sroot */ 80*3678Sroot pnamatch(np) 81*3678Sroot char *np; 82*3678Sroot { 83*3678Sroot register char *Np, *Bp; 84*3678Sroot 85*3678Sroot Bp = pbuf; 86*3678Sroot for (;;) { 87*3678Sroot for (Np = np; *Np && *Bp == *Np; Bp++, Np++) 88*3678Sroot continue; 89*3678Sroot if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0)) 90*3678Sroot return (1); 91*3678Sroot while (*Bp && *Bp != ':' && *Bp != '|') 92*3678Sroot Bp++; 93*3678Sroot if (*Bp == 0 || *Bp == ':') 94*3678Sroot return (0); 95*3678Sroot Bp++; 96*3678Sroot } 97*3678Sroot } 98*3678Sroot 99*3678Sroot /* 100*3678Sroot * Skip to the next field. Notice that this is very dumb, not 101*3678Sroot * knowing about \: escapes or any such. If necessary, :'s can be put 102*3678Sroot * into the printcap file in octal. 103*3678Sroot */ 104*3678Sroot static char * 105*3678Sroot pskip(bp) 106*3678Sroot register char *bp; 107*3678Sroot { 108*3678Sroot 109*3678Sroot while (*bp && *bp != ':') 110*3678Sroot bp++; 111*3678Sroot if (*bp == ':') 112*3678Sroot bp++; 113*3678Sroot return (bp); 114*3678Sroot } 115*3678Sroot 116*3678Sroot /* 117*3678Sroot * Return the (numeric) option id. 118*3678Sroot * Numeric options look like 119*3678Sroot * li#80 120*3678Sroot * i.e. the option string is separated from the numeric value by 121*3678Sroot * a # character. If the option is not found we return -1. 122*3678Sroot * Note that we handle octal numbers beginning with 0. 123*3678Sroot */ 124*3678Sroot pgetnum(id) 125*3678Sroot char *id; 126*3678Sroot { 127*3678Sroot register int i, base; 128*3678Sroot register char *bp = pbuf; 129*3678Sroot 130*3678Sroot for (;;) { 131*3678Sroot bp = pskip(bp); 132*3678Sroot if (*bp == 0) 133*3678Sroot return (-1); 134*3678Sroot if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1]) 135*3678Sroot continue; 136*3678Sroot if (*bp != '#') 137*3678Sroot continue; 138*3678Sroot bp++; 139*3678Sroot base = 10; 140*3678Sroot if (*bp == '0') 141*3678Sroot base = 8; 142*3678Sroot i = 0; 143*3678Sroot while (isdigit(*bp)) 144*3678Sroot i *= base, i += *bp++ - '0'; 145*3678Sroot return (i); 146*3678Sroot } 147*3678Sroot } 148*3678Sroot 149*3678Sroot /* 150*3678Sroot * Handle a flag option. 151*3678Sroot * Flag options are given "naked", i.e. followed by a : or the end 152*3678Sroot * of the buffer. Return 1 if we find the option, or 0 if it is 153*3678Sroot * not given. 154*3678Sroot */ 155*3678Sroot pgetflag(id) 156*3678Sroot char *id; 157*3678Sroot { 158*3678Sroot register char *bp = pbuf; 159*3678Sroot 160*3678Sroot for (;;) { 161*3678Sroot bp = pskip(bp); 162*3678Sroot if (!*bp) 163*3678Sroot return (0); 164*3678Sroot if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1] && (!*bp || *bp == ':')) 165*3678Sroot return (1); 166*3678Sroot } 167*3678Sroot } 168*3678Sroot 169*3678Sroot /* 170*3678Sroot * Get a string valued option. 171*3678Sroot * These are given as 172*3678Sroot * cl=^Z 173*3678Sroot * Much decoding is done on the strings, and the strings are 174*3678Sroot * placed in area, which is a ref parameter which is updated. 175*3678Sroot * No checking on area overflow. 176*3678Sroot */ 177*3678Sroot char * 178*3678Sroot pgetstr(id, area) 179*3678Sroot char *id, **area; 180*3678Sroot { 181*3678Sroot register char *bp = pbuf; 182*3678Sroot 183*3678Sroot for (;;) { 184*3678Sroot bp = pskip(bp); 185*3678Sroot if (!*bp) 186*3678Sroot return (0); 187*3678Sroot if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1]) 188*3678Sroot continue; 189*3678Sroot if (*bp != '=') 190*3678Sroot continue; 191*3678Sroot bp++; 192*3678Sroot return (pdecode(bp, area)); 193*3678Sroot } 194*3678Sroot } 195*3678Sroot 196*3678Sroot /* 197*3678Sroot * Tdecode does the grung work to decode the 198*3678Sroot * string capability escapes. 199*3678Sroot */ 200*3678Sroot static char * 201*3678Sroot pdecode(str, area) 202*3678Sroot register char *str; 203*3678Sroot char **area; 204*3678Sroot { 205*3678Sroot register char *cp; 206*3678Sroot register int c; 207*3678Sroot register char *dp; 208*3678Sroot int i; 209*3678Sroot 210*3678Sroot cp = *area; 211*3678Sroot while ((c = *str++) && c != ':') { 212*3678Sroot switch (c) { 213*3678Sroot 214*3678Sroot case '^': 215*3678Sroot c = *str++ & 037; 216*3678Sroot break; 217*3678Sroot 218*3678Sroot case '\\': 219*3678Sroot dp = "E\033^^\\\\::n\nr\rt\tb\bf\f"; 220*3678Sroot c = *str++; 221*3678Sroot nextc: 222*3678Sroot if (*dp++ == c) { 223*3678Sroot c = *dp++; 224*3678Sroot break; 225*3678Sroot } 226*3678Sroot dp++; 227*3678Sroot if (*dp) 228*3678Sroot goto nextc; 229*3678Sroot if (isdigit(c)) { 230*3678Sroot c -= '0', i = 2; 231*3678Sroot do 232*3678Sroot c <<= 3, c |= *str++ - '0'; 233*3678Sroot while (--i && isdigit(*str)); 234*3678Sroot } 235*3678Sroot break; 236*3678Sroot } 237*3678Sroot *cp++ = c; 238*3678Sroot } 239*3678Sroot *cp++ = 0; 240*3678Sroot str = *area; 241*3678Sroot *area = cp; 242*3678Sroot return (str); 243*3678Sroot } 244