.
[coreutils.git] / src / pr.c
blob15f2f236349318626b94784c74e2429a39f66948
1 /* pr -- convert text files for printing.
2 Copyright (C) 1988, 1991, 1995 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
18 /* Author: Pete TerMaat. */
20 /* Things to watch: Sys V screws up on ...
21 pr -n -3 -s: /usr/dict/words
22 pr -m -o10 -n /usr/dict/words{,,,}
23 pr -6 -a -n -o5 /usr/dict/words
25 Ideas:
27 Keep a things_to_do list of functions to call when we know we have
28 something to print. Cleaner than current series of checks.
30 Improve the printing of control prefixes.
33 Options:
35 +PAGE Begin output at page PAGE of the output.
37 -COLUMN Produce output that is COLUMN columns wide and print
38 columns down.
40 -a Print columns across rather than down. The input
41 one
42 two
43 three
44 four
45 will be printed as
46 one two three
47 four
49 -b Balance columns on the last page.
51 -c Print unprintable characters as control prefixes.
52 Control-g is printed as ^G.
54 -d Double space the output.
56 -e[c[k]] Expand tabs to spaces on input. Optional argument C
57 is the input tab character. (Default is `\t'.) Optional
58 argument K is the input tab character's width. (Default is 8.)
61 -f Use formfeeds instead of newlines to separate pages.
63 -h header Replace the filename in the header with the string HEADER.
65 -i[c[k]] Replace spaces with tabs on output. Optional argument
66 C is the output tab character. (Default is `\t'.) Optional
67 argument K is the output tab character's width. (Default
68 is 8.)
70 -l lines Set the page length to LINES. Default is 66.
72 -m Print files in parallel.
74 -n[c[k]] Precede each column with a line number.
75 (With parallel files, precede each line with a line
76 number.) Optional argument C is the character to print
77 after each number. (Default `\t'.) Optional argument
78 K is the number of digits per line number. (Default 5.)
80 -o offset Offset each line with a margin OFFSET spaces wide.
81 Total page width is the size of this offset plus the
82 width set with `-w'.
84 -r Ignore files that can't be opened.
86 -s[c] Separate each line with a character. Optional argument C is
87 the character to be used. Default is `\t'.
89 -t Do not print headers or footers.
91 -v Print unprintable characters as escape sequences.
92 Control-G becomes \007.
94 -w width Set the page width to WIDTH characters. */
97 #include <config.h>
99 #include <stdio.h>
100 #include <getopt.h>
101 #include <sys/types.h>
102 #include <time.h>
103 #include "system.h"
104 #include "version.h"
105 #include "error.h"
107 char *xmalloc ();
108 char *xrealloc ();
110 static int char_to_clump ();
111 static int read_line ();
112 static int print_page ();
113 static int print_stored ();
114 static int open_file ();
115 static int skip_to_page ();
116 static void getoptarg ();
117 static void usage ();
118 static void print_files ();
119 static void init_header ();
120 static void init_store_cols ();
121 static void store_columns ();
122 static void balance ();
123 static void store_char ();
124 static void pad_down ();
125 static void read_rest_of_line ();
126 static void print_char ();
127 static void cleanup ();
129 #ifndef TRUE
130 #define TRUE 1
131 #define FALSE 0
132 #endif
134 /* Used with start_position in the struct COLUMN described below.
135 If start_position == ANYWHERE, we aren't truncating columns and
136 can begin printing a column anywhere. Otherwise we must pad to
137 the horizontal position start_position. */
138 #define ANYWHERE 0
140 /* Each column has one of these structures allocated for it.
141 If we're only dealing with one file, fp is the same for all
142 columns.
144 The general strategy is to spend time setting up these column
145 structures (storing columns if necessary), after which printing
146 is a matter of flitting from column to column and calling
147 print_func.
149 Parallel files, single files printing across in multiple
150 columns, and single files printing down in multiple columns all
151 fit the same printing loop.
153 print_func Function used to print lines in this column.
154 If we're storing this column it will be
155 print_stored(), Otherwise it will be read_line().
157 char_func Function used to process characters in this column.
158 If we're storing this column it will be store_char(),
159 otherwise it will be print_char().
161 current_line Index of the current entry in line_vector, which
162 contains the index of the first character of the
163 current line in buff[].
165 lines_stored Number of lines in this column which are stored in
166 buff.
168 lines_to_print If we're storing this column, lines_to_print is
169 the number of stored_lines which remain to be
170 printed. Otherwise it is the number of lines
171 we can print without exceeding lines_per_body.
173 start_position The horizontal position we want to be in before we
174 print the first character in this column.
176 numbered True means precede this column with a line number. */
178 struct COLUMN
180 FILE *fp; /* Input stream for this column. */
181 char *name; /* File name. */
182 enum
184 OPEN,
185 ON_HOLD, /* Hit a form feed. */
186 CLOSED
187 } status; /* Status of the file pointer. */
188 int (*print_func) (); /* Func to print lines in this col. */
189 void (*char_func) (); /* Func to print/store chars in this col. */
190 int current_line; /* Index of current place in line_vector. */
191 int lines_stored; /* Number of lines stored in buff. */
192 int lines_to_print; /* No. lines stored or space left on page. */
193 int start_position; /* Horizontal position of first char. */
194 int numbered;
197 typedef struct COLUMN COLUMN;
199 #define NULLCOL (COLUMN *)0
201 /* The name under which this program was invoked. */
202 char *program_name;
204 /* All of the columns to print. */
205 static COLUMN *column_vector;
207 /* When printing a single file in multiple downward columns,
208 we store the leftmost columns contiguously in buff.
209 To print a line from buff, get the index of the first char
210 from line_vector[i], and print up to line_vector[i + 1]. */
211 static char *buff;
213 /* Index of the position in buff where the next character
214 will be stored. */
215 static int buff_current;
217 /* The number of characters in buff.
218 Used for allocation of buff and to detect overflow of buff. */
219 static int buff_allocated;
221 /* Array of indices into buff.
222 Each entry is an index of the first character of a line.
223 This is used when storing lines to facilitate shuffling when
224 we do column balancing on the last page. */
225 static int *line_vector;
227 /* Array of horizonal positions.
228 For each line in line_vector, end_vector[line] is the horizontal
229 position we are in after printing that line. We keep track of this
230 so that we know how much we need to pad to prepare for the next
231 column. */
232 static int *end_vector;
234 /* (-m) True means we're printing multiple files in parallel. */
235 static int parallel_files = FALSE;
237 /* (-[0-9]+) True means we're given an option explicitly specifying
238 number of columns. Used to detect when this option is used with -m. */
239 static int explicit_columns = FALSE;
241 /* (-t) True means we're printing headers and footers. */
242 static int extremities = TRUE;
244 /* True means we need to print a header as soon as we know we've got input
245 to print after it. */
246 static int print_a_header;
248 /* (-h) True means we're using the standard header rather than a
249 customized one specified by the -h flag. */
250 static int standard_header = TRUE;
252 /* (-f) True means use formfeeds instead of newlines to separate pages. */
253 static int use_form_feed = FALSE;
255 /* True means we have read the standard input. */
256 static int have_read_stdin = FALSE;
258 /* True means the -a flag has been given. */
259 static int print_across_flag = FALSE;
261 /* True means we're printing one file in multiple (>1) downward columns. */
262 static int storing_columns = TRUE;
264 /* (-b) True means balance columns on the last page as Sys V does. */
265 static int balance_columns = FALSE;
267 /* (-l) Number of lines on a page, including header and footer lines. */
268 static int lines_per_page = 66;
270 /* Number of lines in the header and footer can be reset to 0 using
271 the -t flag. */
272 static int lines_per_header = 5;
273 static int lines_per_body;
274 static int lines_per_footer = 5;
276 /* (-w) Width in characters of the page. Does not include the width of
277 the margin. */
278 static int chars_per_line = 72;
280 /* Number of characters in a column. Based on the gutter and page widths. */
281 static int chars_per_column;
283 /* (-e) True means convert tabs to spaces on input. */
284 static int untabify_input = FALSE;
286 /* (-e) The input tab character. */
287 static char input_tab_char = '\t';
289 /* (-e) Tabstops are at chars_per_tab, 2*chars_per_tab, 3*chars_per_tab, ...
290 where the leftmost column is 1. */
291 static int chars_per_input_tab = 8;
293 /* (-i) True means convert spaces to tabs on output. */
294 static int tabify_output = FALSE;
296 /* (-i) The output tab character. */
297 static char output_tab_char = '\t';
299 /* (-i) The width of the output tab. */
300 static int chars_per_output_tab = 8;
302 /* Keeps track of pending white space. When we hit a nonspace
303 character after some whitespace, we print whitespace, tabbing
304 if necessary to get to output_position + spaces_not_printed. */
305 static int spaces_not_printed;
307 /* Number of spaces between columns (though tabs can be used when possible to
308 use up the equivalent amount of space). Not sure if this is worth making
309 a flag for. BSD uses 0, Sys V uses 1. Sys V looks better. */
310 static int chars_per_gutter = 1;
312 /* (-o) Number of spaces in the left margin (tabs used when possible). */
313 static int chars_per_margin = 0;
315 /* Position where the next character will fall.
316 Leftmost position is 0 + chars_per_margin.
317 Rightmost position is chars_per_margin + chars_per_line - 1.
318 This is important for converting spaces to tabs on output. */
319 static int output_position;
321 /* Horizontal position relative to the current file.
322 (output_position depends on where we are on the page;
323 input_position depends on where we are in the file.)
324 Important for converting tabs to spaces on input. */
325 static int input_position;
327 /* Count number of failed opens so we can exit with non-zero
328 status if there were any. */
329 static int failed_opens = 0;
331 /* The horizontal position we'll be at after printing a tab character
332 of width c_ from the position h_. */
333 #define pos_after_tab(c_, h_) h_ - h_ % c_ + c_
335 /* The number of spaces taken up if we print a tab character with width
336 c_ from position h_. */
337 #define tab_width(c_, h_) - h_ % c_ + c_
339 /* (-NNN) Number of columns of text to print. */
340 static int columns = 1;
342 /* (+NNN) Page number on which to begin printing. */
343 static int first_page_number = 1;
345 /* Number of files open (not closed, not on hold). */
346 static int files_ready_to_read = 0;
348 /* Current page number. Displayed in header. */
349 static int page_number;
351 /* Current line number. Displayed when -n flag is specified.
353 When printing files in parallel (-m flag), line numbering is as follows:
354 1 foo goo moo
355 2 hoo too zoo
357 When printing files across (-a flag), ...
358 1 foo 2 moo 3 goo
359 4 hoo 3 too 6 zoo
361 Otherwise, line numbering is as follows:
362 1 foo 3 goo 5 too
363 2 moo 4 hoo 6 zoo */
364 static int line_number;
366 /* (-n) True means lines should be preceded by numbers. */
367 static int numbered_lines = FALSE;
369 /* (-n) Character which follows each line number. */
370 static char number_separator = '\t';
372 /* (-n) Width in characters of a line number. */
373 static int chars_per_number = 5;
375 /* Used when widening the first column to accommodate numbers -- only
376 needed when printing files in parallel. Includes width of both the
377 number and the number_separator. */
378 static int number_width;
380 /* Buffer sprintf uses to format a line number. */
381 static char *number_buff;
383 /* (-v) True means unprintable characters are printed as escape sequences.
384 control-g becomes \007. */
385 static int use_esc_sequence = FALSE;
387 /* (-c) True means unprintable characters are printed as control prefixes.
388 control-g becomes ^G. */
389 static int use_cntrl_prefix = FALSE;
391 /* (-d) True means output is double spaced. */
392 static int double_space = FALSE;
394 /* Number of files opened initially in init_files. Should be 1
395 unless we're printing multiple files in parallel. */
396 static int total_files = 0;
398 /* (-r) True means don't complain if we can't open a file. */
399 static int ignore_failed_opens = FALSE;
401 /* (-s) True means we separate columns with a specified character. */
402 static int use_column_separator = FALSE;
404 /* Character used to separate columns if the the -s flag has been specified. */
405 static char column_separator = '\t';
407 /* Number of separator characters waiting to be printed as soon as we
408 know that we have any input remaining to be printed. */
409 static int separators_not_printed;
411 /* Position we need to pad to, as soon as we know that we have input
412 remaining to be printed. */
413 static int padding_not_printed;
415 /* True means we should pad the end of the page. Remains false until we
416 know we have a page to print. */
417 static int pad_vertically;
419 /* (-h) String of characters used in place of the filename in the header. */
420 static char *custom_header;
422 /* String containing the date, filename or custom header, and "Page ". */
423 static char *header;
425 static int *clump_buff;
427 /* True means we truncate lines longer than chars_per_column. */
428 static int truncate_lines = FALSE;
430 /* If non-zero, display usage information and exit. */
431 static int show_help;
433 /* If non-zero, print the version on standard output then exit. */
434 static int show_version;
436 static struct option const long_options[] =
438 {"help", no_argument, &show_help, 1},
439 {"version", no_argument, &show_version, 1},
440 {0, 0, 0, 0}
443 /* Return the number of columns that have either an open file or
444 stored lines. */
446 static int
447 cols_ready_to_print ()
449 COLUMN *q;
450 int i;
451 int n;
453 n = 0;
454 for (q = column_vector, i = 0; i < columns; ++q, ++i)
455 if (q->status == OPEN ||
456 (storing_columns && q->lines_stored > 0 && q->lines_to_print > 0))
457 ++n;
458 return n;
461 void
462 main (argc, argv)
463 int argc;
464 char **argv;
466 int c;
467 int accum = 0;
468 int n_files;
469 char **file_names;
471 program_name = argv[0];
473 n_files = 0;
474 file_names = (argc > 1
475 ? (char **) xmalloc ((argc - 1) * sizeof (char *))
476 : NULL);
478 while (1)
480 c = getopt_long (argc, argv,
481 "-0123456789abcde::fFh:i::l:mn::o:rs::tvw:",
482 long_options, (int *) 0);
483 if (c == 1) /* Non-option argument. */
485 char *s;
486 s = optarg;
487 if (*s == '+')
489 ++s;
490 if (!ISDIGIT (*s))
492 error (0, 0, "`+' requires a numeric argument");
493 usage (2);
495 /* FIXME: use strtol */
496 first_page_number = atoi (s);
498 else
500 file_names[n_files++] = optarg;
503 else
505 if (ISDIGIT (c))
507 accum = accum * 10 + c - '0';
508 continue;
510 else
512 if (accum > 0)
514 columns = accum;
515 explicit_columns = TRUE;
516 accum = 0;
521 if (c == 1)
522 continue;
524 if (c == EOF)
525 break;
527 switch (c)
529 case 0: /* getopt long option */
530 break;
532 case 'a':
533 print_across_flag = TRUE;
534 storing_columns = FALSE;
535 break;
536 case 'b':
537 balance_columns = TRUE;
538 break;
539 case 'c':
540 use_cntrl_prefix = TRUE;
541 break;
542 case 'd':
543 double_space = TRUE;
544 break;
545 case 'e':
546 if (optarg)
547 getoptarg (optarg, 'e', &input_tab_char,
548 &chars_per_input_tab);
549 /* Could check tab width > 0. */
550 untabify_input = TRUE;
551 break;
552 case 'f':
553 case 'F':
554 use_form_feed = TRUE;
555 break;
556 case 'h':
557 custom_header = optarg;
558 standard_header = FALSE;
559 break;
560 case 'i':
561 if (optarg)
562 getoptarg (optarg, 'i', &output_tab_char,
563 &chars_per_output_tab);
564 /* Could check tab width > 0. */
565 tabify_output = TRUE;
566 break;
567 case 'l':
568 lines_per_page = atoi (optarg);
569 break;
570 case 'm':
571 parallel_files = TRUE;
572 storing_columns = FALSE;
573 break;
574 case 'n':
575 numbered_lines = TRUE;
576 if (optarg)
577 getoptarg (optarg, 'n', &number_separator,
578 &chars_per_number);
579 break;
580 case 'o':
581 chars_per_margin = atoi (optarg);
582 break;
583 case 'r':
584 ignore_failed_opens = TRUE;
585 break;
586 case 's':
587 use_column_separator = TRUE;
588 if (optarg)
590 char *s;
591 s = optarg;
592 column_separator = *s;
593 if (*++s)
595 fprintf (stderr, "\
596 %s: extra characters in the argument to the `-s' option: `%s'\n",
597 program_name, s);
598 usage (2);
601 break;
602 case 't':
603 extremities = FALSE;
604 break;
605 case 'v':
606 use_esc_sequence = TRUE;
607 break;
608 case 'w':
609 chars_per_line = atoi (optarg);
610 break;
611 default:
612 usage (2);
613 break;
617 if (show_version)
619 printf ("pr - %s\n", version_string);
620 exit (0);
623 if (show_help)
624 usage (0);
626 if (parallel_files && explicit_columns)
627 error (1, 0,
628 "Cannot specify number of columns when printing in parallel.");
630 if (parallel_files && print_across_flag)
631 error (1, 0,
632 "Cannot specify both printing across and printing in parallel.");
634 for ( ; optind < argc; optind++)
636 file_names[n_files++] = argv[optind];
639 if (n_files == 0)
641 /* No file arguments specified; read from standard input. */
642 print_files (0, (char **) 0);
644 else
646 if (parallel_files)
647 print_files (n_files, file_names);
648 else
650 int i;
651 for (i=0; i<n_files; i++)
652 print_files (1, &file_names[i]);
656 cleanup ();
658 if (have_read_stdin && fclose (stdin) == EOF)
659 error (1, errno, "standard input");
660 if (ferror (stdout) || fclose (stdout) == EOF)
661 error (1, errno, "write error");
662 if (failed_opens > 0)
663 exit(1);
664 exit (0);
667 /* Parse options of the form -scNNN.
669 Example: -nck, where 'n' is the option, c is the optional number
670 separator, and k is the optional width of the field used when printing
671 a number. */
673 static void
674 getoptarg (arg, switch_char, character, number)
675 char *arg, switch_char, *character;
676 int *number;
678 if (!ISDIGIT (*arg))
679 *character = *arg++;
680 if (*arg)
682 if (ISDIGIT (*arg))
683 *number = atoi (arg);
684 else
686 fprintf (stderr, "\
687 %s: extra characters in the argument to the `-%c' option: `%s'\n",
688 program_name, switch_char, arg);
689 usage (2);
694 /* Set parameters related to formatting. */
696 static void
697 init_parameters (number_of_files)
698 int number_of_files;
700 int chars_used_by_number = 0;
702 lines_per_body = lines_per_page - lines_per_header - lines_per_footer;
703 if (lines_per_body <= 0)
704 extremities = FALSE;
705 if (extremities == FALSE)
706 lines_per_body = lines_per_page;
708 if (double_space)
709 lines_per_body = lines_per_body / 2;
711 /* If input is stdin, cannot print parallel files. BSD dumps core
712 on this. */
713 if (number_of_files == 0)
714 parallel_files = FALSE;
716 if (parallel_files)
717 columns = number_of_files;
719 /* Tabification is assumed for multiple columns. */
720 if (columns > 1)
722 if (!use_column_separator)
723 truncate_lines = TRUE;
725 untabify_input = TRUE;
726 tabify_output = TRUE;
728 else
729 storing_columns = FALSE;
731 if (numbered_lines)
733 if (number_separator == input_tab_char)
735 number_width = chars_per_number +
736 tab_width (chars_per_input_tab,
737 (chars_per_margin + chars_per_number));
739 else
740 number_width = chars_per_number + 1;
741 /* The number is part of the column width unless we are
742 printing files in parallel. */
743 if (parallel_files)
744 chars_used_by_number = number_width;
747 chars_per_column = (chars_per_line - chars_used_by_number -
748 (columns - 1) * chars_per_gutter) / columns;
750 if (chars_per_column < 1)
751 error (1, 0, "page width too narrow");
753 if (numbered_lines)
755 if (number_buff != (char *) 0)
756 free (number_buff);
757 number_buff = (char *)
758 xmalloc (2 * chars_per_number * sizeof (char));
761 /* Pick the maximum between the tab width and the width of an
762 escape sequence. */
763 if (clump_buff != (int *) 0)
764 free (clump_buff);
765 clump_buff = (int *) xmalloc ((chars_per_input_tab > 4
766 ? chars_per_input_tab : 4) * sizeof (int));
769 /* Open the necessary files,
770 maintaining a COLUMN structure for each column.
772 With multiple files, each column p has a different p->fp.
773 With single files, each column p has the same p->fp.
774 Return 1 if (number_of_files > 0) and no files can be opened,
775 0 otherwise. */
777 static int
778 init_fps (number_of_files, av)
779 int number_of_files;
780 char **av;
782 int i, files_left;
783 COLUMN *p;
784 FILE *firstfp;
785 char *firstname;
787 total_files = 0;
789 if (column_vector != NULLCOL)
790 free ((char *) column_vector);
791 column_vector = (COLUMN *) xmalloc (columns * sizeof (COLUMN));
793 if (parallel_files)
795 files_left = number_of_files;
796 for (p = column_vector; files_left--; ++p, ++av)
798 if (open_file (*av, p) == 0)
800 --p;
801 --columns;
804 if (columns == 0)
805 return 1;
806 init_header ("", -1);
808 else
810 p = column_vector;
811 if (number_of_files > 0)
813 if (open_file (*av, p) == 0)
814 return 1;
815 init_header (*av, fileno (p->fp));
817 else
819 p->name = "standard input";
820 p->fp = stdin;
821 have_read_stdin = TRUE;
822 p->status = OPEN;
823 ++total_files;
824 init_header ("", -1);
827 firstname = p->name;
828 firstfp = p->fp;
829 for (i = columns - 1, ++p; i; --i, ++p)
831 p->name = firstname;
832 p->fp = firstfp;
833 p->status = OPEN;
836 files_ready_to_read = total_files;
837 return 0;
840 /* Determine print_func and char_func, the functions
841 used by each column for printing and/or storing.
843 Determine the horizontal position desired when we begin
844 printing a column (p->start_position). */
846 static void
847 init_funcs ()
849 int i, h, h_next;
850 COLUMN *p;
852 h = chars_per_margin;
854 if (use_column_separator)
855 h_next = ANYWHERE;
856 else
858 /* When numbering lines of parallel files, we enlarge the
859 first column to accomodate the number. Looks better than
860 the Sys V approach. */
861 if (parallel_files && numbered_lines)
862 h_next = h + chars_per_column + number_width;
863 else
864 h_next = h + chars_per_column;
867 /* This loop takes care of all but the rightmost column. */
869 for (p = column_vector, i = 1; i < columns; ++p, ++i)
871 if (storing_columns) /* One file, multi columns down. */
873 p->char_func = store_char;
874 p->print_func = print_stored;
876 else
877 /* One file, multi columns across; or parallel files. */
879 p->char_func = print_char;
880 p->print_func = read_line;
883 /* Number only the first column when printing files in
884 parallel. */
885 p->numbered = numbered_lines && (!parallel_files || i == 1);
886 p->start_position = h;
888 /* If we're using separators, all start_positions are
889 ANYWHERE, except the first column's start_position when
890 using a margin. */
892 if (use_column_separator)
894 h = ANYWHERE;
895 h_next = ANYWHERE;
897 else
899 h = h_next + chars_per_gutter;
900 h_next = h + chars_per_column;
904 /* The rightmost column.
906 Doesn't need to be stored unless we intend to balance
907 columns on the last page. */
908 if (storing_columns && balance_columns)
910 p->char_func = store_char;
911 p->print_func = print_stored;
913 else
915 p->char_func = print_char;
916 p->print_func = read_line;
919 p->numbered = numbered_lines && (!parallel_files || i == 1);
920 p->start_position = h;
923 /* Open a file. Return nonzero if successful, zero if failed. */
925 static int
926 open_file (name, p)
927 char *name;
928 COLUMN *p;
930 if (!strcmp (name, "-"))
932 p->name = "standard input";
933 p->fp = stdin;
934 have_read_stdin = 1;
936 else
938 p->name = name;
939 p->fp = fopen (name, "r");
941 if (p->fp == NULL)
943 ++failed_opens;
944 if (!ignore_failed_opens)
945 error (0, errno, "%s", name);
946 return 0;
948 p->status = OPEN;
949 ++total_files;
950 return 1;
953 /* Close the file in P.
955 If we aren't dealing with multiple files in parallel, we change
956 the status of all columns in the column list to reflect the close. */
958 static void
959 close_file (p)
960 COLUMN *p;
962 COLUMN *q;
963 int i;
965 if (p->status == CLOSED)
966 return;
967 if (ferror (p->fp))
968 error (1, errno, "%s", p->name);
969 if (p->fp != stdin && fclose (p->fp) == EOF)
970 error (1, errno, "%s", p->name);
972 if (!parallel_files)
974 for (q = column_vector, i = columns; i; ++q, --i)
976 q->status = CLOSED;
977 if (q->lines_stored == 0)
979 q->lines_to_print = 0;
983 else
985 p->status = CLOSED;
986 p->lines_to_print = 0;
989 --files_ready_to_read;
992 /* Put a file on hold until we start a new page,
993 since we've hit a form feed.
995 If we aren't dealing with parallel files, we must change the
996 status of all columns in the column list. */
998 static void
999 hold_file (p)
1000 COLUMN *p;
1002 COLUMN *q;
1003 int i;
1005 if (!parallel_files)
1006 for (q = column_vector, i = columns; i; ++q, --i)
1007 q->status = ON_HOLD;
1008 else
1009 p->status = ON_HOLD;
1010 p->lines_to_print = 0;
1011 --files_ready_to_read;
1014 /* Undo hold_file -- go through the column list and change any
1015 ON_HOLD columns to OPEN. Used at the end of each page. */
1017 static void
1018 reset_status ()
1020 int i = columns;
1021 COLUMN *p;
1023 for (p = column_vector; i; --i, ++p)
1024 if (p->status == ON_HOLD)
1026 p->status = OPEN;
1027 files_ready_to_read++;
1031 /* Print a single file, or multiple files in parallel.
1033 Set up the list of columns, opening the necessary files.
1034 Allocate space for storing columns, if necessary.
1035 Skip to first_page_number, if user has asked to skip leading pages.
1036 Determine which functions are appropriate to store/print lines
1037 in each column.
1038 Print the file(s). */
1040 static void
1041 print_files (number_of_files, av)
1042 int number_of_files;
1043 char **av;
1045 init_parameters (number_of_files);
1046 if (init_fps (number_of_files, av))
1047 return;
1048 if (storing_columns)
1049 init_store_cols ();
1051 if (first_page_number > 1)
1053 if (!skip_to_page (first_page_number))
1054 return;
1055 else
1056 page_number = first_page_number;
1058 else
1059 page_number = 1;
1061 init_funcs ();
1063 line_number = 1;
1064 while (print_page ())
1068 /* Generous estimate of number of characters taken up by "Jun 7 00:08 " and
1069 "Page NNNNN". */
1070 #define CHARS_FOR_DATE_AND_PAGE 50
1072 /* Initialize header information.
1073 If DESC is non-negative, it is a file descriptor open to
1074 FILENAME for reading.
1076 Allocate space for a header string,
1077 Determine the time, insert file name or user-specified string.
1079 It might be nice to have a "blank headers" option, since
1080 pr -h "" still prints the date and page number. */
1082 static void
1083 init_header (filename, desc)
1084 char *filename;
1085 int desc;
1087 int chars_per_header;
1088 char *f = filename;
1089 char *t, *middle;
1090 struct stat st;
1092 if (filename == 0)
1093 f = "";
1095 /* If parallel files or standard input, use current time. */
1096 if (desc < 0 || !strcmp (filename, "-") || fstat (desc, &st))
1097 st.st_mtime = time ((time_t *) 0);
1098 t = ctime (&st.st_mtime);
1100 t[16] = '\0'; /* Mark end of month and time string. */
1101 t[24] = '\0'; /* Mark end of year string. */
1103 middle = standard_header ? f : custom_header;
1105 chars_per_header = strlen (middle) + CHARS_FOR_DATE_AND_PAGE + 1;
1106 if (header != (char *) 0)
1107 free (header);
1108 header = (char *) xmalloc (chars_per_header * sizeof (char));
1110 sprintf (header, "%s %s %s Page", &t[4], &t[20], middle);
1113 /* Set things up for printing a page
1115 Scan through the columns ...
1116 Determine which are ready to print
1117 (i.e., which have lines stored or open files)
1118 Set p->lines_to_print appropriately
1119 (to p->lines_stored if we're storing, or lines_per_body
1120 if we're reading straight from the file)
1121 Keep track of this total so we know when to stop printing */
1123 static void
1124 init_page ()
1126 int j;
1127 COLUMN *p;
1129 if (storing_columns)
1131 store_columns ();
1132 for (j = columns - 1, p = column_vector; j; --j, ++p)
1134 p->lines_to_print = p->lines_stored;
1137 /* Last column. */
1138 if (balance_columns)
1140 p->lines_to_print = p->lines_stored;
1142 /* Since we're not balancing columns, we don't need to store
1143 the rightmost column. Read it straight from the file. */
1144 else
1146 if (p->status == OPEN)
1148 p->lines_to_print = lines_per_body;
1150 else
1151 p->lines_to_print = 0;
1154 else
1155 for (j = columns, p = column_vector; j; --j, ++p)
1156 if (p->status == OPEN)
1158 p->lines_to_print = lines_per_body;
1160 else
1161 p->lines_to_print = 0;
1164 /* Print one page.
1166 As long as there are lines left on the page and columns ready to print,
1167 Scan across the column list
1168 if the column has stored lines or the file is open
1169 pad to the appropriate spot
1170 print the column
1171 pad the remainder of the page with \n or \f as requested
1172 reset the status of all files -- any files which where on hold because
1173 of formfeeds are now put back into the lineup. */
1175 static int
1176 print_page ()
1178 int j;
1179 int lines_left_on_page;
1180 COLUMN *p;
1182 /* Used as an accumulator (with | operator) of successive values of
1183 pad_vertically. The trick is to set pad_vertically
1184 to zero before each run through the inner loop, then after that
1185 loop, it tells us whether a line was actually printed (whether a
1186 newline needs to be output -- or two for double spacing). But those
1187 values have to be accumulated (in pv) so we can invoke pad_down
1188 properly after the outer loop completes. */
1189 int pv;
1191 init_page ();
1193 if (cols_ready_to_print () == 0)
1194 return FALSE;
1196 if (extremities)
1197 print_a_header = TRUE;
1199 /* Don't pad unless we know a page was printed. */
1200 pad_vertically = FALSE;
1201 pv = FALSE;
1203 lines_left_on_page = lines_per_body;
1204 if (double_space)
1205 lines_left_on_page *= 2;
1207 while (lines_left_on_page > 0 && cols_ready_to_print () > 0)
1209 output_position = 0;
1210 spaces_not_printed = 0;
1211 separators_not_printed = 0;
1212 pad_vertically = FALSE;
1214 for (j = 1, p = column_vector; j <= columns; ++j, ++p)
1216 input_position = 0;
1217 if (p->lines_to_print > 0)
1219 padding_not_printed = p->start_position;
1221 if (!(p->print_func) (p))
1222 read_rest_of_line (p);
1223 pv |= pad_vertically;
1225 if (use_column_separator)
1226 ++separators_not_printed;
1228 --p->lines_to_print;
1229 if (p->lines_to_print <= 0)
1231 if (cols_ready_to_print () <= 0)
1232 break;
1237 if (pad_vertically)
1239 putchar ('\n');
1240 --lines_left_on_page;
1243 if (double_space && pv && extremities)
1245 putchar ('\n');
1246 --lines_left_on_page;
1250 pad_vertically = pv;
1252 if (pad_vertically && extremities)
1253 pad_down (lines_left_on_page + lines_per_footer);
1255 reset_status (); /* Change ON_HOLD to OPEN. */
1257 return TRUE; /* More pages to go. */
1260 /* Allocate space for storing columns.
1262 This is necessary when printing multiple columns from a single file.
1263 Lines are stored consecutively in buff, separated by '\0'.
1264 (We can't use a fixed offset since with the '-s' flag lines aren't
1265 truncated.)
1267 We maintain a list (line_vector) of pointers to the beginnings
1268 of lines in buff. We allocate one more than the number of lines
1269 because the last entry tells us the index of the last character,
1270 which we need to know in order to print the last line in buff. */
1272 static void
1273 init_store_cols ()
1275 int total_lines = lines_per_body * columns;
1276 int chars_if_truncate = total_lines * (chars_per_column + 1);
1278 if (line_vector != (int *) 0)
1279 free ((int *) line_vector);
1280 line_vector = (int *) xmalloc ((total_lines + 1) * sizeof (int *));
1282 if (end_vector != (int *) 0)
1283 free ((int *) end_vector);
1284 end_vector = (int *) xmalloc (total_lines * sizeof (int *));
1286 if (buff != (char *) 0)
1287 free (buff);
1288 buff_allocated = use_column_separator ? 2 * chars_if_truncate
1289 : chars_if_truncate; /* Tune this. */
1290 buff = (char *) xmalloc (buff_allocated * sizeof (char));
1293 /* Store all but the rightmost column.
1294 (Used when printing a single file in multiple downward columns)
1296 For each column
1297 set p->current_line to be the index in line_vector of the
1298 first line in the column
1299 For each line in the column
1300 store the line in buff
1301 add to line_vector the index of the line's first char
1302 buff_start is the index in buff of the first character in the
1303 current line. */
1305 static void
1306 store_columns ()
1308 int i, j;
1309 int line = 0;
1310 int buff_start;
1311 int last_col; /* The rightmost column which will be saved in buff */
1312 COLUMN *p;
1314 buff_current = 0;
1315 buff_start = 0;
1317 if (balance_columns)
1318 last_col = columns;
1319 else
1320 last_col = columns - 1;
1322 for (i = 1, p = column_vector; i <= last_col; ++i, ++p)
1323 p->lines_stored = 0;
1325 for (i = 1, p = column_vector; i <= last_col && files_ready_to_read;
1326 ++i, ++p)
1328 p->current_line = line;
1329 for (j = lines_per_body; j && files_ready_to_read; --j)
1331 if (p->status == OPEN) /* Redundant. Clean up. */
1333 input_position = 0;
1335 if (!read_line (p, i))
1336 read_rest_of_line (p);
1338 if (p->status == OPEN
1339 || buff_start != buff_current)
1341 ++p->lines_stored;
1342 line_vector[line] = buff_start;
1343 end_vector[line++] = input_position;
1344 buff_start = buff_current;
1349 /* Keep track of the location of the last char in buff. */
1350 line_vector[line] = buff_start;
1352 if (balance_columns && p->lines_stored != lines_per_body)
1353 balance (line);
1356 static void
1357 balance (total_stored)
1358 int total_stored;
1360 COLUMN *p;
1361 int i, lines;
1362 int first_line = 0;
1364 for (i = 1, p = column_vector; i <= columns; ++i, ++p)
1366 lines = total_stored / columns;
1367 if (i <= total_stored % columns)
1368 ++lines;
1370 p->lines_stored = lines;
1371 p->current_line = first_line;
1373 first_line += lines;
1377 /* Store a character in the buffer. */
1379 static void
1380 store_char (c)
1381 int c;
1383 if (buff_current >= buff_allocated)
1385 /* May be too generous. */
1386 buff_allocated = 2 * buff_allocated;
1387 buff = (char *) xrealloc (buff, buff_allocated * sizeof (char));
1389 buff[buff_current++] = (char) c;
1392 static void
1393 number (p)
1394 COLUMN *p;
1396 int i;
1397 char *s;
1399 sprintf (number_buff, "%*d", chars_per_number, line_number++);
1400 s = number_buff;
1401 for (i = chars_per_number; i > 0; i--)
1402 (p->char_func) ((int) *s++);
1404 if (number_separator == input_tab_char)
1406 i = number_width - chars_per_number;
1407 while (i-- > 0)
1408 (p->char_func) ((int) ' ');
1410 else
1411 (p->char_func) ((int) number_separator);
1413 if (truncate_lines && !parallel_files)
1414 input_position += number_width;
1417 /* Print (or store) padding until the current horizontal position
1418 is position. */
1420 static void
1421 pad_across_to (position)
1422 int position;
1424 register int h = output_position;
1426 if (tabify_output)
1427 spaces_not_printed = position - output_position;
1428 else
1430 while (++h <= position)
1431 putchar (' ');
1432 output_position = position;
1436 /* Pad to the bottom of the page.
1438 If the user has requested a formfeed, use one.
1439 Otherwise, use newlines. */
1441 static void
1442 pad_down (lines)
1443 int lines;
1445 register int i;
1447 if (use_form_feed)
1448 putchar ('\f');
1449 else
1450 for (i = lines; i; --i)
1451 putchar ('\n');
1454 /* Read the rest of the line.
1456 Read from the current column's file until an end of line is
1457 hit. Used when we've truncated a line and we no longer need
1458 to print or store its characters. */
1460 static void
1461 read_rest_of_line (p)
1462 COLUMN *p;
1464 register int c;
1465 FILE *f = p->fp;
1467 while ((c = getc (f)) != '\n')
1469 if (c == '\f')
1471 hold_file (p);
1472 break;
1474 else if (c == EOF)
1476 close_file (p);
1477 break;
1482 /* If we're tabifying output,
1484 When print_char encounters white space it keeps track
1485 of our desired horizontal position and delays printing
1486 until this function is called. */
1488 static void
1489 print_white_space ()
1491 register int h_new;
1492 register int h_old = output_position;
1493 register int goal = h_old + spaces_not_printed;
1495 while (goal - h_old > 1
1496 && (h_new = pos_after_tab (chars_per_output_tab, h_old)) <= goal)
1498 putchar (output_tab_char);
1499 h_old = h_new;
1501 while (++h_old <= goal)
1502 putchar (' ');
1504 output_position = goal;
1505 spaces_not_printed = 0;
1508 /* Print column separators.
1510 We keep a count until we know that we'll be printing a line,
1511 then print_separators() is called. */
1513 static void
1514 print_separators ()
1516 for (; separators_not_printed > 0; --separators_not_printed)
1517 print_char (column_separator);
1520 /* Print (or store, depending on p->char_func) a clump of N
1521 characters. */
1523 static void
1524 print_clump (p, n, clump)
1525 COLUMN *p;
1526 int n;
1527 int *clump;
1529 while (n--)
1530 (p->char_func) (*clump++);
1533 /* Print a character.
1535 If we're tabifying, all tabs have been converted to spaces by
1536 process_char(). Keep a count of consecutive spaces, and when
1537 a nonspace is encountered, call print_white_space() to print the
1538 required number of tabs and spaces. */
1540 static void
1541 print_char (c)
1542 int c;
1544 if (tabify_output)
1546 if (c == ' ')
1548 ++spaces_not_printed;
1549 return;
1551 else if (spaces_not_printed > 0)
1552 print_white_space ();
1554 /* Nonprintables are assumed to have width 0, except '\b'. */
1555 if (!ISPRINT (c))
1557 if (c == '\b')
1558 --output_position;
1560 else
1561 ++output_position;
1563 putchar (c);
1566 /* Skip to page PAGE before printing. */
1568 static int
1569 skip_to_page (page)
1570 int page;
1572 int n, i, j;
1573 COLUMN *p;
1575 for (n = 1; n < page; ++n)
1577 for (i = 1; i <= lines_per_body; ++i)
1579 for (j = 1, p = column_vector; j <= columns; ++j, ++p)
1580 read_rest_of_line (p);
1582 reset_status ();
1584 return files_ready_to_read > 0;
1587 /* Print a header.
1589 Formfeeds are assumed to use up two lines at the beginning of
1590 the page. */
1592 static void
1593 print_header ()
1595 if (!use_form_feed)
1596 fprintf (stdout, "\n\n");
1598 output_position = 0;
1599 pad_across_to (chars_per_margin);
1600 print_white_space ();
1602 fprintf (stdout, "%s %d\n\n\n", header, page_number++);
1604 print_a_header = FALSE;
1605 output_position = 0;
1608 /* Print (or store, if p->char_func is store_char()) a line.
1610 Read a character to determine whether we have a line or not.
1611 (We may hit EOF, \n, or \f)
1613 Once we know we have a line,
1614 set pad_vertically = TRUE, meaning it's safe
1615 to pad down at the end of the page, since we do have a page.
1616 print a header if needed.
1617 pad across to padding_not_printed if needed.
1618 print any separators which need to be printed.
1619 print a line number if it needs to be printed.
1621 Print the clump which corresponds to the first character.
1623 Enter a loop and keep printing until an end of line condition
1624 exists, or until we exceed chars_per_column.
1626 Return FALSE if we exceed chars_per_column before reading
1627 an end of line character, TRUE otherwise. */
1629 static int
1630 read_line (p)
1631 COLUMN *p;
1633 register int c, chars;
1634 int last_input_position;
1636 c = getc (p->fp);
1638 last_input_position = input_position;
1639 switch (c)
1641 case '\f':
1642 hold_file (p);
1643 return TRUE;
1644 case EOF:
1645 close_file (p);
1646 return TRUE;
1647 case '\n':
1648 break;
1649 default:
1650 chars = char_to_clump (c);
1653 if (truncate_lines && input_position > chars_per_column)
1655 input_position = last_input_position;
1656 return FALSE;
1659 if (p->char_func != store_char)
1661 pad_vertically = TRUE;
1663 if (print_a_header)
1664 print_header ();
1666 if (padding_not_printed != ANYWHERE)
1668 pad_across_to (padding_not_printed);
1669 padding_not_printed = ANYWHERE;
1672 if (use_column_separator)
1673 print_separators ();
1676 if (p->numbered)
1677 number (p);
1679 if (c == '\n')
1680 return TRUE;
1682 print_clump (p, chars, clump_buff);
1684 for (;;)
1686 c = getc (p->fp);
1688 switch (c)
1690 case '\n':
1691 return TRUE;
1692 case '\f':
1693 hold_file (p);
1694 return TRUE;
1695 case EOF:
1696 close_file (p);
1697 return TRUE;
1700 last_input_position = input_position;
1701 chars = char_to_clump (c);
1702 if (truncate_lines && input_position > chars_per_column)
1704 input_position = last_input_position;
1705 return FALSE;
1708 print_clump (p, chars, clump_buff);
1712 /* Print a line from buff.
1714 If this function has been called, we know we have something to
1715 print. Therefore we set pad_vertically to TRUE, print
1716 a header if necessary, pad across if necessary, and print
1717 separators if necessary.
1719 Return TRUE, meaning there is no need to call read_rest_of_line. */
1721 static int
1722 print_stored (p)
1723 COLUMN *p;
1725 int line = p->current_line++;
1726 register char *first = &buff[line_vector[line]];
1727 register char *last = &buff[line_vector[line + 1]];
1729 pad_vertically = TRUE;
1731 if (print_a_header)
1732 print_header ();
1734 if (padding_not_printed != ANYWHERE)
1736 pad_across_to (padding_not_printed);
1737 padding_not_printed = ANYWHERE;
1740 if (use_column_separator)
1741 print_separators ();
1743 while (first != last)
1744 print_char (*first++);
1746 if (spaces_not_printed == 0)
1747 output_position = p->start_position + end_vector[line];
1749 return TRUE;
1752 /* Convert a character to the proper format and return the number of
1753 characters in the resulting clump. Increment input_position by
1754 the width of the clump.
1756 Tabs are converted to clumps of spaces.
1757 Nonprintable characters may be converted to clumps of escape
1758 sequences or control prefixes.
1760 Note: the width of a clump is not necessarily equal to the number of
1761 characters in clump_buff. (e.g, the width of '\b' is -1, while the
1762 number of characters is 1.) */
1764 static int
1765 char_to_clump (c)
1766 int c;
1768 register int *s = clump_buff;
1769 register int i;
1770 char esc_buff[4];
1771 int width;
1772 int chars;
1774 if (c == input_tab_char)
1776 width = tab_width (chars_per_input_tab, input_position);
1778 if (untabify_input)
1780 for (i = width; i; --i)
1781 *s++ = ' ';
1782 chars = width;
1784 else
1786 *s = c;
1787 chars = 1;
1791 else if (!ISPRINT (c))
1793 if (use_esc_sequence)
1795 width = 4;
1796 chars = 4;
1797 *s++ = '\\';
1798 sprintf (esc_buff, "%03o", c);
1799 for (i = 0; i <= 2; ++i)
1800 *s++ = (int) esc_buff[i];
1802 else if (use_cntrl_prefix)
1804 if (c < 0200)
1806 width = 2;
1807 chars = 2;
1808 *s++ = '^';
1809 *s++ = c ^ 0100;
1811 else
1813 width = 4;
1814 chars = 4;
1815 *s++ = '\\';
1816 sprintf (esc_buff, "%03o", c);
1817 for (i = 0; i <= 2; ++i)
1818 *s++ = (int) esc_buff[i];
1821 else if (c == '\b')
1823 width = -1;
1824 chars = 1;
1825 *s = c;
1827 else
1829 width = 0;
1830 chars = 1;
1831 *s = c;
1834 else
1836 width = 1;
1837 chars = 1;
1838 *s = c;
1841 input_position += width;
1842 return chars;
1845 /* We've just printed some files and need to clean up things before
1846 looking for more options and printing the next batch of files.
1848 Free everything we've xmalloc'ed, except `header'. */
1850 static void
1851 cleanup ()
1853 if (number_buff)
1854 free (number_buff);
1855 if (clump_buff)
1856 free (clump_buff);
1857 if (column_vector)
1858 free (column_vector);
1859 if (line_vector)
1860 free (line_vector);
1861 if (end_vector)
1862 free (end_vector);
1863 if (buff)
1864 free (buff);
1867 /* Complain, print a usage message, and die. */
1869 static void
1870 usage (status)
1871 int status;
1873 if (status != 0)
1874 fprintf (stderr, "Try `%s --help' for more information.\n",
1875 program_name);
1876 else
1878 printf ("\
1879 Usage: %s [OPTION]... [FILE]...\n\
1881 program_name);
1882 printf ("\
1883 Paginate or columnate FILE(s) for printing.\n\
1885 +PAGE begin printing with page PAGE\n\
1886 -COLUMN produce COLUMN-column output and print columns down\n\
1887 -F, -f simulate formfeed with newlines on output\n\
1888 -a print columns across rather than down\n\
1889 -b balance columns on the last page\n\
1890 -c use hat notation (^G) and octal backslash notation\n\
1891 -d double space the output\n\
1892 -e[CHAR[WIDTH]] expand input CHARs (TABs) to tab WIDTH (8)\n\
1893 -h HEADER use HEADER instead of filename in page headers\n\
1894 -i[CHAR[WIDTH]] replace spaces with CHARs (TABs) to tab WIDTH (8)\n\
1895 -l PAGE_LENGTH set the page length to PAGE_LENGTH (66) lines\n\
1896 -m print all files in parallel, one in each column\n\
1897 -n[SEP[DIGITS]] number lines, use DIGITS (5) digits, then SEP (TAB)\n\
1898 -o MARGIN offset each line with MARGIN spaces (do not affect -w)\n\
1899 -r inhibit warning when a file cannot be opened\n\
1900 -s[SEP] separate columns by character SEP (TAB)\n\
1901 -t inhibit 5-line page headers and trailers\n\
1902 -v use octal backslash notation\n\
1903 -w PAGE_WIDTH set page width to PAGE_WIDTH (72) columns\n\
1904 --help display this help and exit\n\
1905 --version output version information and exit\n\
1907 -t implied by -l N when N < 10. Without -s, columns are separated by\n\
1908 spaces. With no FILE, or when FILE is -, read standard input.\n\
1911 exit (status);