|
|
1.1 ! root 1: #include <stdio.h> ! 2: /* ! 3: * PR command (print files in pages and columns, with headings) ! 4: * 2+head+2+page[56]+5 ! 5: */ ! 6: ! 7: #define ESC '\033' ! 8: #define LENGTH 66 ! 9: #define LINEW 72 ! 10: #define NUMW 5 ! 11: #define MARGIN 10 ! 12: #define DEFTAB 8 ! 13: ! 14: FILE *fopen(), *mustopen(); ! 15: char nulls[] = ""; ! 16: typedef struct { FILE *f_f; char *f_name; int f_nextc; } FILS; ! 17: FILS *Files; ! 18: int Multi = 0, Nfiles = 0, Error = 0, Balance = 0, onintr(); ! 19: ! 20: #include <signal.h> ! 21: #include <ctype.h> ! 22: #include <sys/types.h> ! 23: #include <sys/stat.h> ! 24: typedef char CHAR; ! 25: typedef int ANY; ! 26: typedef unsigned UNS; ! 27: #define NFILES 10 ! 28: int Mode; ! 29: char *ttyname(), *Ttyout, obuf[BUFSIZ]; ! 30: #define istty(F) ttyname(fileno(F)) ! 31: /* ARGSUSED */ ! 32: fixtty(argc, argv) char **argv; ! 33: { ! 34: struct stat sbuf; ! 35: ! 36: setbuf(stdout, obuf); ! 37: if (signal(SIGINT, SIG_IGN) != SIG_IGN) signal(SIGINT, onintr); ! 38: if (Ttyout= istty(stdout)) { ! 39: stat(Ttyout, &sbuf); ! 40: Mode = sbuf.st_mode&0777; ! 41: chmod(Ttyout, 0600); ! 42: } ! 43: return (argc); ! 44: } ! 45: ! 46: #define done() if (Ttyout) chmod(Ttyout, Mode) ! 47: #define INTREXIT _exit ! 48: char *GETDATE() /* return date file was last modified */ ! 49: { ! 50: char *ctime(); ! 51: static char *now = NULL; ! 52: static struct stat sbuf, nbuf; ! 53: ! 54: if (Nfiles > 1 || Files->f_name == nulls) { ! 55: if (now == NULL) ! 56: { time(&nbuf.st_mtime); now = ctime(&nbuf.st_mtime); } ! 57: return (now); ! 58: } else { ! 59: stat(Files->f_name, &sbuf); ! 60: return (ctime(&sbuf.st_mtime)); ! 61: } ! 62: } ! 63: ! 64: #define CADDID() ! 65: #define HEAD "%12.12s %4.4s %s Page %d\n\n\n", date+4, date+20, head, Page ! 66: #define TOLOWER(c) (isupper(c) ? tolower(c) : c) /* ouch! */ ! 67: #define cerror(S) fprintf(stderr, "pr: %s", S) ! 68: ! 69: char *ffiler(s) char *s; ! 70: { ! 71: static char buf[100]; ! 72: ! 73: sprintf(buf, "can't open %s", s); ! 74: return (buf); ! 75: } ! 76: ! 77: #define STDINNAME() nulls ! 78: #define TTY "/dev/tty", "r" ! 79: #define PROMPT() putc('\7', stderr) /* BEL */ ! 80: #define TABS(N,C) if ((N = intopt(argv, &C)) < 0) N = DEFTAB ! 81: #define INSTABS() if (Itabn == 0 && Ttyout) Itabn = DEFTAB ! 82: #define ETABS (Inpos % Etabn) ! 83: #define ITABS (Itabn > 0 && Nspace >= (nc = Itabn - Outpos % Itabn)) ! 84: #define NSEPC '\t' ! 85: ! 86: ANY *getspace(); ! 87: ! 88: main(argc, argv) char *argv[]; ! 89: { ! 90: FILS fstr[NFILES]; ! 91: int nfdone = 0; ! 92: ! 93: Files = fstr; ! 94: for (argc = findopt(argc, argv); argc > 0; --argc, ++argv) ! 95: if (Multi == 'm') { ! 96: if (Nfiles >= NFILES - 1) die("too many files"); ! 97: if (mustopen(*argv, &Files[Nfiles++]) == NULL) ! 98: ++nfdone; /* suppress printing */ ! 99: } else { ! 100: if (print(*argv)) ! 101: fclose(Files->f_f); ! 102: ++nfdone; ! 103: } ! 104: if (!nfdone) /* no files named, use stdin */ ! 105: print(nulls); /* on GCOS, use current file, if any */ ! 106: errprint(); /* print accumulated error reports */ ! 107: exit(Error); ! 108: } ! 109: ! 110: ! 111: long Lnumb = 0; ! 112: FILE *Ttyin = stdin; ! 113: int Dblspace = 1, Fpage = 1, Formfeed = 0, ! 114: Length = LENGTH, Linew = 0, Offset = 0, Ncols = 1, Pause = 0, Sepc = 0, ! 115: Colw, Plength, Margin = MARGIN, Numw, Nsepc = NSEPC, Report = 1, ! 116: Etabn = 0, Etabc = '\t', Itabn = 0, Itabc = '\t'; ! 117: char *Head = NULL; ! 118: CHAR *Buffer = NULL, *Bufend; ! 119: typedef struct { CHAR *c_ptr, *c_ptr0; long c_lno; } *COLP; ! 120: COLP Colpts; ! 121: ! 122: findopt(argc, argv) char *argv[]; ! 123: { ! 124: char **eargv = argv; ! 125: int eargc = 0, c; ! 126: ! 127: argc = fixtty(argc, argv); ! 128: while (--argc > 0) { ! 129: switch (c = **++argv) { ! 130: case '-': ! 131: if ((c = *++*argv) == '\0') break; ! 132: case '+': ! 133: do { ! 134: if (isdigit(c)) ! 135: { --*argv; Ncols = atoix(argv); } ! 136: else switch (c = TOLOWER(c)) { ! 137: case '+': if ((Fpage = atoix(argv)) < 1) ! 138: Fpage = 1; ! 139: continue; ! 140: case 'd': Dblspace = 2; continue; ! 141: case 'e': TABS(Etabn, Etabc); continue; ! 142: case 'f': ++Formfeed; continue; ! 143: case 'h': if (--argc > 0) Head = argv[1]; ! 144: continue; ! 145: case 'i': TABS(Itabn, Itabc); continue; ! 146: case 'l': Length = atoix(argv); continue; ! 147: case 'a': ! 148: case 'm': Multi = c; continue; ! 149: case 'o': Offset = atoix(argv); continue; ! 150: case 'p': ++Pause; continue; ! 151: case 'r': Report = 0; continue; ! 152: case 's': ! 153: if ((Sepc = (*argv)[1]) != '\0') ++*argv; ! 154: else Sepc = '\t'; ! 155: continue; ! 156: case 't': Margin = 0; continue; ! 157: case 'w': Linew = atoix(argv); continue; ! 158: case 'n': ! 159: case 'x': /* retained for historical reasons */ ! 160: ++Lnumb; ! 161: if ((Numw = intopt(argv, &Nsepc)) <= 0) ! 162: Numw = NUMW; ! 163: case 'b': Balance = 1; continue; ! 164: case 'q': /* retained for historical reasons */ ! 165: case 'j': /* ignore GCOS jprint option */ ! 166: continue; ! 167: default : die("bad option"); ! 168: } ! 169: } while ((c = *++*argv) != '\0'); ! 170: if (Head == argv[1]) ++argv; ! 171: continue; ! 172: } ! 173: *eargv++ = *argv; ! 174: ++eargc; ! 175: } ! 176: if (Length == 0) Length = LENGTH; ! 177: if (Length <= Margin) Margin = 0; ! 178: Plength = Length - Margin/2; ! 179: if (Multi == 'm') Ncols = eargc; ! 180: switch (Ncols) { ! 181: case 0: ! 182: Ncols = 1; ! 183: case 1: ! 184: break; ! 185: default: ! 186: if (Etabn == 0) /* respect explicit tab specification */ ! 187: Etabn = DEFTAB; ! 188: INSTABS(); ! 189: } ! 190: if (Linew == 0) Linew = Ncols != 1 && Sepc == 0 ? LINEW : 512; ! 191: if (Lnumb) Linew -= Multi == 'm' ? Numw : Numw * Ncols; ! 192: if ((Colw = (Linew - Ncols + 1)/Ncols) < 1) ! 193: die("width too small"); ! 194: if (Ncols != 1 && Multi == 0) { ! 195: UNS buflen = ((UNS)(Plength/Dblspace + 1))*(Linew+1)*sizeof(CHAR); ! 196: Buffer = (CHAR *)getspace(buflen); ! 197: Bufend = &Buffer[buflen]; ! 198: Colpts = (COLP)getspace((UNS)((Ncols+1)*sizeof(*Colpts))); ! 199: } ! 200: if (Ttyout && (Pause || Formfeed) && !istty(stdin)) ! 201: Ttyin = fopen(TTY); ! 202: return (eargc); ! 203: } ! 204: ! 205: intopt(argv, optp) char *argv[]; int *optp; ! 206: { ! 207: int c; ! 208: ! 209: if ((c = (*argv)[1]) != '\0' && !isdigit(c)) { *optp = c; ++*argv; } ! 210: return ((c = atoix(argv)) != 0 ? c : -1); ! 211: } ! 212: ! 213: int Page, C = '\0', Nspace, Inpos; ! 214: ! 215: print(name) char *name; ! 216: { ! 217: static int notfirst = 0; ! 218: char *date = NULL, *head = NULL; ! 219: int c; ! 220: ! 221: if (Multi != 'm' && mustopen(name, &Files[0]) == NULL) return (0); ! 222: if (Buffer) ungetc(Files->f_nextc, Files->f_f); ! 223: if (Lnumb) Lnumb = 1; ! 224: for (Page = 0; ; putpage()) { ! 225: if (C == EOF) break; ! 226: if (Buffer) nexbuf(); ! 227: Inpos = 0; ! 228: if (get(0) == EOF) break; ! 229: fflush(stdout); ! 230: if (++Page >= Fpage) { ! 231: if (Ttyout && (Pause || Formfeed && !notfirst++)) { ! 232: PROMPT(); /* prompt with bell and pause */ ! 233: while ((c = getc(Ttyin)) != EOF && c != '\n') ; ! 234: } ! 235: if (Margin == 0) continue; ! 236: CADDID(); ! 237: if (date == NULL) date = GETDATE(); ! 238: if (head == NULL) head = Head != NULL ? Head : ! 239: Nfiles < 2 ? Files->f_name : nulls; ! 240: printf("\n\n"); ! 241: Nspace = Offset; ! 242: putspace(); ! 243: printf(HEAD); ! 244: } ! 245: } ! 246: C = '\0'; ! 247: return (1); ! 248: } ! 249: ! 250: int Outpos, Lcolpos, Pcolpos, Line; ! 251: ! 252: putpage() ! 253: { ! 254: register int colno; ! 255: ! 256: for (Line = Margin/2; ; get(0)) { ! 257: for (Nspace = Offset, colno = 0, Outpos = 0; C != '\f'; ) { ! 258: if (Lnumb && C != EOF && (colno == 0 || Multi == 'a')) { ! 259: if (Page >= Fpage) { ! 260: putspace(); ! 261: printf("%*ld", Numw, Buffer ? ! 262: Colpts[colno].c_lno++ : Lnumb); ! 263: Outpos += Numw; ! 264: put(Nsepc); ! 265: } ! 266: ++Lnumb; ! 267: } ! 268: for (Lcolpos = 0, Pcolpos = 0; ! 269: C != '\n' && C != '\f' && C != EOF; get(colno)) ! 270: put(C); ! 271: if (C == EOF || ++colno == Ncols || ! 272: C == '\n' && get(colno) == EOF) break; ! 273: if (Sepc) put(Sepc); ! 274: else if ((Nspace += Colw - Lcolpos + 1) < 1) Nspace = 1; ! 275: } ! 276: /* ! 277: if (C == EOF) { ! 278: if (Margin != 0) break; ! 279: if (colno != 0) put('\n'); ! 280: return; ! 281: } ! 282: */ ! 283: if (C == EOF && colno == 0) { ! 284: if (Margin != 0) break; ! 285: return; ! 286: } ! 287: if (C == '\f') break; ! 288: put('\n'); ! 289: if (Dblspace == 2 && Line < Plength) put('\n'); ! 290: if (Line >= Plength) break; ! 291: } ! 292: if (Formfeed) put('\f'); ! 293: else while (Line < Length) put('\n'); ! 294: } ! 295: ! 296: nexbuf() ! 297: { ! 298: register CHAR *s = Buffer; ! 299: register COLP p = Colpts; ! 300: int j, c, bline = 0; ! 301: ! 302: for ( ; ; ) { ! 303: p->c_ptr0 = p->c_ptr = s; ! 304: if (p == &Colpts[Ncols]) return; ! 305: (p++)->c_lno = Lnumb + bline; ! 306: for (j = (Length - Margin)/Dblspace; --j >= 0; ++bline) ! 307: for (Inpos = 0; ; ) { ! 308: if ((c = getc(Files->f_f)) == EOF) { ! 309: for (*s = EOF; p <= &Colpts[Ncols]; ++p) ! 310: p->c_ptr0 = p->c_ptr = s; ! 311: if (Balance) ! 312: balance(bline); ! 313: return; ! 314: } ! 315: if (isprint(c)) ++Inpos; ! 316: if (Inpos <= Colw || c == '\n') { ! 317: *s = c; ! 318: if (++s >= Bufend) ! 319: die("page-buffer overflow"); ! 320: } ! 321: if (c == '\n') break; ! 322: switch (c) { ! 323: case '\b': if (Inpos == 0) --s; ! 324: case ESC: if (Inpos > 0) --Inpos; ! 325: } ! 326: } ! 327: } ! 328: } ! 329: ! 330: balance(bline) /* line balancing for last page */ ! 331: { ! 332: register CHAR *s = Buffer; ! 333: register COLP p = Colpts; ! 334: int colno = 0, j, c, l; ! 335: ! 336: c = bline % Ncols; ! 337: l = (bline + Ncols - 1)/Ncols; ! 338: bline = 0; ! 339: do { ! 340: for (j = 0; j < l; ++j) ! 341: while (*s++ != '\n') ; ! 342: (++p)->c_lno = Lnumb + (bline += l); ! 343: p->c_ptr0 = p->c_ptr = s; ! 344: if (++colno == c) --l; ! 345: } while (colno < Ncols - 1); ! 346: } ! 347: ! 348: get(colno) ! 349: { ! 350: static int peekc = 0; ! 351: register COLP p; ! 352: register FILS *q; ! 353: register int c; ! 354: ! 355: if (peekc) ! 356: { peekc = 0; c = Etabc; } ! 357: else if (Buffer) { ! 358: p = &Colpts[colno]; ! 359: if (p->c_ptr >= (p+1)->c_ptr0) c = EOF; ! 360: else if ((c = *p->c_ptr) != EOF) ++p->c_ptr; ! 361: } else if ((c = ! 362: (q = &Files[Multi == 'a' ? 0 : colno])->f_nextc) == EOF) { ! 363: for (q = &Files[Nfiles]; --q >= Files && q->f_nextc == EOF; ) ; ! 364: if (q >= Files) c = '\n'; ! 365: } else ! 366: q->f_nextc = getc(q->f_f); ! 367: if (Etabn != 0 && c == Etabc) { ! 368: ++Inpos; ! 369: peekc = ETABS; ! 370: c = ' '; ! 371: } else if (isprint(c)) ! 372: ++Inpos; ! 373: else ! 374: switch (c) { ! 375: case '\b': ! 376: case ESC: ! 377: if (Inpos > 0) --Inpos; ! 378: break; ! 379: case '\f': ! 380: if (Ncols == 1) break; ! 381: c = '\n'; ! 382: case '\n': ! 383: case '\r': ! 384: Inpos = 0; ! 385: } ! 386: return (C = c); ! 387: } ! 388: ! 389: put(c) ! 390: { ! 391: int move; ! 392: ! 393: switch (c) { ! 394: case ' ': ! 395: ++Nspace; ++Lcolpos; return; ! 396: case '\b': ! 397: if (Lcolpos == 0) return; ! 398: if (Nspace > 0) { --Nspace; --Lcolpos; return; } ! 399: if (Lcolpos > Pcolpos) { --Lcolpos; return; } ! 400: case ESC: ! 401: move = -1; ! 402: break; ! 403: case '\n': ! 404: ++Line; ! 405: case '\r': ! 406: case '\f': ! 407: Pcolpos = 0; Lcolpos = 0; Nspace = 0; Outpos = 0; ! 408: default: ! 409: move = (isprint(c) != 0); ! 410: } ! 411: if (Page < Fpage) return; ! 412: if (Lcolpos > 0 || move > 0) Lcolpos += move; ! 413: if (Lcolpos <= Colw) { ! 414: putspace(); ! 415: putchar(c); ! 416: Pcolpos = Lcolpos; ! 417: Outpos += move; ! 418: } ! 419: } ! 420: ! 421: putspace() ! 422: { ! 423: int nc; ! 424: ! 425: for ( ; Nspace > 0; Outpos += nc, Nspace -= nc) ! 426: if (ITABS) ! 427: putchar(Itabc); ! 428: else { ! 429: nc = 1; ! 430: putchar(' '); ! 431: } ! 432: } ! 433: ! 434: atoix(p) register char **p; ! 435: { ! 436: register int n = 0, c; ! 437: ! 438: while (isdigit(c = *++*p)) n = 10*n + c - '0'; ! 439: --*p; ! 440: return (n); ! 441: } ! 442: ! 443: /* Defer message about failure to open file to prevent messing up ! 444: alignment of page with tear perforations or form markers. ! 445: Treat empty file as special case and report as diagnostic. ! 446: */ ! 447: #define EMPTY 14 /* length of " -- empty file" */ ! 448: typedef struct err { struct err *e_nextp; char *e_mess; } ERR; ! 449: ERR *Err = NULL, *Lasterr = (ERR *)&Err; ! 450: ! 451: FILE *mustopen(s, f) char *s; register FILS *f; ! 452: { ! 453: if (*s == '\0') { ! 454: f->f_name = STDINNAME(); ! 455: f->f_f = stdin; ! 456: } else if ((f->f_f = fopen(f->f_name = s, "r")) == NULL) { ! 457: char *strcpy(); ! 458: s = ffiler(f->f_name); ! 459: s = strcpy((char *)getspace((UNS)(strlen(s) + 1)), s); ! 460: } ! 461: if (f->f_f != NULL) { ! 462: if ((f->f_nextc = getc(f->f_f)) != EOF || Multi == 'm') ! 463: return (f->f_f); ! 464: sprintf(s = (char *)getspace((UNS)(strlen(f->f_name) + 1 + EMPTY)), ! 465: "%s -- empty file", f->f_name); ! 466: fclose(f->f_f); ! 467: } ! 468: Error = 1; ! 469: if (Report) ! 470: if (Ttyout) { /* accumulate error reports */ ! 471: Lasterr = Lasterr->e_nextp = (ERR *)getspace((UNS)sizeof(ERR)); ! 472: Lasterr->e_nextp = NULL; ! 473: Lasterr->e_mess = s; ! 474: } else { /* ok to print error report now */ ! 475: cerror(s); ! 476: putc('\n', stderr); ! 477: } ! 478: return ((FILE *)NULL); ! 479: } ! 480: ! 481: ANY *getspace(n) UNS n; ! 482: { ! 483: ANY *t; ! 484: ! 485: if ((t = (ANY *)malloc(n)) == NULL) die("out of space"); ! 486: return (t); ! 487: } ! 488: ! 489: die(s) char *s; ! 490: { ! 491: ++Error; ! 492: errprint(); ! 493: cerror(s); ! 494: putc('\n', stderr); ! 495: exit(1); ! 496: } ! 497: ! 498: onintr() ! 499: { ! 500: ++Error; ! 501: errprint(); ! 502: INTREXIT(1); ! 503: } ! 504: ! 505: errprint() /* print accumulated error reports */ ! 506: { ! 507: fflush(stdout); ! 508: for ( ; Err != NULL; Err = Err->e_nextp) { ! 509: cerror(Err->e_mess); ! 510: putc('\n', stderr); ! 511: } ! 512: done(); ! 513: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.