1: /*\ 2: * 3: * ulf -- Universal Lineprinter Filter 4: * Written by Cliff Matthews, on April 7th, 1983 at the 5: * University of New Mexico 6: * 7: * Supports: diablo and dumb (LA180, LA120) "lineprinters" 8: * 9: * This program uses a "line_structure" that is a linked list of arrays to 10: * hold enough characters for one physical line on the lineprinter. The 11: * first array contains the characters of the line, and all subsequent arrays 12: * hold overprinting characters. Blanks are left as zero's, so that they 13: * don't have to be printed, just move the printhead whatever way is easiest. 14: * 15: \*/ 16: 17: #include <stdio.h> 18: #include <ctype.h> 19: #include <errno.h> 20: #include <sgtty.h> 21: #include "lp.local.h" 22: 23: #define CONTROL 20 /* How many tolerable control characters */ 24: #define RPRINT "\0336" /* Make diablo print backword esc 6 */ 25: #define FPRINT "\0335" /* Make diablo print forward esc 5 */ 26: #define FORWARD 1 /* directions for diablo */ 27: #define BACKWARD 0 /* directions for diablo */ 28: 29: struct line_s { 30: char *line; 31: struct line_s *next; 32: }; 33: 34: char *malloc(); 35: char *rindex(); 36: char *pgetstr(); 37: struct line_s *makeline(); 38: 39: short BR; /* baud rate if lp is a tty */ 40: int FC; /* flags to clear if lp is a tty */ 41: int FS; /* flags to set if lp is a tty */ 42: int XC; /* flags to clear for local mode */ 43: int XS; /* flags to set for local mode */ 44: 45: char *lpac; /* where the lineprinter accounting is kept */ 46: char *invoke; /* name this filter was invoked as */ 47: char *user; /* name the user that this should be billed to */ 48: char *ff; /* what to use for a form feed */ 49: int linelen; /* length of a line for current line_printer */ 50: int pagesize; /* number of lines on a page */ 51: int manual; /* paper must be fed by hand */ 52: int printhead; /* location of the printhead */ 53: int diablo; /* are we a diablo or not */ 54: int linenum; /* number of lines printed so far on this page */ 55: unsigned pages; /* number of pages printed */ 56: int direction; /* 1 means we are printing forward */ 57: static int eatme = 0; /* set when disposing of bad output */ 58: 59: main(argc,argv) 60: int argc; 61: char *argv[]; 62: { 63: 64: char c; /* last character read */ 65: struct line_s *linepointer; /* chars to print later */ 66: int loc; /* current printing location */ 67: 68: init(argv); 69: linepointer = makeline(); 70: 71: while ( (c = getchar()) != EOF ) { 72: if (!eatme) 73: switch (c) { 74: case ' ': /* Space */ 75: loc++; 76: break; 77: 78: case '\b': /* Backspace */ 79: loc--; 80: break; 81: 82: case '\t': /* Tab */ 83: loc += 8 - (loc % 8); 84: break; 85: 86: case '\n': /* New Line */ 87: dumplines( linepointer ); 88: loc = 0; 89: break; 90: 91: case '\r': /* Carriage Return */ 92: loc = 0; 93: break; 94: 95: case '\f': /* Form Feed */ 96: dumplines( linepointer ); 97: loc = 0; 98: throwpage(); 99: break; 100: 101: default: 102: c &= 0177; /* Turn off parity */ 103: if ( !isprint( c ) ) 104: tossout(); /* Not Printable */ 105: else 106: if (( loc >= 0) && ( loc <= linelen - 1)) 107: place( c, loc++, linepointer ); 108: else 109: loc++; /* off page */ 110: } 111: } 112: bill(user); 113: } 114: 115: static struct bauds { 116: int baud; 117: int speed; 118: } bauds[] = { 119: 50, B50, 120: 75, B75, 121: 110, B110, 122: 134, B134, 123: 150, B150, 124: 200, B200, 125: 300, B300, 126: 600, B600, 127: 1200, B1200, 128: 1800, B1800, 129: 2400, B2400, 130: 4800, B4800, 131: 9600, B9600, 132: 19200, EXTA, 133: 38400, EXTB, 134: 0, 0 135: }; 136: 137: init(argv) /* initialize global variables */ 138: char *argv[]; 139: { 140: static char buf[BUFSIZ/2]; /* Stolen from lpr.c */ 141: char b[BUFSIZ]; /* Stolen from lpr.c */ 142: int stat; /* Stolen from lpr.c */ 143: char *bp = buf; /* Stolen from lpr.c */ 144: char *cp; /* scratch character pointer */ 145: int i; /* scratch index */ 146: register struct bauds *baudp; 147: static struct sgttyb sbuf; 148: 149: printhead = 0; 150: linenum = 0; 151: pages = 1; 152: invoke = ((cp = rindex(*argv,'/')) ? cp + 1 : *argv); 153: user = argv[1]; 154: 155: if (strncmp("diablo",invoke,sizeof("diablo")-sizeof(char)) == 0) 156: diablo = 1; 157: else 158: diablo = 0; 159: 160: if ((stat = pgetent(b, invoke)) <= 0) { 161: printf("%s: can't find printer description\n",invoke); 162: exit(3); 163: } else { 164: if ((linelen = pgetnum("pw", &bp)) == NULL) 165: linelen = DEFLINELEN; 166: if ((pagesize = pgetnum("pl", &bp)) == NULL) 167: pagesize = DEFPAGESIZE; 168: BR = pgetnum("br", &bp); 169: if ((lpac = pgetstr("af", &bp)) == NULL) 170: lpac = DEFACCOUNTFILE; 171: if ((ff = pgetstr("ff", &bp)) == NULL) 172: ff = "\f"; 173: if ((FC = pgetnum("fc")) < 0) 174: FC = 0; 175: if ((FS = pgetnum("fs")) < 0) 176: FS = 0; 177: if ((XC = pgetnum("xc")) < 0) 178: XC = 0; 179: if ((XS = pgetnum("xs")) < 0) 180: XS = 0; 181: if ((LF = pgetstr("lf", &bp)) == NULL) 182: LF = DEFLOGF; 183: } 184: 185: if (ioctl(fileno(stdout), TIOCEXCL, (char *)0) < 0) { 186: log("cannot set exclusive-use"); 187: exit(1); 188: } 189: if (ioctl(fileno(stdout), TIOCGETP, (char *) &sbuf) < 0) { 190: log("cannot get tty parameters"); 191: exit(1); 192: } 193: 194: if (BR) { 195: for (baudp = bauds; baudp->baud; baudp++) 196: if (BR == baudp->baud) 197: break; 198: if (!baudp->baud) { 199: log("illegal baud rate %d", BR); 200: exit(1); 201: } 202: sbuf.sg_ispeed = sbuf.sg_ospeed = baudp->speed; 203: } 204: sbuf.sg_flags &= ~FC; 205: sbuf.sg_flags |= FS; 206: if (ioctl(fileno(stdout), TIOCSETP, (char *)&sbuf) < 0) { 207: log("cannot set tty parameters"); 208: exit(1); 209: } 210: if (XC) { 211: if (ioctl(fileno(stdout), TIOCLBIC, (char *) &XC) < 0) { 212: log("cannot set local tty parameters"); 213: exit(1); 214: } 215: } 216: if (XS) { 217: if (ioctl(fileno(stdout), TIOCLBIS, (char *) &XS) < 0) { 218: log("cannot set local tty parameters"); 219: exit(1); 220: } 221: } 222: 223: putchar ('\r'); 224: direction = FORWARD; 225: } 226: 227: struct line_s * 228: makeline() /* malloc up some memory for a line_structure */ 229: { 230: struct line_s *s; /* memory allocated for the new line */ 231: char *cp; /* scratch char pointer */ 232: char *end; /* last legal array position for while loop */ 233: 234: s = (struct line_s *) malloc(sizeof(struct line_s)); 235: if ( s == 0 ) 236: outofmemory(); 237: else { 238: s->next = NULL; 239: cp = s->line = malloc(linelen + 1); 240: if ( s->line == 0) 241: outofmemory(); 242: else { 243: end = s->line + linelen; 244: while ( cp < end ) 245: *cp++ = ' '; 246: *cp = 0; 247: } 248: } 249: return (s); 250: } 251: 252: tossout() /* toss out invalid characters, and keep count, maybe puke */ 253: { 254: 255: static int tossed = 0; /* how many characters have been discarded */ 256: 257: if (++tossed > CONTROL) { 258: if (diablo) 259: spaceto(0,FORWARD); 260: printf("\r\n\n\n\n\n\n"); 261: printf("%s: *************************************\r\n",invoke); 262: printf("%s: *************************************\r\n",invoke); 263: printf("%s: *************************************\r\n",invoke); 264: printf("%s: Too many control characters in output\r\n",invoke); 265: printf("%s: *************************************\r\n",invoke); 266: printf("%s: *************************************\r\n",invoke); 267: printf("%s: *************************************\r\n",invoke); 268: eatme = 1; 269: } 270: } 271: 272: place(c, location, p) /* add a new character to a line_structure */ 273: char c; /* character to place */ 274: struct line_s *p; /* structure to put character in */ 275: int location; /* where in the line the character should go */ 276: { 277: char *cp; 278: 279: if (*(cp = (p->line + location)) != ' ') { 280: if (p->next == NULL) 281: p->next = makeline(); 282: place(c, location, p->next); 283: } else 284: *cp = c; 285: } 286: 287: dumplines(p) /* dump the top-level line_structure */ 288: struct line_s *p; 289: { 290: char *cp, *end; /* scratch, and last legit array element */ 291: 292: if (p->next != NULL) 293: rdumpl(p->next); 294: qprint(p->line); 295: printf("\n"); 296: 297: linenum++; 298: if (linenum == pagesize) { 299: pages++; 300: linenum = 0; 301: } 302: 303: cp = p->line; 304: end = cp + linelen; 305: while ( cp < end ) 306: *cp++ = ' '; 307: 308: p->next = NULL; 309: } 310: 311: 312: rdumpl(p) /* recursively dump the overprints */ 313: struct line_s *p; 314: { 315: if (p->next != NULL) 316: rdumpl(p->next); 317: qprint(p->line); 318: free(p->line); 319: free(p); 320: } 321: 322: outofmemory() 323: { 324: printf("%s: Out of Memory\n",invoke); 325: exit(ENOMEM); 326: } 327: 328: qprint(line) /* print a line efficiently */ 329: char *line; 330: { 331: char *cp; /* scratch character pointer */ 332: char *end; /* last legitimate array position */ 333: int r,l; /* right most character, leftmost */ 334: int i,j; /* temporary values */ 335: 336: cp = line + linelen - 1; 337: while ( cp >= line && *cp == ' ') 338: --cp; 339: 340: if ( cp < line ) 341: return; 342: 343: if (diablo) { 344: r = cp - line; 345: end = line + linelen; 346: cp = line; 347: while ( *cp++ == ' ' ); 348: l = cp - line - 1; 349: i = abs(printhead - l) + (2 * ((direction == FORWARD) ? 1 : -1)); 350: j = abs(printhead - r); 351: if ( (printhead < l) || (i < j) ) { 352: spaceto(l,FORWARD); 353: pr(line,l,r); 354: } else { 355: spaceto(r,BACKWARD); 356: pr(line,r,l); 357: } 358: 359: } else { 360: *++cp = '\0'; 361: printf("%s\r", line); 362: } 363: } 364: 365: spaceto( where, dir) 366: int where; /* which column */ 367: int dir; /* which way to go afterward */ 368: { 369: if (where == 0) { 370: putchar('\r'); 371: direction = FORWARD; /* where else should we go */ 372: } else { 373: if ( direction != dir ) { 374: printf("%s", ( dir == FORWARD ) ? FPRINT : RPRINT ); 375: direction = dir; 376: } 377: if (printhead != where) { 378: putchar('\033'); /* <esc><tab># gets you to # */ 379: putchar('\t'); 380: putchar((char)where+1); 381: } 382: } 383: printhead = where; 384: } 385: 386: pr(line,start,stop) /* prints the characters from start to stop */ 387: int start; /* array index of first character */ 388: int stop; /* array index of last character */ 389: char *line; /* line to play with */ 390: { 391: char *end; /* last character location to access */ 392: char *cp; /* scratch character position */ 393: 394: end = line + stop; 395: cp = line + start; 396: if (start < stop) { 397: while ( cp <= end ) 398: putchar( *cp++ ); 399: printhead = stop+1; 400: } else { 401: while ( cp >= end ) 402: putchar( *cp-- ); 403: if ( printhead < 0 ) 404: printhead = 0; 405: printhead = stop-1; 406: } 407: } 408: 409: throwpage() /* toss a page */ 410: { 411: register int x; 412: 413: printf("%s",ff); 414: pages++; 415: 416: linenum = 0; 417: } 418: 419: bill(account) 420: char *account; 421: { 422: FILE *fopen(), *ac; 423: 424: if ((ac = fopen(lpac,"a")) != NULL) { 425: fprintf(ac,"%s\t%u\n",account,pages); 426: fclose(ac); 427: } 428: } 429: 430: /*VARARGS1*/ 431: log(message, a1, a2, a3) 432: char *message; 433: { 434: short console; 435: FILE *lfd; 436: lfd = fopen(lf,"a"); 437: console = isatty(fileno(lfd)); 438: 439: fprintf(lfd, console ? "\r\n%s: " : "%s: ", invoke); 440: fprintf(lfd, message, a1, a2, a3); 441: if (console) 442: putc('\r', lfd); 443: putc('\n', lfd); 444: fclose(lfd); 445: }