pr.c

Go to the documentation of this file.
00001 /* pr - print files                     Author: Michiel Huisjes */
00002 
00003 /* Pr - print files
00004  *
00005  * Author: Michiel Huisjes.
00006  * Modified: Jacob P. Bunschoten.       (30 nov 87)
00007  *      When "columns" is not given and numbering is on:
00008  *              line numbers are correlated with input lines.
00009  *      (try pr [-1] -n file )
00010  *      tabs are accounted for.
00011  *      When numbering is turned on, width know this.
00012  *      automatic line-folding. -f to get the original program.
00013  *      backspaces are accounted for. -b to disable this.
00014  *      multi-column mode changed.
00015  *      header can be given and used.
00016  *      format changed may occur between printing of several files:
00017  *              pr -l30 file1 -w75 file2
00018  *
00019  * Modified: Rick Thomas.               (Sept 12, 1988)
00020  *      added "-M" option to cover functionality of old "-n" option,
00021  *      and made "-n" option behavior compatible with system V.
00022  *
00023  * Usage: pr [+page] [-columns] [-h header] [-wwidth] [-llength] [-ntm] [files]
00024  *        -t : Do not print the 5 line header and trailer at the page.
00025  *        -n : Turn on line numbering.
00026  *        -M : Use "Minix" style line numbering -- Each page begins at
00027  *             a line number that is an even multiple of the page length.
00028  *             Like the listings in Appendix E of the book.
00029  *        +page    : Start printing at page n.
00030  *        -columns : Print files in n-columns.
00031  *        -l length: Take the length of the page to be n instead of 66
00032  *        -h header: Take next argument as page header.
00033  *        -w width  : Take the width of the page to be n instead of default 79
00034  *        -f : do not fold lines.
00035  *
00036  * Modified: Lars Fredriksen            (Jan 19, 1990)
00037  *      fixed the program so that
00038  *              pr -n *.c
00039  *      would work. The clobal variable 'width' was decremented
00040  *      by NUM_WIDTH, for each file, resulting in width finally
00041  *      being so small that nothing was printed. Used the local
00042  *      variable 'w' for the width adjustment (in print())
00043  *
00044  * Modified: Kenneth J. Hendrickson     (10 April 1991)
00045  *      date in header should be last modification date for files,
00046  *      and the current time for stdin.
00047  *
00048  * Modified: Kees J. Bot                (5 October 1992)
00049  *      Use localtime(3) to get the date, it knows TZ.
00050  */
00051 
00052 #include <sys/types.h>
00053 #include <sys/stat.h>
00054 #include <string.h>
00055 #include <time.h>
00056 #include <stdlib.h>
00057 #include <stdio.h>
00058 
00059 
00060 #define DEF_LENGTH      66
00061 #define DEF_WIDTH       79
00062 #define NUM_WIDTH       8
00063 #define TAB_WIDTH       8       /* fixed tab_width */
00064 
00065 /* Used to compute next (fixed) tabstop */
00066 #define TO_TAB(x)       (( (x) + TAB_WIDTH ) & ~07 )
00067 
00068 typedef char BOOL;
00069 
00070 #define FALSE           0
00071 #define TRUE            1
00072 
00073 /* EAT: eat rest of input line */
00074 #define EAT(fp)         while((c=getc(fp))!='\n' && c!=EOF)
00075 
00076 /* L_BUF: calculate address of pointer to char (string) used in format */
00077 #define L_BUF(i,j)      * (char **) (line_buf + (i + j*length)*sizeof(char *))
00078 
00079 char *header;
00080 BOOL no_header;
00081 BOOL number = FALSE;
00082 BOOL minix_number = FALSE;
00083 BOOL ext_header_set = FALSE;    /* external header given */
00084 BOOL back_space = TRUE;         /* back space correction in line width */
00085 BOOL dont_fold = FALSE;         /* original. If the line does not fit eat it. */
00086 short columns;
00087 short cwidth;
00088 short start_page = 1;
00089 short width = DEF_WIDTH;
00090 short length = DEF_LENGTH;
00091 short linenr;
00092 char *line_buf;                 /* used in format for multi-column output */
00093 
00094 char output[1024];
00095 
00096 _PROTOTYPE(int main, (int argc, char **argv));
00097 _PROTOTYPE(static char *myalloc, (size_t size));
00098 _PROTOTYPE(char skip_page, (int lines, int width, FILE * filep));
00099 _PROTOTYPE(void format, (FILE * filep));
00100 _PROTOTYPE(void print_page, (int pagenr, int maxcol));
00101 _PROTOTYPE(void print, (FILE * filep));
00102 _PROTOTYPE(void out_header, (int page));
00103 _PROTOTYPE(void print_time, (time_t t));
00104 
00105 int main(argc, argv)
00106 int argc;
00107 char *argv[];
00108 {
00109   FILE *file;
00110   char *ptr;
00111   int index = 1;                /* index is one ahead of argc */
00112   int line, col;
00113 
00114   setbuf(stdout, output);
00115   do {
00116         if (argc == index)      /* No arguments (left) */
00117                 goto pr_files;
00118 
00119         ptr = argv[index++];
00120         if (*ptr == '+') {
00121                 start_page = atoi(++ptr);
00122                 continue;
00123         }
00124         if (*ptr != '-') {      /* no flags */
00125                 index--;
00126                 goto pr_files;
00127         }
00128         if (*++ptr >= '0' && *ptr <= '9') {
00129                 columns = atoi(ptr);
00130                 if (columns <= 0) columns = 1;
00131                 continue;       /* Fetch next flag */
00132         }
00133         while (*ptr) switch (*ptr++) {
00134                     case 't':   no_header = TRUE;       break;
00135                     case 'n':
00136                         number = TRUE;
00137                         minix_number = FALSE;
00138                         break;
00139                     case 'M':
00140                         number = TRUE;
00141                         minix_number = TRUE;
00142                         break;
00143                     case 'h':
00144                         header = argv[index++];
00145                         ext_header_set = TRUE;
00146                         break;
00147                     case 'w':
00148                         if ((width = atoi(ptr)) <= 0) width = DEF_WIDTH;
00149                         *ptr = '\0';
00150                         break;
00151                     case 'l':
00152                         if ((length = atoi(ptr)) <= 0) length = DEF_LENGTH;
00153                         *ptr = '\0';
00154                         break;
00155                     case 'b':   /* back_space correction off */
00156                         back_space = FALSE;
00157                         break;
00158                     case 'f':   /* do not fold lines */
00159                         dont_fold = TRUE;
00160                         break;
00161                     default:
00162                         fprintf(stderr, "Usage: %s [+page] [-columns] [-h header] [-w<width>] [-l<length>] [-nMt] [files]\n", argv[0]);
00163                         exit(1);
00164                 }
00165         continue;               /* Scan for next flags */
00166 
00167 
00168         /* ==============  flags are read. Print the file(s) ========= */
00169 
00170 pr_files:
00171 
00172         if (!no_header) length -= 10;
00173 
00174         if (columns) {
00175                 cwidth = width / columns + 1;
00176                 if (columns > width) {
00177                         fprintf(stderr, "Too many columns for page width.\n");
00178                         exit(1);
00179                 }
00180 
00181                 /* Allocate piece of mem to hold some pointers */
00182                 line_buf = myalloc(length * columns * sizeof(char *));
00183         }
00184         for (line = 0; line < length; line++)
00185                 for (col = 0; col < columns; col++)
00186                         L_BUF(line, col) = NULL;
00187 
00188         if (length <= 0) {
00189                 fprintf(stderr, "Minimal length should be %d\n", no_header ?
00190                         1 : 11);
00191                 exit(1);
00192         }
00193         while (index <= argc) { /* print all files, including stdin */
00194                 if (index < argc && (*argv[index] == '-' || *argv[index] == '+'))
00195                         break;  /* Format change */
00196 
00197                 if (argc == index) {    /* no file specified, so stdin */
00198                         if (!ext_header_set) header = "";
00199                         file = stdin;
00200                 } else {
00201                         if ((file = fopen(argv[index], "r")) == (FILE *) 0) {
00202                                 fprintf(stderr, "Cannot open %s\n", argv[index++]);
00203                                 continue;
00204                         }
00205                         if (!ext_header_set) header = argv[index];
00206                 }
00207                 if (columns)
00208                         format(file);
00209                 else
00210                         print(file);
00211                 fclose(file);
00212                 if (++index >= argc)
00213                         break;  /* all files (including stdin) done */
00214         }
00215         if (index >= argc) break;
00216         /* When control comes here. format changes are to be done.
00217          * reinitialize some variables */
00218         if (!no_header) length += 10;
00219 
00220         start_page = 1;
00221         ext_header_set = FALSE;
00222         if (columns) free(line_buf);
00223   } while (index <= argc);      /* "pr -l60" should work too */
00224 
00225   (void) fflush(stdout);
00226   return(0);
00227 }
00228 
00229 char skip_page(lines, width, filep)
00230 int lines, width;
00231 FILE *filep;
00232 {
00233   short c;
00234   int char_cnt;
00235   int w;
00236 
00237   do {
00238         w = width;
00239         if (number)             /* first lines are shorter */
00240                 if (!columns || /* called from print(file)  */
00241                     !(lines % columns)) /* called from format(file) */
00242                         w -= NUM_WIDTH;
00243 
00244         char_cnt = 0;
00245         while ((c = getc(filep)) != '\n' && c != EOF && char_cnt < w) {
00246                 /* Calculate if this line is longer than "width (w)"
00247                  * characters */
00248                 if (c == '\b' && back_space) {
00249                         if (--char_cnt < 0) char_cnt = 0;
00250                 } else if (c == '\t')
00251                         char_cnt = TO_TAB(char_cnt);
00252                 else
00253                         char_cnt++;
00254         }
00255         if (dont_fold && c != '\n' && c != EOF) EAT(filep);
00256         lines--;
00257         if (c == '\n') linenr++;
00258   } while (lines > 0 && c != EOF);
00259 
00260   return c;                     /* last char read */
00261 }
00262 
00263 void format(filep)
00264 FILE *filep;
00265 {
00266   char buf[512];
00267   short c = '\0';
00268   short index, lines, i;
00269   short page_number = 0;
00270   short maxcol = columns;
00271   short wdth;
00272   short line, col;
00273 
00274   do {
00275         /* Check printing of page */
00276         page_number++;
00277 
00278         if (page_number < start_page && c != EOF) {
00279                 c = (char) skip_page(columns * length, cwidth, filep);
00280                 continue;
00281         }
00282         if (c == EOF) return;
00283 
00284         lines = columns * length;
00285         for (line = 0; line < length; line++)
00286                 for (col = 0; col < columns; col++) {
00287                         if (L_BUF(line, col) != NULL)
00288                                 free(L_BUF(line, col));
00289                         L_BUF(line, col) = (char *) NULL;
00290                 }
00291         line = 0;
00292         col = 0;
00293         do {
00294                 index = 0;
00295                 wdth = cwidth - 1;
00296                 if (number && !col)     /* need room for numbers */
00297                         wdth -= NUM_WIDTH;
00298 
00299                 /* Intermidiate colums are shortened by 1 char */
00300                 /* Last column not */
00301                 if (col + 1 == columns) wdth++;
00302                 for (i = 0; i < wdth - 1; i++) {
00303                         c = getc(filep);
00304                         if (c == '\n' || c == EOF) break;
00305 
00306                         if (c == '\b' && back_space) {
00307                                 buf[index++] = '\b';
00308                                 if (--i < 0) {  /* just in case ... */
00309                                         i = 0;
00310                                         index = 0;
00311                                 }
00312                         } else if (c == '\t') {
00313                                 int cnt, max;
00314 
00315                                 max = TO_TAB(i);
00316                                 for (cnt = i; cnt < max; cnt++)
00317                                         buf[index++] = ' ';
00318                                 i = max - 1;
00319                         } else
00320                                 buf[index++] = (char) c;
00321                 }
00322                 buf[index++] = '\0';
00323                 /* Collected enough chars (or eoln, or EOF) */
00324 
00325                 /* First char is EOF */
00326                 if (i == 0 && lines == columns * length && c == EOF) return;
00327 
00328                 /* Alloc mem to hold this (sub) string */
00329                 L_BUF(line, col) = myalloc(index * sizeof(char));
00330                 strcpy(L_BUF(line, col), buf);
00331 
00332                 line++;
00333                 line %= length;
00334                 if (line == 0) {
00335                         col++;
00336                         col %= columns;
00337                 }
00338                 if (dont_fold && c != '\n' && c != EOF) EAT(filep);
00339                 lines--;        /* line ready for output */
00340                 if (c == EOF) {
00341                         maxcol = columns - lines / length;
00342                 }
00343         } while (c != EOF && lines);
00344         print_page(page_number, maxcol);
00345   } while (c != EOF);
00346 }
00347 
00348 void print_page(pagenr, maxcol)
00349 short pagenr, maxcol;
00350 {
00351   short pad, i, j;
00352   short width;
00353   char *p;
00354 
00355   if (minix_number)
00356         linenr = (pagenr - 1) * length + 1;
00357   else
00358         linenr = 1;
00359 
00360   if (!no_header) out_header(pagenr);
00361 
00362   for (i = 0; i < length; i++) {
00363         for (j = 0; j < maxcol; j++) {
00364                 width = cwidth;
00365                 if (number && j == 0) { /* first columns */
00366                         printf("%7.7d ", linenr++);     /* 7 == NUM_WIDTH-1 */
00367                         width -= NUM_WIDTH;
00368                 }
00369                 pad = 0;
00370                 if (p = (char *) L_BUF(i, j))
00371                         for (; pad < width - 1 && *p; pad++) putchar(*p++);
00372                 if (j < maxcol - 1) while (pad++ < width - 1)
00373                                 putchar(' ');
00374         }
00375         putchar('\n');
00376   }
00377   if (!no_header) printf("\n\n\n\n\n");
00378 }
00379 
00380 void print(filep)
00381 FILE *filep;
00382 {
00383   short c = '\0';
00384   short page_number = 0;
00385   short lines;
00386   short cnt;
00387   short w = width;
00388   BOOL pr_number = TRUE;        /* only real lines are numbered, not folded
00389                          * parts */
00390 
00391   linenr = 1;
00392   if (number) w -= NUM_WIDTH;
00393 
00394   do {
00395         /* Check printing of page */
00396         page_number++;
00397 
00398         if (page_number < start_page && c != EOF) {
00399                 pr_number = FALSE;
00400                 c = skip_page(length, w, filep);
00401                 if (c == '\n') pr_number = TRUE;
00402                 continue;
00403         }
00404         if (c == EOF) return;
00405 
00406         if (minix_number) linenr = (page_number - 1) * length + 1;
00407 
00408         if (page_number == start_page) c = getc(filep);
00409 
00410         /* Print the page */
00411         lines = length;
00412         while (lines && c != EOF) {
00413                 if (lines == length && !no_header) out_header(page_number);
00414                 if (number)
00415                         if (pr_number)
00416                                 printf("%7.7d ", linenr++);     /* 7 == NUM_WIDTH-1 */
00417                         else
00418                                 printf("%7c ", ' ');    /* 7 == NUM_WIDTH-1 */
00419                 pr_number = FALSE;
00420                 cnt = 0;
00421                 while (c != '\n' && c != EOF && cnt < w) {
00422                         if (c == '\t') {
00423                                 int i, max;
00424                                 max = TO_TAB(cnt);
00425                                 for (i = cnt; i < max; i++) putchar(' ');
00426                                 cnt = max - 1;
00427                         } else if (c == '\b' && back_space) {
00428                                 putchar('\b');
00429                                 cnt--;
00430                         } else
00431                                 putchar(c);
00432                         c = getc(filep);
00433                         cnt++;
00434                 }
00435                 putchar('\n');
00436                 if (dont_fold && c != '\n' && c != EOF) EAT(filep);
00437                 lines--;
00438                 if (c == '\n') {
00439                         c = getc(filep);
00440                         pr_number = TRUE;
00441                 }
00442         }
00443         if (lines == length)    /* We never printed anything on this
00444                                  * page --  */
00445                 return;         /* even the header, so dont try to fill it up */
00446         if (!no_header)         /* print the trailer -- 5 blank lines */
00447                 printf("\n\n\n\n\n");
00448   } while (c != EOF);
00449 
00450   /* Fill last page */
00451   if (page_number >= start_page) {
00452         while (lines--) putchar('\n');
00453   }
00454 }
00455 
00456 static char *myalloc(size)
00457 size_t size;                    /* How many bytes */
00458 {
00459   void *ptr;
00460 
00461   ptr = malloc(size);
00462   if (ptr == NULL) {
00463         fprintf(stderr, "malloc returned NULL\n");
00464         exit(1);
00465   }
00466   return(char *) ptr;
00467 }
00468 
00469 void out_header(page)
00470 short page;
00471 {
00472   time_t t;
00473   struct stat buf;
00474 
00475   if (strlen(header)) {
00476         stat(header, &buf);     /* use last modify time for file */
00477         t = buf.st_mtime;
00478   } else
00479         (void) time(&t);        /* use current time for stdin */
00480   print_time(t);
00481   printf("  %s   Page %d\n\n\n", header, page);
00482 }
00483 
00484 char *moname[] = {
00485           "Jan", "Feb", "Mar", "Apr", "May", "Jun",
00486           "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
00487 };
00488 
00489 /* Print the date. */
00490 void print_time(t)
00491 time_t t;
00492 {
00493   struct tm *tm;
00494 
00495   tm = localtime(&t);
00496 
00497   printf("\n\n%s %2d %2d:%02d %d",
00498          moname[tm->tm_mon],
00499          tm->tm_mday,
00500          tm->tm_hour,
00501          tm->tm_min,
00502          1900 + tm->tm_year
00503         );
00504 }

Generated on Fri Apr 14 22:57:10 2006 for minix by  doxygen 1.4.6