(main): When argc == 1, don't try to xmalloc (0).
[coreutils.git] / src / pr.c
blob3451fa38b634d248305d0358670c5268382540f1
1 /* pr -- convert text files for printing.
2 Copyright (C) 1988, 1991 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., 675 Mass Ave, Cambridge, MA 02139, 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 <stdio.h>
98 #include <getopt.h>
99 #include <sys/types.h>
100 #include <time.h>
101 #include "system.h"
102 #include "version.h"
104 char *xmalloc ();
105 char *xrealloc ();
106 void error ();
108 static int char_to_clump ();
109 static int read_line ();
110 static int print_page ();
111 static int print_stored ();
112 static int open_file ();
113 static int skip_to_page ();
114 static void getoptarg ();
115 static void usage ();
116 static void print_files ();
117 static void init_header ();
118 static void init_store_cols ();
119 static void store_columns ();
120 static void balance ();
121 static void store_char ();
122 static void pad_down ();
123 static void read_rest_of_line ();
124 static void print_char ();
125 static void cleanup ();
127 #ifndef TRUE
128 #define TRUE 1
129 #define FALSE 0
130 #endif
132 /* Used with start_position in the struct COLUMN described below.
133 If start_position == ANYWHERE, we aren't truncating columns and
134 can begin printing a column anywhere. Otherwise we must pad to
135 the horizontal position start_position. */
136 #define ANYWHERE 0
138 /* Each column has one of these structures allocated for it.
139 If we're only dealing with one file, fp is the same for all
140 columns.
142 The general strategy is to spend time setting up these column
143 structures (storing columns if necessary), after which printing
144 is a matter of flitting from column to column and calling
145 print_func.
147 Parallel files, single files printing across in multiple
148 columns, and single files printing down in multiple columns all
149 fit the same printing loop.
151 print_func Function used to print lines in this column.
152 If we're storing this column it will be
153 print_stored(), Otherwise it will be read_line().
155 char_func Function used to process characters in this column.
156 If we're storing this column it will be store_char(),
157 otherwise it will be print_char().
159 current_line Index of the current entry in line_vector, which
160 contains the index of the first character of the
161 current line in buff[].
163 lines_stored Number of lines in this column which are stored in
164 buff.
166 lines_to_print If we're storing this column, lines_to_print is
167 the number of stored_lines which remain to be
168 printed. Otherwise it is the number of lines
169 we can print without exceeding lines_per_body.
171 start_position The horizontal position we want to be in before we
172 print the first character in this column.
174 numbered True means precede this column with a line number. */
176 struct COLUMN
178 FILE *fp; /* Input stream for this column. */
179 char *name; /* File name. */
180 enum
182 OPEN,
183 ON_HOLD, /* Hit a form feed. */
184 CLOSED
185 } status; /* Status of the file pointer. */
186 int (*print_func) (); /* Func to print lines in this col. */
187 void (*char_func) (); /* Func to print/store chars in this col. */
188 int current_line; /* Index of current place in line_vector. */
189 int lines_stored; /* Number of lines stored in buff. */
190 int lines_to_print; /* No. lines stored or space left on page. */
191 int start_position; /* Horizontal position of first char. */
192 int numbered;
195 typedef struct COLUMN COLUMN;
197 #define NULLCOL (COLUMN *)0
199 /* The name under which this program was invoked. */
200 char *program_name;
202 /* All of the columns to print. */
203 static COLUMN *column_vector;
205 /* When printing a single file in multiple downward columns,
206 we store the leftmost columns contiguously in buff.
207 To print a line from buff, get the index of the first char
208 from line_vector[i], and print up to line_vector[i + 1]. */
209 static char *buff;
211 /* Index of the position in buff where the next character
212 will be stored. */
213 static int buff_current;
215 /* The number of characters in buff.
216 Used for allocation of buff and to detect overflow of buff. */
217 static int buff_allocated;
219 /* Array of indices into buff.
220 Each entry is an index of the first character of a line.
221 This is used when storing lines to facilitate shuffling when
222 we do column balancing on the last page. */
223 static int *line_vector;
225 /* Array of horizonal positions.
226 For each line in line_vector, end_vector[line] is the horizontal
227 position we are in after printing that line. We keep track of this
228 so that we know how much we need to pad to prepare for the next
229 column. */
230 static int *end_vector;
232 /* (-m) True means we're printing multiple files in parallel. */
233 static int parallel_files = FALSE;
235 /* (-[0-9]+) True means we're given an option explicitly specifying
236 number of columns. Used to detect when this option is used with -m. */
237 static int explicit_columns = FALSE;
239 /* (-t) True means we're printing headers and footers. */
240 static int extremities = TRUE;
242 /* True means we need to print a header as soon as we know we've got input
243 to print after it. */
244 static int print_a_header;
246 /* (-h) True means we're using the standard header rather than a
247 customized one specified by the -h flag. */
248 static int standard_header = TRUE;
250 /* (-f) True means use formfeeds instead of newlines to separate pages. */
251 static int use_form_feed = FALSE;
253 /* True means we have read the standard input. */
254 static int have_read_stdin = FALSE;
256 /* True means the -a flag has been given. */
257 static int print_across_flag = FALSE;
259 /* True means we're printing one file in multiple (>1) downward columns. */
260 static int storing_columns = TRUE;
262 /* (-b) True means balance columns on the last page as Sys V does. */
263 static int balance_columns = FALSE;
265 /* (-l) Number of lines on a page, including header and footer lines. */
266 static int lines_per_page = 66;
268 /* Number of lines in the header and footer can be reset to 0 using
269 the -t flag. */
270 static int lines_per_header = 5;
271 static int lines_per_body;
272 static int lines_per_footer = 5;
274 /* (-w) Width in characters of the page. Does not include the width of
275 the margin. */
276 static int chars_per_line = 72;
278 /* Number of characters in a column. Based on the gutter and page widths. */
279 static int chars_per_column;
281 /* (-e) True means convert tabs to spaces on input. */
282 static int untabify_input = FALSE;
284 /* (-e) The input tab character. */
285 static char input_tab_char = '\t';
287 /* (-e) Tabstops are at chars_per_tab, 2*chars_per_tab, 3*chars_per_tab, ...
288 where the leftmost column is 1. */
289 static int chars_per_input_tab = 8;
291 /* (-i) True means convert spaces to tabs on output. */
292 static int tabify_output = FALSE;
294 /* (-i) The output tab character. */
295 static char output_tab_char = '\t';
297 /* (-i) The width of the output tab. */
298 static int chars_per_output_tab = 8;
300 /* Keeps track of pending white space. When we hit a nonspace
301 character after some whitespace, we print whitespace, tabbing
302 if necessary to get to output_position + spaces_not_printed. */
303 static int spaces_not_printed;
305 /* Number of spaces between columns (though tabs can be used when possible to
306 use up the equivalent amount of space). Not sure if this is worth making
307 a flag for. BSD uses 0, Sys V uses 1. Sys V looks better. */
308 static int chars_per_gutter = 1;
310 /* (-o) Number of spaces in the left margin (tabs used when possible). */
311 static int chars_per_margin = 0;
313 /* Position where the next character will fall.
314 Leftmost position is 0 + chars_per_margin.
315 Rightmost position is chars_per_margin + chars_per_line - 1.
316 This is important for converting spaces to tabs on output. */
317 static int output_position;
319 /* Horizontal position relative to the current file.
320 (output_position depends on where we are on the page;
321 input_position depends on where we are in the file.)
322 Important for converting tabs to spaces on input. */
323 static int input_position;
325 /* Count number of failed opens so we can exit with non-zero
326 status if there were any. */
327 static int failed_opens = 0;
329 /* The horizontal position we'll be at after printing a tab character
330 of width c_ from the position h_. */
331 #define pos_after_tab(c_, h_) h_ - h_ % c_ + c_
333 /* The number of spaces taken up if we print a tab character with width
334 c_ from position h_. */
335 #define tab_width(c_, h_) - h_ % c_ + c_
337 /* (-NNN) Number of columns of text to print. */
338 static int columns = 1;
340 /* (+NNN) Page number on which to begin printing. */
341 static int first_page_number = 1;
343 /* Number of files open (not closed, not on hold). */
344 static int files_ready_to_read = 0;
346 /* Current page number. Displayed in header. */
347 static int page_number;
349 /* Current line number. Displayed when -n flag is specified.
351 When printing files in parallel (-m flag), line numbering is as follows:
352 1 foo goo moo
353 2 hoo too zoo
355 When printing files across (-a flag), ...
356 1 foo 2 moo 3 goo
357 4 hoo 3 too 6 zoo
359 Otherwise, line numbering is as follows:
360 1 foo 3 goo 5 too
361 2 moo 4 hoo 6 zoo */
362 static int line_number;
364 /* (-n) True means lines should be preceded by numbers. */
365 static int numbered_lines = FALSE;
367 /* (-n) Character which follows each line number. */
368 static char number_separator = '\t';
370 /* (-n) Width in characters of a line number. */
371 static int chars_per_number = 5;
373 /* Used when widening the first column to accommodate numbers -- only
374 needed when printing files in parallel. Includes width of both the
375 number and the number_separator. */
376 static int number_width;
378 /* Buffer sprintf uses to format a line number. */
379 static char *number_buff;
381 /* (-v) True means unprintable characters are printed as escape sequences.
382 control-g becomes \007. */
383 static int use_esc_sequence = FALSE;
385 /* (-c) True means unprintable characters are printed as control prefixes.
386 control-g becomes ^G. */
387 static int use_cntrl_prefix = FALSE;
389 /* (-d) True means output is double spaced. */
390 static int double_space = FALSE;
392 /* Number of files opened initially in init_files. Should be 1
393 unless we're printing multiple files in parallel. */
394 static int total_files = 0;
396 /* (-r) True means don't complain if we can't open a file. */
397 static int ignore_failed_opens = FALSE;
399 /* (-s) True means we separate columns with a specified character. */
400 static int use_column_separator = FALSE;
402 /* Character used to separate columns if the the -s flag has been specified. */
403 static char column_separator = '\t';
405 /* Number of separator characters waiting to be printed as soon as we
406 know that we have any input remaining to be printed. */
407 static int separators_not_printed;
409 /* Position we need to pad to, as soon as we know that we have input
410 remaining to be printed. */
411 static int padding_not_printed;
413 /* True means we should pad the end of the page. Remains false until we
414 know we have a page to print. */
415 static int pad_vertically;
417 /* (-h) String of characters used in place of the filename in the header. */
418 static char *custom_header;
420 /* String containing the date, filename or custom header, and "Page ". */
421 static char *header;
423 static int *clump_buff;
425 /* True means we truncate lines longer than chars_per_column. */
426 static int truncate_lines = FALSE;
428 /* If non-zero, display usage information and exit. */
429 static int show_help;
431 /* If non-zero, print the version on standard output then exit. */
432 static int show_version;
434 static struct option const long_options[] =
436 {"help", no_argument, &show_help, 1},
437 {"version", no_argument, &show_version, 1},
438 {0, 0, 0, 0}
441 /* Return the number of columns that have either an open file or
442 stored lines. */
444 static int
445 cols_ready_to_print ()
447 COLUMN *q;
448 int i;
449 int n;
451 n = 0;
452 for (q = column_vector, i = 0; i < columns; ++q, ++i)
453 if (q->status == OPEN ||
454 (storing_columns && q->lines_stored > 0 && q->lines_to_print > 0))
455 ++n;
456 return n;
459 void
460 main (argc, argv)
461 int argc;
462 char **argv;
464 int c;
465 int accum = 0;
466 int n_files;
467 char **file_names;
469 program_name = argv[0];
471 n_files = 0;
472 file_names = (argc > 1
473 ? (char **) xmalloc ((argc - 1) * sizeof (char *))
474 : NULL);
476 while (1)
478 c = getopt_long (argc, argv,
479 "-0123456789abcde::fFh:i::l:mn::o:rs::tvw:",
480 long_options, (int *) 0);
481 if (c == 1) /* Non-option argument. */
483 char *s;
484 s = optarg;
485 if (*s == '+')
487 ++s;
488 if (!ISDIGIT (*s))
490 error (0, 0, "`+' requires a numeric argument");
491 usage ();
493 /* FIXME: use strtol */
494 first_page_number = atoi (s);
496 else
498 file_names[n_files++] = optarg;
501 else
503 if (ISDIGIT (c))
505 accum = accum * 10 + c - '0';
506 continue;
508 else
510 if (accum > 0)
512 columns = accum;
513 explicit_columns = TRUE;
514 accum = 0;
519 if (c == 1)
520 continue;
522 if (c == EOF)
523 break;
525 switch (c)
527 case 0: /* getopt long option */
528 break;
530 case 'a':
531 print_across_flag = TRUE;
532 storing_columns = FALSE;
533 break;
534 case 'b':
535 balance_columns = TRUE;
536 break;
537 case 'c':
538 use_cntrl_prefix = TRUE;
539 break;
540 case 'd':
541 double_space = TRUE;
542 break;
543 case 'e':
544 if (optarg)
545 getoptarg (optarg, 'e', &input_tab_char,
546 &chars_per_input_tab);
547 /* Could check tab width > 0. */
548 untabify_input = TRUE;
549 break;
550 case 'f':
551 case 'F':
552 use_form_feed = TRUE;
553 break;
554 case 'h':
555 custom_header = optarg;
556 standard_header = FALSE;
557 break;
558 case 'i':
559 if (optarg)
560 getoptarg (optarg, 'i', &output_tab_char,
561 &chars_per_output_tab);
562 /* Could check tab width > 0. */
563 tabify_output = TRUE;
564 break;
565 case 'l':
566 lines_per_page = atoi (optarg);
567 break;
568 case 'm':
569 parallel_files = TRUE;
570 storing_columns = FALSE;
571 break;
572 case 'n':
573 numbered_lines = TRUE;
574 if (optarg)
575 getoptarg (optarg, 'n', &number_separator,
576 &chars_per_number);
577 break;
578 case 'o':
579 chars_per_margin = atoi (optarg);
580 break;
581 case 'r':
582 ignore_failed_opens = TRUE;
583 break;
584 case 's':
585 use_column_separator = TRUE;
586 if (optarg)
588 char *s;
589 s = optarg;
590 column_separator = *s;
591 if (*++s)
593 fprintf (stderr, "\
594 %s: extra characters in the argument to the `-s' option: `%s'\n",
595 program_name, s);
596 usage ();
599 break;
600 case 't':
601 extremities = FALSE;
602 break;
603 case 'v':
604 use_esc_sequence = TRUE;
605 break;
606 case 'w':
607 chars_per_line = atoi (optarg);
608 break;
609 default:
610 usage ();
611 break;
615 if (show_version)
617 printf ("%s\n", version_string);
618 exit (0);
621 if (show_help)
622 usage ();
624 if (parallel_files && explicit_columns)
625 error (1, 0,
626 "Cannot specify number of columns when printing in parallel.");
628 if (parallel_files && print_across_flag)
629 error (1, 0,
630 "Cannot specify both printing across and printing in parallel.");
632 for ( ; optind < argc; optind++)
634 file_names[n_files++] = argv[optind];
637 if (n_files == 0)
639 /* No file arguments specified; read from standard input. */
640 print_files (0, (char **) 0);
642 else
644 if (parallel_files)
645 print_files (n_files, file_names);
646 else
648 int i;
649 for (i=0; i<n_files; i++)
650 print_files (1, &file_names[i]);
654 cleanup ();
656 if (have_read_stdin && fclose (stdin) == EOF)
657 error (1, errno, "standard input");
658 if (ferror (stdout) || fclose (stdout) == EOF)
659 error (1, errno, "write error");
660 if (failed_opens > 0)
661 exit(1);
662 exit (0);
665 /* Parse options of the form -scNNN.
667 Example: -nck, where 'n' is the option, c is the optional number
668 separator, and k is the optional width of the field used when printing
669 a number. */
671 static void
672 getoptarg (arg, switch_char, character, number)
673 char *arg, switch_char, *character;
674 int *number;
676 if (!ISDIGIT (*arg))
677 *character = *arg++;
678 if (*arg)
680 if (ISDIGIT (*arg))
681 *number = atoi (arg);
682 else
684 fprintf (stderr, "\
685 %s: extra characters in the argument to the `-%c' option: `%s'\n",
686 program_name, switch_char, arg);
687 usage ();
692 /* Set parameters related to formatting. */
694 static void
695 init_parameters (number_of_files)
696 int number_of_files;
698 int chars_used_by_number = 0;
700 lines_per_body = lines_per_page - lines_per_header - lines_per_footer;
701 if (lines_per_body <= 0)
702 extremities = FALSE;
703 if (extremities == FALSE)
704 lines_per_body = lines_per_page;
706 if (double_space)
707 lines_per_body = lines_per_body / 2;
709 /* If input is stdin, cannot print parallel files. BSD dumps core
710 on this. */
711 if (number_of_files == 0)
712 parallel_files = FALSE;
714 if (parallel_files)
715 columns = number_of_files;
717 /* Tabification is assumed for multiple columns. */
718 if (columns > 1)
720 if (!use_column_separator)
721 truncate_lines = TRUE;
723 untabify_input = TRUE;
724 tabify_output = TRUE;
726 else
727 storing_columns = FALSE;
729 if (numbered_lines)
731 if (number_separator == input_tab_char)
733 number_width = chars_per_number +
734 tab_width (chars_per_input_tab,
735 (chars_per_margin + chars_per_number));
737 else
738 number_width = chars_per_number + 1;
739 /* The number is part of the column width unless we are
740 printing files in parallel. */
741 if (parallel_files)
742 chars_used_by_number = number_width;
745 chars_per_column = (chars_per_line - chars_used_by_number -
746 (columns - 1) * chars_per_gutter) / columns;
748 if (chars_per_column < 1)
749 error (1, 0, "page width too narrow");
751 if (numbered_lines)
753 if (number_buff != (char *) 0)
754 free (number_buff);
755 number_buff = (char *)
756 xmalloc (2 * chars_per_number * sizeof (char));
759 /* Pick the maximum between the tab width and the width of an
760 escape sequence. */
761 if (clump_buff != (int *) 0)
762 free (clump_buff);
763 clump_buff = (int *) xmalloc ((chars_per_input_tab > 4
764 ? chars_per_input_tab : 4) * sizeof (int));
767 /* Open the necessary files,
768 maintaining a COLUMN structure for each column.
770 With multiple files, each column p has a different p->fp.
771 With single files, each column p has the same p->fp.
772 Return 1 if (number_of_files > 0) and no files can be opened,
773 0 otherwise. */
775 static int
776 init_fps (number_of_files, av)
777 int number_of_files;
778 char **av;
780 int i, files_left;
781 COLUMN *p;
782 FILE *firstfp;
783 char *firstname;
785 total_files = 0;
787 if (column_vector != NULLCOL)
788 free ((char *) column_vector);
789 column_vector = (COLUMN *) xmalloc (columns * sizeof (COLUMN));
791 if (parallel_files)
793 files_left = number_of_files;
794 for (p = column_vector; files_left--; ++p, ++av)
796 if (open_file (*av, p) == 0)
798 --p;
799 --columns;
802 if (columns == 0)
803 return 1;
804 init_header ("", -1);
806 else
808 p = column_vector;
809 if (number_of_files > 0)
811 if (open_file (*av, p) == 0)
812 return 1;
813 init_header (*av, fileno (p->fp));
815 else
817 p->name = "standard input";
818 p->fp = stdin;
819 have_read_stdin = TRUE;
820 p->status = OPEN;
821 ++total_files;
822 init_header ("", -1);
825 firstname = p->name;
826 firstfp = p->fp;
827 for (i = columns - 1, ++p; i; --i, ++p)
829 p->name = firstname;
830 p->fp = firstfp;
831 p->status = OPEN;
834 files_ready_to_read = total_files;
835 return 0;
838 /* Determine print_func and char_func, the functions
839 used by each column for printing and/or storing.
841 Determine the horizontal position desired when we begin
842 printing a column (p->start_position). */
844 static void
845 init_funcs ()
847 int i, h, h_next;
848 COLUMN *p;
850 h = chars_per_margin;
852 if (use_column_separator)
853 h_next = ANYWHERE;
854 else
856 /* When numbering lines of parallel files, we enlarge the
857 first column to accomodate the number. Looks better than
858 the Sys V approach. */
859 if (parallel_files && numbered_lines)
860 h_next = h + chars_per_column + number_width;
861 else
862 h_next = h + chars_per_column;
865 /* This loop takes care of all but the rightmost column. */
867 for (p = column_vector, i = 1; i < columns; ++p, ++i)
869 if (storing_columns) /* One file, multi columns down. */
871 p->char_func = store_char;
872 p->print_func = print_stored;
874 else
875 /* One file, multi columns across; or parallel files. */
877 p->char_func = print_char;
878 p->print_func = read_line;
881 /* Number only the first column when printing files in
882 parallel. */
883 p->numbered = numbered_lines && (!parallel_files || i == 1);
884 p->start_position = h;
886 /* If we're using separators, all start_positions are
887 ANYWHERE, except the first column's start_position when
888 using a margin. */
890 if (use_column_separator)
892 h = ANYWHERE;
893 h_next = ANYWHERE;
895 else
897 h = h_next + chars_per_gutter;
898 h_next = h + chars_per_column;
902 /* The rightmost column.
904 Doesn't need to be stored unless we intend to balance
905 columns on the last page. */
906 if (storing_columns && balance_columns)
908 p->char_func = store_char;
909 p->print_func = print_stored;
911 else
913 p->char_func = print_char;
914 p->print_func = read_line;
917 p->numbered = numbered_lines && (!parallel_files || i == 1);
918 p->start_position = h;
921 /* Open a file. Return nonzero if successful, zero if failed. */
923 static int
924 open_file (name, p)
925 char *name;
926 COLUMN *p;
928 if (!strcmp (name, "-"))
930 p->name = "standard input";
931 p->fp = stdin;
932 have_read_stdin = 1;
934 else
936 p->name = name;
937 p->fp = fopen (name, "r");
939 if (p->fp == NULL)
941 ++failed_opens;
942 if (!ignore_failed_opens)
943 error (0, errno, "%s", name);
944 return 0;
946 p->status = OPEN;
947 ++total_files;
948 return 1;
951 /* Close the file in P.
953 If we aren't dealing with multiple files in parallel, we change
954 the status of all columns in the column list to reflect the close. */
956 static void
957 close_file (p)
958 COLUMN *p;
960 COLUMN *q;
961 int i;
963 if (p->status == CLOSED)
964 return;
965 if (ferror (p->fp))
966 error (1, errno, "%s", p->name);
967 if (p->fp != stdin && fclose (p->fp) == EOF)
968 error (1, errno, "%s", p->name);
970 if (!parallel_files)
972 for (q = column_vector, i = columns; i; ++q, --i)
974 q->status = CLOSED;
975 if (q->lines_stored == 0)
977 q->lines_to_print = 0;
981 else
983 p->status = CLOSED;
984 p->lines_to_print = 0;
987 --files_ready_to_read;
990 /* Put a file on hold until we start a new page,
991 since we've hit a form feed.
993 If we aren't dealing with parallel files, we must change the
994 status of all columns in the column list. */
996 static void
997 hold_file (p)
998 COLUMN *p;
1000 COLUMN *q;
1001 int i;
1003 if (!parallel_files)
1004 for (q = column_vector, i = columns; i; ++q, --i)
1005 q->status = ON_HOLD;
1006 else
1007 p->status = ON_HOLD;
1008 p->lines_to_print = 0;
1009 --files_ready_to_read;
1012 /* Undo hold_file -- go through the column list and change any
1013 ON_HOLD columns to OPEN. Used at the end of each page. */
1015 static void
1016 reset_status ()
1018 int i = columns;
1019 COLUMN *p;
1021 for (p = column_vector; i; --i, ++p)
1022 if (p->status == ON_HOLD)
1024 p->status = OPEN;
1025 files_ready_to_read++;
1029 /* Print a single file, or multiple files in parallel.
1031 Set up the list of columns, opening the necessary files.
1032 Allocate space for storing columns, if necessary.
1033 Skip to first_page_number, if user has asked to skip leading pages.
1034 Determine which functions are appropriate to store/print lines
1035 in each column.
1036 Print the file(s). */
1038 static void
1039 print_files (number_of_files, av)
1040 int number_of_files;
1041 char **av;
1043 init_parameters (number_of_files);
1044 if (init_fps (number_of_files, av))
1045 return;
1046 if (storing_columns)
1047 init_store_cols ();
1049 if (first_page_number > 1)
1051 if (!skip_to_page (first_page_number))
1052 return;
1053 else
1054 page_number = first_page_number;
1056 else
1057 page_number = 1;
1059 init_funcs ();
1061 line_number = 1;
1062 while (print_page ())
1066 /* Generous estimate of number of characters taken up by "Jun 7 00:08 " and
1067 "Page NNNNN". */
1068 #define CHARS_FOR_DATE_AND_PAGE 50
1070 /* Initialize header information.
1071 If DESC is non-negative, it is a file descriptor open to
1072 FILENAME for reading.
1074 Allocate space for a header string,
1075 Determine the time, insert file name or user-specified string.
1077 It might be nice to have a "blank headers" option, since
1078 pr -h "" still prints the date and page number. */
1080 static void
1081 init_header (filename, desc)
1082 char *filename;
1083 int desc;
1085 int chars_per_header;
1086 char *f = filename;
1087 char *t, *middle;
1088 struct stat st;
1090 if (filename == 0)
1091 f = "";
1093 /* If parallel files or standard input, use current time. */
1094 if (desc < 0 || !strcmp (filename, "-") || fstat (desc, &st))
1095 st.st_mtime = time ((time_t *) 0);
1096 t = ctime (&st.st_mtime);
1098 t[16] = '\0'; /* Mark end of month and time string. */
1099 t[24] = '\0'; /* Mark end of year string. */
1101 middle = standard_header ? f : custom_header;
1103 chars_per_header = strlen (middle) + CHARS_FOR_DATE_AND_PAGE + 1;
1104 if (header != (char *) 0)
1105 free (header);
1106 header = (char *) xmalloc (chars_per_header * sizeof (char));
1108 sprintf (header, "%s %s %s Page", &t[4], &t[20], middle);
1111 /* Set things up for printing a page
1113 Scan through the columns ...
1114 Determine which are ready to print
1115 (i.e., which have lines stored or open files)
1116 Set p->lines_to_print appropriately
1117 (to p->lines_stored if we're storing, or lines_per_body
1118 if we're reading straight from the file)
1119 Keep track of this total so we know when to stop printing */
1121 static void
1122 init_page ()
1124 int j;
1125 COLUMN *p;
1127 if (storing_columns)
1129 store_columns ();
1130 for (j = columns - 1, p = column_vector; j; --j, ++p)
1132 p->lines_to_print = p->lines_stored;
1135 /* Last column. */
1136 if (balance_columns)
1138 p->lines_to_print = p->lines_stored;
1140 /* Since we're not balancing columns, we don't need to store
1141 the rightmost column. Read it straight from the file. */
1142 else
1144 if (p->status == OPEN)
1146 p->lines_to_print = lines_per_body;
1148 else
1149 p->lines_to_print = 0;
1152 else
1153 for (j = columns, p = column_vector; j; --j, ++p)
1154 if (p->status == OPEN)
1156 p->lines_to_print = lines_per_body;
1158 else
1159 p->lines_to_print = 0;
1162 /* Print one page.
1164 As long as there are lines left on the page and columns ready to print,
1165 Scan across the column list
1166 if the column has stored lines or the file is open
1167 pad to the appropriate spot
1168 print the column
1169 pad the remainder of the page with \n or \f as requested
1170 reset the status of all files -- any files which where on hold because
1171 of formfeeds are now put back into the lineup. */
1173 static int
1174 print_page ()
1176 int j;
1177 int lines_left_on_page;
1178 COLUMN *p;
1180 /* Used as an accumulator (with | operator) of successive values of
1181 pad_vertically. The trick is to set pad_vertically
1182 to zero before each run through the inner loop, then after that
1183 loop, it tells us whether a line was actually printed (whether a
1184 newline needs to be output -- or two for double spacing). But those
1185 values have to be accumulated (in pv) so we can invoke pad_down
1186 properly after the outer loop completes. */
1187 int pv;
1189 init_page ();
1191 if (cols_ready_to_print () == 0)
1192 return FALSE;
1194 if (extremities)
1195 print_a_header = TRUE;
1197 /* Don't pad unless we know a page was printed. */
1198 pad_vertically = FALSE;
1199 pv = FALSE;
1201 lines_left_on_page = lines_per_body;
1202 if (double_space)
1203 lines_left_on_page *= 2;
1205 while (lines_left_on_page > 0 && cols_ready_to_print () > 0)
1207 output_position = 0;
1208 spaces_not_printed = 0;
1209 separators_not_printed = 0;
1210 pad_vertically = FALSE;
1212 for (j = 1, p = column_vector; j <= columns; ++j, ++p)
1214 input_position = 0;
1215 if (p->lines_to_print > 0)
1217 padding_not_printed = p->start_position;
1219 if (!(p->print_func) (p))
1220 read_rest_of_line (p);
1221 pv |= pad_vertically;
1223 if (use_column_separator)
1224 ++separators_not_printed;
1226 --p->lines_to_print;
1227 if (p->lines_to_print <= 0)
1229 if (cols_ready_to_print () <= 0)
1230 break;
1235 if (pad_vertically)
1237 putchar ('\n');
1238 --lines_left_on_page;
1241 if (double_space && pv && extremities)
1243 putchar ('\n');
1244 --lines_left_on_page;
1248 pad_vertically = pv;
1250 if (pad_vertically && extremities)
1251 pad_down (lines_left_on_page + lines_per_footer);
1253 reset_status (); /* Change ON_HOLD to OPEN. */
1255 return TRUE; /* More pages to go. */
1258 /* Allocate space for storing columns.
1260 This is necessary when printing multiple columns from a single file.
1261 Lines are stored consecutively in buff, separated by '\0'.
1262 (We can't use a fixed offset since with the '-s' flag lines aren't
1263 truncated.)
1265 We maintain a list (line_vector) of pointers to the beginnings
1266 of lines in buff. We allocate one more than the number of lines
1267 because the last entry tells us the index of the last character,
1268 which we need to know in order to print the last line in buff. */
1270 static void
1271 init_store_cols ()
1273 int total_lines = lines_per_body * columns;
1274 int chars_if_truncate = total_lines * (chars_per_column + 1);
1276 if (line_vector != (int *) 0)
1277 free ((int *) line_vector);
1278 line_vector = (int *) xmalloc ((total_lines + 1) * sizeof (int *));
1280 if (end_vector != (int *) 0)
1281 free ((int *) end_vector);
1282 end_vector = (int *) xmalloc (total_lines * sizeof (int *));
1284 if (buff != (char *) 0)
1285 free (buff);
1286 buff_allocated = use_column_separator ? 2 * chars_if_truncate
1287 : chars_if_truncate; /* Tune this. */
1288 buff = (char *) xmalloc (buff_allocated * sizeof (char));
1291 /* Store all but the rightmost column.
1292 (Used when printing a single file in multiple downward columns)
1294 For each column
1295 set p->current_line to be the index in line_vector of the
1296 first line in the column
1297 For each line in the column
1298 store the line in buff
1299 add to line_vector the index of the line's first char
1300 buff_start is the index in buff of the first character in the
1301 current line. */
1303 static void
1304 store_columns ()
1306 int i, j;
1307 int line = 0;
1308 int buff_start;
1309 int last_col; /* The rightmost column which will be saved in buff */
1310 COLUMN *p;
1312 buff_current = 0;
1313 buff_start = 0;
1315 if (balance_columns)
1316 last_col = columns;
1317 else
1318 last_col = columns - 1;
1320 for (i = 1, p = column_vector; i <= last_col; ++i, ++p)
1321 p->lines_stored = 0;
1323 for (i = 1, p = column_vector; i <= last_col && files_ready_to_read;
1324 ++i, ++p)
1326 p->current_line = line;
1327 for (j = lines_per_body; j && files_ready_to_read; --j)
1329 if (p->status == OPEN) /* Redundant. Clean up. */
1331 input_position = 0;
1333 if (!read_line (p, i))
1334 read_rest_of_line (p);
1336 if (p->status == OPEN
1337 || buff_start != buff_current)
1339 ++p->lines_stored;
1340 line_vector[line] = buff_start;
1341 end_vector[line++] = input_position;
1342 buff_start = buff_current;
1347 /* Keep track of the location of the last char in buff. */
1348 line_vector[line] = buff_start;
1350 if (balance_columns && p->lines_stored != lines_per_body)
1351 balance (line);
1354 static void
1355 balance (total_stored)
1356 int total_stored;
1358 COLUMN *p;
1359 int i, lines;
1360 int first_line = 0;
1362 for (i = 1, p = column_vector; i <= columns; ++i, ++p)
1364 lines = total_stored / columns;
1365 if (i <= total_stored % columns)
1366 ++lines;
1368 p->lines_stored = lines;
1369 p->current_line = first_line;
1371 first_line += lines;
1375 /* Store a character in the buffer. */
1377 static void
1378 store_char (c)
1379 int c;
1381 if (buff_current >= buff_allocated)
1383 /* May be too generous. */
1384 buff_allocated = 2 * buff_allocated;
1385 buff = (char *) xrealloc (buff, buff_allocated * sizeof (char));
1387 buff[buff_current++] = (char) c;
1390 static void
1391 number (p)
1392 COLUMN *p;
1394 int i;
1395 char *s;
1397 sprintf (number_buff, "%*d", chars_per_number, line_number++);
1398 s = number_buff;
1399 for (i = chars_per_number; i > 0; i--)
1400 (p->char_func) ((int) *s++);
1402 if (number_separator == input_tab_char)
1404 i = number_width - chars_per_number;
1405 while (i-- > 0)
1406 (p->char_func) ((int) ' ');
1408 else
1409 (p->char_func) ((int) number_separator);
1411 if (truncate_lines && !parallel_files)
1412 input_position += number_width;
1415 /* Print (or store) padding until the current horizontal position
1416 is position. */
1418 static void
1419 pad_across_to (position)
1420 int position;
1422 register int h = output_position;
1424 if (tabify_output)
1425 spaces_not_printed = position - output_position;
1426 else
1428 while (++h <= position)
1429 putchar (' ');
1430 output_position = position;
1434 /* Pad to the bottom of the page.
1436 If the user has requested a formfeed, use one.
1437 Otherwise, use newlines. */
1439 static void
1440 pad_down (lines)
1441 int lines;
1443 register int i;
1445 if (use_form_feed)
1446 putchar ('\f');
1447 else
1448 for (i = lines; i; --i)
1449 putchar ('\n');
1452 /* Read the rest of the line.
1454 Read from the current column's file until an end of line is
1455 hit. Used when we've truncated a line and we no longer need
1456 to print or store its characters. */
1458 static void
1459 read_rest_of_line (p)
1460 COLUMN *p;
1462 register int c;
1463 FILE *f = p->fp;
1465 while ((c = getc (f)) != '\n')
1467 if (c == '\f')
1469 hold_file (p);
1470 break;
1472 else if (c == EOF)
1474 close_file (p);
1475 break;
1480 /* If we're tabifying output,
1482 When print_char encounters white space it keeps track
1483 of our desired horizontal position and delays printing
1484 until this function is called. */
1486 static void
1487 print_white_space ()
1489 register int h_new;
1490 register int h_old = output_position;
1491 register int goal = h_old + spaces_not_printed;
1493 while (goal - h_old > 1
1494 && (h_new = pos_after_tab (chars_per_output_tab, h_old)) <= goal)
1496 putchar (output_tab_char);
1497 h_old = h_new;
1499 while (++h_old <= goal)
1500 putchar (' ');
1502 output_position = goal;
1503 spaces_not_printed = 0;
1506 /* Print column separators.
1508 We keep a count until we know that we'll be printing a line,
1509 then print_separators() is called. */
1511 static void
1512 print_separators ()
1514 for (; separators_not_printed > 0; --separators_not_printed)
1515 print_char (column_separator);
1518 /* Print (or store, depending on p->char_func) a clump of N
1519 characters. */
1521 static void
1522 print_clump (p, n, clump)
1523 COLUMN *p;
1524 int n;
1525 int *clump;
1527 while (n--)
1528 (p->char_func) (*clump++);
1531 /* Print a character.
1533 If we're tabifying, all tabs have been converted to spaces by
1534 process_char(). Keep a count of consecutive spaces, and when
1535 a nonspace is encountered, call print_white_space() to print the
1536 required number of tabs and spaces. */
1538 static void
1539 print_char (c)
1540 int c;
1542 if (tabify_output)
1544 if (c == ' ')
1546 ++spaces_not_printed;
1547 return;
1549 else if (spaces_not_printed > 0)
1550 print_white_space ();
1552 /* Nonprintables are assumed to have width 0, except '\b'. */
1553 if (!ISPRINT (c))
1555 if (c == '\b')
1556 --output_position;
1558 else
1559 ++output_position;
1561 putchar (c);
1564 /* Skip to page PAGE before printing. */
1566 static int
1567 skip_to_page (page)
1568 int page;
1570 int n, i, j;
1571 COLUMN *p;
1573 for (n = 1; n < page; ++n)
1575 for (i = 1; i <= lines_per_body; ++i)
1577 for (j = 1, p = column_vector; j <= columns; ++j, ++p)
1578 read_rest_of_line (p);
1580 reset_status ();
1582 return files_ready_to_read > 0;
1585 /* Print a header.
1587 Formfeeds are assumed to use up two lines at the beginning of
1588 the page. */
1590 static void
1591 print_header ()
1593 if (!use_form_feed)
1594 fprintf (stdout, "\n\n");
1596 output_position = 0;
1597 pad_across_to (chars_per_margin);
1598 print_white_space ();
1600 fprintf (stdout, "%s %d\n\n\n", header, page_number++);
1602 print_a_header = FALSE;
1603 output_position = 0;
1606 /* Print (or store, if p->char_func is store_char()) a line.
1608 Read a character to determine whether we have a line or not.
1609 (We may hit EOF, \n, or \f)
1611 Once we know we have a line,
1612 set pad_vertically = TRUE, meaning it's safe
1613 to pad down at the end of the page, since we do have a page.
1614 print a header if needed.
1615 pad across to padding_not_printed if needed.
1616 print any separators which need to be printed.
1617 print a line number if it needs to be printed.
1619 Print the clump which corresponds to the first character.
1621 Enter a loop and keep printing until an end of line condition
1622 exists, or until we exceed chars_per_column.
1624 Return FALSE if we exceed chars_per_column before reading
1625 an end of line character, TRUE otherwise. */
1627 static int
1628 read_line (p)
1629 COLUMN *p;
1631 register int c, chars;
1632 int last_input_position;
1634 c = getc (p->fp);
1636 last_input_position = input_position;
1637 switch (c)
1639 case '\f':
1640 hold_file (p);
1641 return TRUE;
1642 case EOF:
1643 close_file (p);
1644 return TRUE;
1645 case '\n':
1646 break;
1647 default:
1648 chars = char_to_clump (c);
1651 if (truncate_lines && input_position > chars_per_column)
1653 input_position = last_input_position;
1654 return FALSE;
1657 if (p->char_func != store_char)
1659 pad_vertically = TRUE;
1661 if (print_a_header)
1662 print_header ();
1664 if (padding_not_printed != ANYWHERE)
1666 pad_across_to (padding_not_printed);
1667 padding_not_printed = ANYWHERE;
1670 if (use_column_separator)
1671 print_separators ();
1674 if (p->numbered)
1675 number (p);
1677 if (c == '\n')
1678 return TRUE;
1680 print_clump (p, chars, clump_buff);
1682 for (;;)
1684 c = getc (p->fp);
1686 switch (c)
1688 case '\n':
1689 return TRUE;
1690 case '\f':
1691 hold_file (p);
1692 return TRUE;
1693 case EOF:
1694 close_file (p);
1695 return TRUE;
1698 last_input_position = input_position;
1699 chars = char_to_clump (c);
1700 if (truncate_lines && input_position > chars_per_column)
1702 input_position = last_input_position;
1703 return FALSE;
1706 print_clump (p, chars, clump_buff);
1710 /* Print a line from buff.
1712 If this function has been called, we know we have something to
1713 print. Therefore we set pad_vertically to TRUE, print
1714 a header if necessary, pad across if necessary, and print
1715 separators if necessary.
1717 Return TRUE, meaning there is no need to call read_rest_of_line. */
1719 static int
1720 print_stored (p)
1721 COLUMN *p;
1723 int line = p->current_line++;
1724 register char *first = &buff[line_vector[line]];
1725 register char *last = &buff[line_vector[line + 1]];
1727 pad_vertically = TRUE;
1729 if (print_a_header)
1730 print_header ();
1732 if (padding_not_printed != ANYWHERE)
1734 pad_across_to (padding_not_printed);
1735 padding_not_printed = ANYWHERE;
1738 if (use_column_separator)
1739 print_separators ();
1741 while (first != last)
1742 print_char (*first++);
1744 if (spaces_not_printed == 0)
1745 output_position = p->start_position + end_vector[line];
1747 return TRUE;
1750 /* Convert a character to the proper format and return the number of
1751 characters in the resulting clump. Increment input_position by
1752 the width of the clump.
1754 Tabs are converted to clumps of spaces.
1755 Nonprintable characters may be converted to clumps of escape
1756 sequences or control prefixes.
1758 Note: the width of a clump is not necessarily equal to the number of
1759 characters in clump_buff. (e.g, the width of '\b' is -1, while the
1760 number of characters is 1.) */
1762 static int
1763 char_to_clump (c)
1764 int c;
1766 register int *s = clump_buff;
1767 register int i;
1768 char esc_buff[4];
1769 int width;
1770 int chars;
1772 if (c == input_tab_char)
1774 width = tab_width (chars_per_input_tab, input_position);
1776 if (untabify_input)
1778 for (i = width; i; --i)
1779 *s++ = ' ';
1780 chars = width;
1782 else
1784 *s = c;
1785 chars = 1;
1789 else if (!ISPRINT (c))
1791 if (use_esc_sequence)
1793 width = 4;
1794 chars = 4;
1795 *s++ = '\\';
1796 sprintf (esc_buff, "%03o", c);
1797 for (i = 0; i <= 2; ++i)
1798 *s++ = (int) esc_buff[i];
1800 else if (use_cntrl_prefix)
1802 if (c < 0200)
1804 width = 2;
1805 chars = 2;
1806 *s++ = '^';
1807 *s++ = c ^ 0100;
1809 else
1811 width = 4;
1812 chars = 4;
1813 *s++ = '\\';
1814 sprintf (esc_buff, "%03o", c);
1815 for (i = 0; i <= 2; ++i)
1816 *s++ = (int) esc_buff[i];
1819 else if (c == '\b')
1821 width = -1;
1822 chars = 1;
1823 *s = c;
1825 else
1827 width = 0;
1828 chars = 1;
1829 *s = c;
1832 else
1834 width = 1;
1835 chars = 1;
1836 *s = c;
1839 input_position += width;
1840 return chars;
1843 /* We've just printed some files and need to clean up things before
1844 looking for more options and printing the next batch of files.
1846 Free everything we've xmalloc'ed, except `header'. */
1848 static void
1849 cleanup ()
1851 if (number_buff)
1852 free (number_buff);
1853 if (clump_buff)
1854 free (clump_buff);
1855 if (column_vector)
1856 free (column_vector);
1857 if (line_vector)
1858 free (line_vector);
1859 if (end_vector)
1860 free (end_vector);
1861 if (buff)
1862 free (buff);
1865 /* Complain, print a usage message, and die. */
1867 static void
1868 usage ()
1870 fprintf (stderr, "\
1871 Usage: %s [+PAGE] [-COLUMN] [-abcdfFmrtv] [-e[in-tab-char[in-tab-width]]]\n\
1872 [-h header] [-i[out-tab-char[out-tab-width]]] [-l page-length]\n\
1873 [-n[number-separator[digits]]] [-o left-margin]\n\
1874 [-s[column-separator]] [-w page-width] [--help] [--version] [file...]\n",
1875 program_name);
1876 exit (2);