|
|
1.1 ! root 1: /* ! 2: * pr -- print files ! 3: * ! 4: * All references to page length exclude possible margin lines. ! 5: */ ! 6: ! 7: #include <stdio.h> ! 8: ! 9: #ifdef COHERENT ! 10: #include <sys/types.h> ! 11: #include <errno.h> ! 12: #endif ! 13: ! 14: #ifdef MSDOS ! 15: #include <sys/timeb.h> /* typedef long time_t; */ ! 16: #endif ! 17: ! 18: #define LSIZE 256 /* line size */ ! 19: #define LENGTH (66-MARGIN) /* default page length */ ! 20: #define WIDTH 80 /* default page width */ ! 21: #define TMAR 5 /* five lines of top margin */ ! 22: #define BMAR 5 /* five lines of bottom margin */ ! 23: #define HEADER 2 /* line # where header appears */ ! 24: ! 25: #define MARGIN (TMAR+BMAR) ! 26: ! 27: ! 28: /* ! 29: * info on input file streams ! 30: * Unless -m is in effect, only f[0] is used. ! 31: */ ! 32: struct f { ! 33: int f_ff; /* '\f' received */ ! 34: FILE *f_stream; /* input stream */ ! 35: }; ! 36: ! 37: ! 38: int ncol = 1, /* # of columns */ ! 39: nskip, /* # pages to skip of each file */ ! 40: length = LENGTH, /* page length */ ! 41: width = WIDTH, /* page width */ ! 42: lno, /* current input line # */ ! 43: fwidth; /* field width */ ! 44: char schar, /* separator char */ ! 45: tflag, /* -t: no header or margins */ ! 46: mflag, /* -m: multiple file output */ ! 47: nflag, /* -n: line number output */ ! 48: *date, /* date string */ ! 49: *header, /* -h: header text */ ! 50: **lines; /* buffer addr for multicolumn */ ! 51: ! 52: struct f f[20]; /* input file info */ ! 53: ! 54: char **init( ), ! 55: *malloc( ), ! 56: *ctime( ); ! 57: int page1( ), page2( ), ! 58: putl( ), nop( ); ! 59: FILE *openf( ); ! 60: ! 61: int (*page)( ) = page1; ! 62: ! 63: ! 64: /* ! 65: * paginate files to standard output ! 66: * If no files are given, use standard input. The file name "-" also ! 67: * means standard input. ! 68: */ ! 69: main( argc, argv) ! 70: char **argv; ! 71: { ! 72: #ifdef MSDOS ! 73: msdoscvt("pr", &argc, &argv); ! 74: #endif ! 75: argv = init( argc, argv); ! 76: ! 77: if (*argv) ! 78: while (*argv) { ! 79: f[0].f_stream = openf( *argv); ! 80: print( *argv++); ! 81: fclose( f[0].f_stream); ! 82: } ! 83: else ! 84: print( ""); ! 85: ! 86: return (0); ! 87: } ! 88: ! 89: ! 90: /* ! 91: * initialize & get options ! 92: * Flags are recognized up to the first file name. If multi-column (-N), ! 93: * allocate line array. If printing multiple files (-m), open all files. ! 94: * There are two paging algorithms: one file per column (page1), and ! 95: * many columns per file (page2). The latter requires page buffering. ! 96: * init( ) makes this selection. ! 97: */ ! 98: char ** ! 99: init( ac, av) ! 100: register char **av; ! 101: { ! 102: register mar = MARGIN; ! 103: static char obuf[BUFSIZ]; ! 104: time_t tvec; ! 105: ! 106: setbuf( stdout, obuf); ! 107: ! 108: while (++av, --ac) { ! 109: if (av[0][0] == '+') ! 110: if ((nskip=atoi( &av[0][1])) <= 0) ! 111: fatal( "bad skip"); ! 112: else ! 113: continue; ! 114: if (av[0][0] != '-') ! 115: break; ! 116: switch (av[0][1]) { ! 117: case '\0': ! 118: break; ! 119: case 'l': ! 120: length = atoi( &av[0][2]) - mar; ! 121: continue; ! 122: case 'w': ! 123: width = atoi( &av[0][2]); ! 124: continue; ! 125: case 'h': ! 126: if (av[0][2]) ! 127: header = &av[0][2]; ! 128: else { ! 129: if (--ac <= 0) ! 130: fatal( "missing header arg"); ! 131: header = (++av)[0]; ! 132: } ! 133: continue; ! 134: case 's': ! 135: if ((schar=av[0][2]) == '\0') ! 136: schar = '\t'; ! 137: continue; ! 138: case 'm': ! 139: ++mflag; ! 140: continue; ! 141: case 't': ! 142: ++tflag; ! 143: length += mar; ! 144: mar = 0; ! 145: continue; ! 146: case 'n': ! 147: ++nflag; ! 148: continue; ! 149: default: ! 150: if ('0'<=av[0][1] && av[0][1]<='9') ! 151: ncol = atoi( &av[0][1]); ! 152: else ! 153: fatal( "no such switch %s", av[0]); ! 154: continue; ! 155: } ! 156: break; ! 157: ! 158: } ! 159: ! 160: f[0].f_stream = stdin; ! 161: if (mflag && av[0]) { ! 162: ncol = 0; ! 163: do { ! 164: f[ncol++].f_stream = openf( av++[0]); ! 165: } while (av[0]); ! 166: } ! 167: ! 168: /* ! 169: * check that all options jive ! 170: */ ! 171: if (length <= 0) ! 172: if (length == -mar) { /* gunja artifice */ ! 173: length = 1; ! 174: ++tflag; ! 175: } ! 176: else ! 177: fatal( "length too small"); ! 178: fwidth = width / ncol; ! 179: if (schar) ! 180: --fwidth; ! 181: if (fwidth <= 0 || (nflag && fwidth < 10)) ! 182: fatal( "width too small"); ! 183: if (fwidth >= LSIZE-1) ! 184: fatal( "too wide"); ! 185: if (ncol>1 && mflag==0) { ! 186: if ((lines=malloc( (ncol-1)*length*sizeof( char *))) == NULL) ! 187: fatal( "insufficient core"); ! 188: page = page2; ! 189: } ! 190: ! 191: time( &tvec); ! 192: date = ctime( &tvec); ! 193: ! 194: return (av); ! 195: } ! 196: ! 197: ! 198: /* ! 199: * open input file ! 200: * Failure to open is fatal. openf( "-") returns stdin. ! 201: */ ! 202: FILE * ! 203: openf( file) ! 204: register char *file; ! 205: { ! 206: register FILE *stream; ! 207: ! 208: lno = 0; ! 209: if (file[0]=='-' && file[1]=='\0') ! 210: return (stdin); ! 211: if ((stream=fopen( file, "r")) == NULL) ! 212: #ifdef COHERENT ! 213: if (errno == EMFILE) ! 214: fatal( "too many files for -m"); ! 215: else ! 216: #endif ! 217: fatal( "can't open %s", file); ! 218: return (stream); ! 219: } ! 220: ! 221: ! 222: /* ! 223: * print from open input streams ! 224: * Control output of pages, perhaps provide header/footer margins and title. ! 225: * The paging routine is expected to give an eof warning on the last page. ! 226: */ ! 227: print( file) ! 228: char *file; ! 229: { ! 230: register i, ! 231: pg, ! 232: eof; ! 233: ! 234: for (pg=1; pg<=nskip; ++pg) ! 235: if ((*page)( nop)) ! 236: return; ! 237: ! 238: do { ! 239: if (tflag == 0) ! 240: for (i=0; i<TMAR; ++i) { ! 241: if (i != HEADER) { ! 242: putchar( '\n'); ! 243: continue; ! 244: } ! 245: printf( "%.12s%.5s %s Page %d, line %ld\n", ! 246: date+4, date+19, ! 247: header? header: file, ! 248: pg, ! 249: (long)(pg-1)*(mflag?1:ncol)*length+1); ! 250: } ! 251: eof = (*page)( putl); ! 252: if (tflag == 0) ! 253: for (i=0; i<BMAR; ++i) ! 254: putchar( '\n'); ! 255: } while (++pg, eof==0); ! 256: } ! 257: ! 258: ! 259: /* ! 260: * page one stream per column ! 261: * This handles all cases of one column per page. ! 262: * Formfeed advances output of that stream to the next page. ! 263: * Eof is only indicated when all streams give this condition. ! 264: */ ! 265: page1( putline) ! 266: int (*putline)( ); ! 267: { ! 268: register i, ! 269: j; ! 270: char lbuf[LSIZE]; ! 271: ! 272: for (i=0; i<length; ++i) { ! 273: for (j=0; j<ncol; ++j) { ! 274: getline( &f[j], lbuf); ! 275: (*putline)( lbuf, j<ncol-1? schar: 0); ! 276: } ! 277: (*putline)( (char *)0); ! 278: } ! 279: ! 280: i = 0; ! 281: for (j=0; j<ncol; ++j) { ! 282: f[j].f_ff = 0; ! 283: if (feof( f[j].f_stream)) ! 284: ++i; ! 285: else if (ungetc( getc( f[j].f_stream), f[j].f_stream) == EOF) ! 286: ++i; ! 287: } ! 288: return (i == j); ! 289: } ! 290: ! 291: ! 292: /* ! 293: * page one stream across multiple columns ! 294: * The first `ncol'-1 columns of text are buffered; the last is simply ! 295: * read as needed. Formfeeds advance output to the next column. ! 296: */ ! 297: page2( putline) ! 298: int (*putline)( ); ! 299: { ! 300: register i, ! 301: j, ! 302: k; ! 303: char lbuf[LSIZE]; ! 304: ! 305: for (i=0; i<(ncol-1)*length; ++i) { ! 306: if ((i%length) == 0) ! 307: f[0].f_ff = 0; ! 308: if (k = getline( &f[0], lbuf)) { ! 309: if ((lines[i]=malloc( k+1)) == NULL) ! 310: fatal( "out of core"); ! 311: strcpy( lines[i], lbuf); ! 312: } ! 313: else ! 314: lines[i] = NULL; ! 315: } ! 316: f[0].f_ff = 0; ! 317: ! 318: for (i=0; i<length; ++i) { ! 319: for (j=0; j<ncol-1; ++j) { ! 320: k = j*length + i; ! 321: if (lines[k]) { ! 322: (*putline)( lines[k], schar); ! 323: free( lines[k]); ! 324: } ! 325: else ! 326: (*putline)( "", schar); ! 327: } ! 328: getline( &f[0], lbuf); ! 329: (*putline)( lbuf, 0); ! 330: (*putline)( (char *)0); ! 331: } ! 332: ! 333: if (feof( f[0].f_stream)) ! 334: return (1); ! 335: if (ungetc( getc( f[0].f_stream), f[0].f_stream) == EOF) ! 336: return (1); ! 337: return (0); ! 338: } ! 339: ! 340: ! 341: /* ! 342: * read a line ! 343: * Simple char processing is done, including tab expansion. getline( ) ! 344: * will return an empty line if f_ff is set. Lines are truncated to ! 345: * fit the field width. ! 346: */ ! 347: getline( fp, lbuf) ! 348: register struct f *fp; ! 349: char *lbuf; ! 350: { ! 351: register col; ! 352: register char *p; ! 353: char c; ! 354: ! 355: col = 0; ! 356: p = lbuf; ! 357: if (feof( fp->f_stream)==0 && fp->f_ff==0) { ! 358: if (nflag) { ! 359: sprintf(p, "%4d: ", ++lno); ! 360: p += 6; ! 361: } ! 362: for (; ; ) { ! 363: switch (c = getc(fp->f_stream)) { ! 364: case '\f': ! 365: ++fp->f_ff; ! 366: case EOF: ! 367: if (nflag && (p == &lbuf[6])) ! 368: p = lbuf; ! 369: break; ! 370: case '\n': ! 371: break; ! 372: case '\r': ! 373: continue; ! 374: case '\t': ! 375: do { ! 376: if (p<&lbuf[LSIZE-1] && col<fwidth) ! 377: *p++ = ' '; ! 378: } while (++col & 7); ! 379: continue; ! 380: case '\b': ! 381: if (col) { ! 382: --col; ! 383: if (p<&lbuf[LSIZE-1] && col<fwidth) ! 384: *p++ = c; ! 385: } ! 386: continue; ! 387: default: ! 388: if (p<&lbuf[LSIZE-1] && col<fwidth) ! 389: *p++ = c; ! 390: ++col; ! 391: continue; ! 392: } ! 393: break; ! 394: } ! 395: ! 396: } ! 397: *p = '\0'; ! 398: return (p - lbuf); ! 399: } ! 400: ! 401: ! 402: /* ! 403: * write a line, incrementally ! 404: * A line of output can be built by successive calls to putl( ). A line ! 405: * address of 0 puts the newline. Simple char processing is done, ! 406: * including tab optimization. Each line segment is padded to the ! 407: * field width, unless a there is a field separator char. ! 408: */ ! 409: putl( lbuf, schr) ! 410: char *lbuf; ! 411: { ! 412: register char *p; ! 413: register c, ! 414: nextxcol; ! 415: static col, ! 416: xcol; ! 417: ! 418: if ((p=lbuf) == NULL) { ! 419: col = 0; ! 420: xcol = 0; ! 421: putchar( '\n'); ! 422: return; ! 423: } ! 424: nextxcol = xcol + fwidth; ! 425: ! 426: for (; ; ) { ! 427: if ((c= *p++) == '\0') { ! 428: if ((c=schr) == '\0') ! 429: break; ! 430: schr = 0; ! 431: --p; ! 432: nextxcol = xcol + 1; ! 433: } ! 434: if (c == ' ') { ! 435: ++xcol; ! 436: continue; ! 437: } ! 438: if (c == '\b') { ! 439: --xcol; ! 440: continue; ! 441: } ! 442: while ((col|7)+1 <= xcol) { ! 443: col = (col|7) + 1; ! 444: putchar( '\t'); ! 445: } ! 446: while (col < xcol) { ! 447: ++col; ! 448: putchar( ' '); ! 449: } ! 450: while (col > xcol) { ! 451: --col; ! 452: putchar( '\b'); ! 453: } ! 454: putchar( c); ! 455: xcol = ++col; ! 456: } ! 457: ! 458: xcol = nextxcol; ! 459: } ! 460: ! 461: ! 462: /* ! 463: * throw away output line ! 464: * Used when skipping the first pages of input. ! 465: */ ! 466: nop( ) ! 467: { ! 468: ! 469: } ! 470: ! 471: ! 472: /* ! 473: * print error message, exit ! 474: */ ! 475: fatal( arg0) ! 476: { ! 477: ! 478: fflush( stdout); ! 479: fprintf( stderr, "pr: %r\n", &arg0); ! 480: exit (1); ! 481: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.