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