source: trunk/coreutils/src/pr.c@ 2603

Last change on this file since 2603 was 2554, checked in by bird, 20 years ago

coretuils-5.94

File size: 78.4 KB
Line 
1/* pr -- convert text files for printing.
2 Copyright (C) 88, 91, 1995-2005 Free Software Foundation, Inc.
3
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.
8
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.
13
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 Foundation,
16 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
17
18/* By Pete TerMaat, with considerable refinement by Roland Huebner. */
19
20
21/* Things to watch: Sys V screws up on ...
22 pr -n -3 -s: /usr/dict/words
23 pr -m -o10 -n /usr/dict/words{,,,}
24 pr -6 -a -n -o5 /usr/dict/words
25
26 Ideas:
27
28 Keep a things_to_do list of functions to call when we know we have
29 something to print. Cleaner than current series of checks.
30
31 Improve the printing of control prefixes.
32
33 Expand the file name in the centered header line to a full file name.
34
35
36 Concept:
37
38 If the input_tab_char differs from the default value TAB
39 (`-e[CHAR[...]]' is used), any input text tab is expanded to the
40 default width of 8 spaces (compare char_to_clump). - Same as SunOS
41 does.
42
43 The treatment of the number_separator (compare add_line_number):
44 The default value TAB of the number_separator (`-n[SEP[...]]') doesn't
45 be thought to be an input character. An optional `-e'-input has no
46 effect.
47 - With single column output
48 only one POSIX requirement has to be met:
49 The default n-separator should be a TAB. The consequence is a
50 different width between the number and the text if the output position
51 of the separator changes, i.e. it depends upon the left margin used.
52 That's not nice but easy-to-use together with the defaults of other
53 utilities, e.g. sort or cut. - Same as SunOS does.
54 - With multicolumn output
55 two conflicting POSIX requirements exist:
56 First `default n-separator is TAB', second `output text columns shall
57 be of equal width'. Moreover POSIX specifies the number+separator a
58 part of the column, together with `-COLUMN' and `-a -COLUMN'.
59 (With -m output the number shall occupy each line only once. Exactly
60 the same situation as single column output exists.)
61 GNU pr gives priority to the 2nd requirement and observes POSIX
62 column definition. The n-separator TAB is expanded to the same number
63 of spaces in each column using the default value 8. Tabification is
64 only performed if it is compatible with the output position.
65 Consequence: The output text columns are of equal width. The layout
66 of a page does not change if the left margin varies. - Looks better
67 than the SunOS approach.
68 SunOS pr gives priority to the 1st requirement. n-separator TAB
69 width varies with each column. Only the width of text part of the
70 column is fixed.
71 Consequence: The output text columns don't have equal width. The
72 widths and the layout of the whole page varies with the left margin.
73 An overflow of the line length (without margin) over the input value
74 PAGE_WIDTH may occur.
75
76 The interference of the POSIX-compliant small letter options -w and -s:
77 (`interference' means `setting a _separator_ with -s switches off the
78 column sturctur and the default - not generally - page_width,
79 acts on -w option')
80 options: text form / separator: equivalent new options:
81 -w l -s[x]
82 --------------------------------------------------------------------
83 1. -- -- columns / space --
84 trunc. to page_width = 72
85 2. -- -s[:] full lines / TAB[:] -J --sep-string[="<TAB>"|:]
86 no truncation
87 3. -w l -- columns / space -W l
88 trunc. to page_width = l
89 4. -w l -s[:] columns / no sep.[:] -W l --sep-string[=:]
90 trunc. to page_width = l
91 --------------------------------------------------------------------
92
93
94 Options:
95
96 Including version 1.22i:
97 Some SMALL LETTER options has been redefined with the object of a
98 better POSIX compliance. The output of some further cases has been
99 adapted to other UNIXes. A violation of downward compatibility has to
100 be accepted.
101 Some NEW CAPITAL LETTER options ( -J, -S, -W) has been introduced to
102 turn off unexpected interferences of small letter options (-s and -w
103 together with the three column options).
104 -N option and the second argument LAST_PAGE of +FIRST_PAGE offer more
105 flexibility; The detailed handling of form feeds set in the input
106 files requires -T option.
107
108 Capital letter options dominate small letter ones.
109
110 Some of the option-arguments cannot be specified as separate arguments
111 from the preceding option letter (already stated in POSIX specification).
112
113 Form feeds in the input cause page breaks in the output. Multiple
114 form feeds produce empty pages.
115
116 +FIRST_PAGE[:LAST_PAGE], --pages=FIRST_PAGE[:LAST_PAGE]
117 begin [stop] printing with page FIRST_[LAST_]PAGE
118
119 -COLUMN, --columns=COLUMN
120 Produce output that is COLUMN columns wide and
121 print columns down, unless -a is used. Balance number of
122 lines in the columns on each page.
123
124 -a, --across Print columns across rather than down, used
125 together with -COLUMN. The input
126 one
127 two
128 three
129 four
130 will be printed with `-a -3' as
131 one two three
132 four
133
134 -b Balance columns on the last page.
135 -b is no longer an independent option. It's always used
136 together with -COLUMN (unless -a is used) to get a
137 consistent formulation with "FF set by hand" in input
138 files. Each formfeed found terminates the number of lines
139 to be read with the actual page. The situation for
140 printing columns down is equivalent to that on the last
141 page. So we need a balancing.
142
143 Keeping -b as an underground option guarantees some
144 downward compatibility. Utilities using pr with -b
145 (a most frequently used form) still work as usual.
146
147 -c, --show-control-chars
148 Print unprintable characters as control prefixes.
149 Control-g is printed as ^G (use hat notation) and
150 octal backslash notation.
151
152 -d, --double-space Double space the output.
153
154 -D FORMAT, --date-format=FORMAT Use FORMAT for the header date.
155
156 -e[CHAR[WIDTH]], --expand-tabs[=CHAR[WIDTH]]
157 Expand tabs to spaces on input. Optional argument CHAR
158 is the input TAB character. (Default is TAB). Optional
159 argument WIDTH is the input TAB character's width.
160 (Default is 8.)
161
162 -F, -f, --form-feed Use formfeeds instead of newlines to separate
163 pages. A three line HEADER is used, no TRAILER with -F,
164 without -F both HEADER and TRAILER are made of five lines.
165
166 -h HEADER, --header=HEADER
167 Replace the filename in the header with the string HEADER.
168 A centered header is used.
169
170 -i[CHAR[WIDTH]], --output-tabs[=CHAR[WIDTH]]
171 Replace spaces with tabs on output. Optional argument
172 CHAR is the output TAB character. (Default is TAB).
173 Optional argument WIDTH is the output TAB character's
174 width. (Default is 8)
175
176 -J, --join-lines Merge lines of full length, turns off -W/-w
177 line truncation, no column alignment, --sep-string[=STRING]
178 sets separators, works with all column options
179 (-COLUMN | -a -COLUMN | -m).
180 -J has been introduced (together with -W and --sep-string) to
181 disentangle the old (POSIX compliant) options -w, -s
182 along with the 3 column options.
183
184 -l PAGE_LENGTH, --length=PAGE_LENGTH
185 Set the page length to PAGE_LENGTH lines. Default is 66,
186 including 5 lines of HEADER and 5 lines of TRAILER
187 without -F, but only 3 lines of HEADER and no TRAILER
188 with -F (i.e the number of text lines defaults to 56 or
189 63 respectively).
190
191 -m, --merge Print files in parallel; pad_across_to align
192 columns; truncate lines and print separator strings;
193 Do it also with empty columns to get a continuous line
194 numbering and column marking by separators throughout
195 the whole merged file.
196
197 Empty pages in some input files produce empty columns
198 [marked by separators] in the merged pages. Completely
199 empty merged pages show no column separators at all.
200
201 The layout of a merged page is ruled by the largest form
202 feed distance of the single pages at that page. Shorter
203 columns will be filled up with empty lines.
204
205 Together with -J option join lines of full length and
206 set separators when -S option is used.
207
208 -n[SEP[DIGITS]], --number-lines[=SEP[DIGITS]]
209 Provide DIGITS digit line numbering (default for DIGITS
210 is 5). With multicolumn output the number occupies the
211 first DIGITS column positions of each text column or only
212 each line of -m output.
213 With single column output the number precedes each line
214 just as -m output.
215 Optional argument SEP is the character appended to the
216 line number to separate it from the text followed.
217 The default separator is a TAB. In a strict sense a TAB
218 is always printed with single column output only. The
219 TAB-width varies with the TAB-position, e.g. with the
220 left margin specified by -o option.
221 With multicolumn output priority is given to `equal width
222 of output columns' (a POSIX specification). The TAB-width
223 is fixed to the value of the 1st column and does not
224 change with different values of left margin. That means a
225 fixed number of spaces is always printed in the place of
226 a TAB. The tabification depends upon the output
227 position.
228
229 Default counting of the line numbers starts with 1st
230 line of the input file (not the 1st line printed,
231 compare the --page option and -N option).
232
233 -N NUMBER, --first-line-number=NUMBER
234 Start line counting with the number NUMBER at the 1st
235 line of first page printed (mostly not the 1st line of
236 the input file).
237
238 -o MARGIN, --indent=MARGIN
239 Offset each line with a margin MARGIN spaces wide.
240 Total page width is the size of the margin plus the
241 PAGE_WIDTH set with -W/-w option.
242
243 -r, --no-file-warnings
244 Omit warning when a file cannot be opened.
245
246 -s[CHAR], --separator[=CHAR]
247 Separate columns by a single character CHAR, default for
248 CHAR is the TAB character without -w and 'no char' with -w.
249 Without `-s' default separator `space' is set.
250 -s[CHAR] turns off line truncation of all 3 column options
251 (-COLUMN|-a -COLUMN|-m) except -w is set. That is a POSIX
252 compliant formulation. The source code translates -s into
253 the new options -S and -J, also -W if required.
254
255 -S STRING, --sep-string[=STRING]
256 Separate columns by any string STRING. The -S option
257 doesn't react upon the -W/-w option (unlike -s option
258 does). It defines a separator nothing else.
259 Without -S: Default separator TAB is used with -J and
260 `space' otherwise (same as -S" ").
261 With -S "": No separator is used.
262 Quotes should be used with blanks and some shell active
263 characters.
264 -S is problematic because in its obsolete form you
265 cannot use -S "STRING", but in its standard form you
266 must use -S "STRING" if STRING is empty. Use
267 --sep-string to avoid the ambiguity.
268
269 -t, --omit-header Do not print headers or footers but retain form
270 feeds set in the input files.
271
272 -T, --omit-pagination
273 Do not print headers or footers, eliminate any pagination
274 by form feeds set in the input files.
275
276 -v, --show-nonprinting
277 Print unprintable characters as escape sequences. Use
278 octal backslash notation. Control-G becomes \007.
279
280 -w PAGE_WIDTH, --width=PAGE_WIDTH
281 Set page width to PAGE_WIDTH characters for multiple
282 text-column output only (default for PAGE_WIDTH is 72).
283 -s[CHAR] turns off the default page width and any line
284 truncation. Lines of full length will be merged,
285 regardless of the column options set. A POSIX compliant
286 formulation.
287
288 -W PAGE_WIDTH, --page-width=PAGE_WIDTH
289 Set the page width to PAGE_WIDTH characters. That's valid
290 with and without a column option. Text lines will be
291 truncated, unless -J is used. Together with one of the
292 column options (-COLUMN| -a -COLUMN| -m) column alignment
293 is always used.
294 Default is 72 characters.
295 Without -W PAGE_WIDTH
296 - but with one of the column options default truncation of
297 72 characters is used (to keep downward compatibility
298 and to simplify most frequently met column tasks).
299 Column alignment and column separators are used.
300 - and without any of the column options NO line truncation
301 is used (to keep downward compatibility and to meet most
302 frequent tasks). That's equivalent to -W 72 -J .
303
304 With/without -W PAGE_WIDTH the header line is always
305 truncated to avoid line overflow.
306
307 (In pr versions newer than 1.14 -S option does no longer
308 affect -W option.)
309
310*/
311
312
313
314#include <config.h>
315
316#include <getopt.h>
317#include <sys/types.h>
318#include "system.h"
319#include "error.h"
320#include "hard-locale.h"
321#include "inttostr.h"
322#include "mbswidth.h"
323#include "quote.h"
324#include "stat-time.h"
325#include "stdio--.h"
326#include "strftime.h"
327#include "xstrtol.h"
328
329/* The official name of this program (e.g., no `g' prefix). */
330#define PROGRAM_NAME "pr"
331
332#define AUTHORS "Pete TerMaat", "Roland Huebner"
333
334/* Used with start_position in the struct COLUMN described below.
335 If start_position == ANYWHERE, we aren't truncating columns and
336 can begin printing a column anywhere. Otherwise we must pad to
337 the horizontal position start_position. */
338#define ANYWHERE 0
339
340/* Each column has one of these structures allocated for it.
341 If we're only dealing with one file, fp is the same for all
342 columns.
343
344 The general strategy is to spend time setting up these column
345 structures (storing columns if necessary), after which printing
346 is a matter of flitting from column to column and calling
347 print_func.
348
349 Parallel files, single files printing across in multiple
350 columns, and single files printing down in multiple columns all
351 fit the same printing loop.
352
353 print_func Function used to print lines in this column.
354 If we're storing this column it will be
355 print_stored(), Otherwise it will be read_line().
356
357 char_func Function used to process characters in this column.
358 If we're storing this column it will be store_char(),
359 otherwise it will be print_char().
360
361 current_line Index of the current entry in line_vector, which
362 contains the index of the first character of the
363 current line in buff[].
364
365 lines_stored Number of lines in this column which are stored in
366 buff.
367
368 lines_to_print If we're storing this column, lines_to_print is
369 the number of stored_lines which remain to be
370 printed. Otherwise it is the number of lines
371 we can print without exceeding lines_per_body.
372
373 start_position The horizontal position we want to be in before we
374 print the first character in this column.
375
376 numbered True means precede this column with a line number. */
377
378/* FIXME: There are many unchecked integer overflows in this file,
379 that will cause this command to misbehave given large inputs or
380 options. Many of the "int" values below should be "size_t" or
381 something else like that. */
382
383struct COLUMN;
384struct COLUMN
385 {
386 FILE *fp; /* Input stream for this column. */
387 char const *name; /* File name. */
388 enum
389 {
390 OPEN,
391 FF_FOUND, /* used with -b option, set with \f, changed
392 to ON_HOLD after print_header */
393 ON_HOLD, /* Hit a form feed. */
394 CLOSED
395 }
396 status; /* Status of the file pointer. */
397
398 /* Func to print lines in this col. */
399 bool (*print_func) (struct COLUMN *);
400
401 /* Func to print/store chars in this col. */
402 void (*char_func) (char);
403
404 int current_line; /* Index of current place in line_vector. */
405 int lines_stored; /* Number of lines stored in buff. */
406 int lines_to_print; /* No. lines stored or space left on page. */
407 int start_position; /* Horizontal position of first char. */
408 bool numbered;
409 bool full_page_printed; /* True means printed without a FF found. */
410
411 /* p->full_page_printed controls a special case of "FF set by hand":
412 True means a full page has been printed without FF found. To avoid an
413 additional empty page we have to ignore a FF immediately following in
414 the next line. */
415 };
416
417typedef struct COLUMN COLUMN;
418
419#define NULLCOL (COLUMN *)0
420
421static int char_to_clump (char c);
422static bool read_line (COLUMN *p);
423static bool print_page (void);
424static bool print_stored (COLUMN *p);
425static bool open_file (char *name, COLUMN *p);
426static bool skip_to_page (uintmax_t page);
427static void print_header (void);
428static void pad_across_to (int position);
429static void add_line_number (COLUMN *p);
430static void getoptarg (char *arg, char switch_char, char *character,
431 int *number);
432void usage (int status);
433static void print_files (int number_of_files, char **av);
434static void init_parameters (int number_of_files);
435static void init_header (char *filename, int desc);
436static bool init_fps (int number_of_files, char **av);
437static void init_funcs (void);
438static void init_store_cols (void);
439static void store_columns (void);
440static void balance (int total_stored);
441static void store_char (char c);
442static void pad_down (int lines);
443static void read_rest_of_line (COLUMN *p);
444static void skip_read (COLUMN *p, int column_number);
445static void print_char (char c);
446static void cleanup (void);
447static void print_sep_string (void);
448static void separator_string (const char *optarg_S);
449
450/* The name under which this program was invoked. */
451char *program_name;
452
453/* All of the columns to print. */
454static COLUMN *column_vector;
455
456/* When printing a single file in multiple downward columns,
457 we store the leftmost columns contiguously in buff.
458 To print a line from buff, get the index of the first character
459 from line_vector[i], and print up to line_vector[i + 1]. */
460static char *buff;
461
462/* Index of the position in buff where the next character
463 will be stored. */
464static int buff_current;
465
466/* The number of characters in buff.
467 Used for allocation of buff and to detect overflow of buff. */
468static size_t buff_allocated;
469
470/* Array of indices into buff.
471 Each entry is an index of the first character of a line.
472 This is used when storing lines to facilitate shuffling when
473 we do column balancing on the last page. */
474static int *line_vector;
475
476/* Array of horizonal positions.
477 For each line in line_vector, end_vector[line] is the horizontal
478 position we are in after printing that line. We keep track of this
479 so that we know how much we need to pad to prepare for the next
480 column. */
481static int *end_vector;
482
483/* (-m) True means we're printing multiple files in parallel. */
484static bool parallel_files = false;
485
486/* (-m) True means a line starts with some empty columns (some files
487 already CLOSED or ON_HOLD) which we have to align. */
488static bool align_empty_cols;
489
490/* (-m) True means we have not yet found any printable column in a line.
491 align_empty_cols = true has to be maintained. */
492static bool empty_line;
493
494/* (-m) False means printable column output precedes a form feed found.
495 Column alignment is done only once. No additional action with that form
496 feed.
497 True means we found only a form feed in a column. Maybe we have to do
498 some column alignment with that form feed. */
499static bool FF_only;
500
501/* (-[0-9]+) True means we're given an option explicitly specifying
502 number of columns. Used to detect when this option is used with -m
503 and when translating old options to new/long options. */
504static bool explicit_columns = false;
505
506/* (-t|-T) False means we aren't printing headers and footers. */
507static bool extremities = true;
508
509/* (-t) True means we retain all FF set by hand in input files.
510 False is set with -T option. */
511static bool keep_FF = false;
512static bool print_a_FF = false;
513
514/* True means we need to print a header as soon as we know we've got input
515 to print after it. */
516static bool print_a_header;
517
518/* (-f) True means use formfeeds instead of newlines to separate pages. */
519static bool use_form_feed = false;
520
521/* True means we have read the standard input. */
522static bool have_read_stdin = false;
523
524/* True means the -a flag has been given. */
525static bool print_across_flag = false;
526
527/* True means we're printing one file in multiple (>1) downward columns. */
528static bool storing_columns = true;
529
530/* (-b) True means balance columns on the last page as Sys V does. */
531/* That's no longer an independent option. With storing_columns = true
532 balance_columns = true is used too (s. function init_parameters).
533 We get a consistent formulation with "FF set by hand" in input files. */
534static bool balance_columns = false;
535
536/* (-l) Number of lines on a page, including header and footer lines. */
537static int lines_per_page = 66;
538
539/* Number of lines in the header and footer can be reset to 0 using
540 the -t flag. */
541static int lines_per_header = 5;
542static int lines_per_body;
543static int lines_per_footer = 5;
544
545/* (-w|-W) Width in characters of the page. Does not include the width of
546 the margin. */
547static int chars_per_line = 72;
548
549/* (-w|W) True means we truncate lines longer than chars_per_column. */
550static bool truncate_lines = false;
551
552/* (-J) True means we join lines without any line truncation. -J
553 dominates -w option. */
554static bool join_lines = false;
555
556/* Number of characters in a column. Based on col_sep_length and
557 page width. */
558static int chars_per_column;
559
560/* (-e) True means convert tabs to spaces on input. */
561static bool untabify_input = false;
562
563/* (-e) The input tab character. */
564static char input_tab_char = '\t';
565
566/* (-e) Tabstops are at chars_per_tab, 2*chars_per_tab, 3*chars_per_tab, ...
567 where the leftmost column is 1. */
568static int chars_per_input_tab = 8;
569
570/* (-i) True means convert spaces to tabs on output. */
571static bool tabify_output = false;
572
573/* (-i) The output tab character. */
574static char output_tab_char = '\t';
575
576/* (-i) The width of the output tab. */
577static int chars_per_output_tab = 8;
578
579/* Keeps track of pending white space. When we hit a nonspace
580 character after some whitespace, we print whitespace, tabbing
581 if necessary to get to output_position + spaces_not_printed. */
582static int spaces_not_printed;
583
584/* (-o) Number of spaces in the left margin (tabs used when possible). */
585static int chars_per_margin = 0;
586
587/* Position where the next character will fall.
588 Leftmost position is 0 + chars_per_margin.
589 Rightmost position is chars_per_margin + chars_per_line - 1.
590 This is important for converting spaces to tabs on output. */
591static int output_position;
592
593/* Horizontal position relative to the current file.
594 (output_position depends on where we are on the page;
595 input_position depends on where we are in the file.)
596 Important for converting tabs to spaces on input. */
597static int input_position;
598
599/* True if there were any failed opens so we can exit with nonzero
600 status. */
601static bool failed_opens = false;
602
603/* The number of spaces taken up if we print a tab character with width
604 c_ from position h_. */
605#define TAB_WIDTH(c_, h_) ((c_) - ((h_) % (c_)))
606
607/* The horizontal position we'll be at after printing a tab character
608 of width c_ from the position h_. */
609#define POS_AFTER_TAB(c_, h_) ((h_) + TAB_WIDTH (c_, h_))
610
611/* (-NNN) Number of columns of text to print. */
612static int columns = 1;
613
614/* (+NNN:MMM) Page numbers on which to begin and stop printing.
615 first_page_number = 0 will be used to check input only. */
616static uintmax_t first_page_number = 0;
617static uintmax_t last_page_number = UINTMAX_MAX;
618
619/* Number of files open (not closed, not on hold). */
620static int files_ready_to_read = 0;
621
622/* Current page number. Displayed in header. */
623static uintmax_t page_number;
624
625/* Current line number. Displayed when -n flag is specified.
626
627 When printing files in parallel (-m flag), line numbering is as follows:
628 1 foo goo moo
629 2 hoo too zoo
630
631 When printing files across (-a flag), ...
632 1 foo 2 moo 3 goo
633 4 hoo 5 too 6 zoo
634
635 Otherwise, line numbering is as follows:
636 1 foo 3 goo 5 too
637 2 moo 4 hoo 6 zoo */
638static int line_number;
639
640/* With line_number overflow, we use power_10 to cut off the higher-order
641 digits of the line_number */
642static int power_10;
643
644/* (-n) True means lines should be preceded by numbers. */
645static bool numbered_lines = false;
646
647/* (-n) Character which follows each line number. */
648static char number_separator = '\t';
649
650/* (-n) line counting starts with 1st line of input file (not with 1st
651 line of 1st page printed). */
652static int line_count = 1;
653
654/* (-n) True means counting of skipped lines starts with 1st line of
655 input file. False means -N option is used in addition, counting of
656 skipped lines not required. */
657static bool skip_count = true;
658
659/* (-N) Counting starts with start_line_number = NUMBER at 1st line of
660 first page printed, usually not 1st page of input file. */
661static int start_line_num = 1;
662
663/* (-n) Width in characters of a line number. */
664static int chars_per_number = 5;
665
666/* Used when widening the first column to accommodate numbers -- only
667 needed when printing files in parallel. Includes width of both the
668 number and the number_separator. */
669static int number_width;
670
671/* Buffer sprintf uses to format a line number. */
672static char *number_buff;
673
674/* (-v) True means unprintable characters are printed as escape sequences.
675 control-g becomes \007. */
676static bool use_esc_sequence = false;
677
678/* (-c) True means unprintable characters are printed as control prefixes.
679 control-g becomes ^G. */
680static bool use_cntrl_prefix = false;
681
682/* (-d) True means output is double spaced. */
683static bool double_space = false;
684
685/* Number of files opened initially in init_files. Should be 1
686 unless we're printing multiple files in parallel. */
687static int total_files = 0;
688
689/* (-r) True means don't complain if we can't open a file. */
690static bool ignore_failed_opens = false;
691
692/* (-S) True means we separate columns with a specified string.
693 -S option does not affect line truncation nor column alignment. */
694static bool use_col_separator = false;
695
696/* String used to separate columns if the -S option has been specified.
697 Default without -S but together with one of the column options
698 -a|COLUMN|-m is a `space' and with the -J option a `tab'. */
699static char *col_sep_string = "";
700static int col_sep_length = 0;
701static char *column_separator = " ";
702static char *line_separator = "\t";
703
704/* Number of separator characters waiting to be printed as soon as we
705 know that we have any input remaining to be printed. */
706static int separators_not_printed;
707
708/* Position we need to pad to, as soon as we know that we have input
709 remaining to be printed. */
710static int padding_not_printed;
711
712/* True means we should pad the end of the page. Remains false until we
713 know we have a page to print. */
714static bool pad_vertically;
715
716/* (-h) String of characters used in place of the filename in the header. */
717static char *custom_header;
718
719/* (-D) Date format for the header. */
720static char const *date_format;
721
722/* Date and file name for the header. */
723static char *date_text;
724static char const *file_text;
725
726/* Output columns available, not counting the date and file name. */
727static int header_width_available;
728
729static char *clump_buff;
730
731/* True means we read the line no. lines_per_body in skip_read
732 called by skip_to_page. That variable controls the coincidence of a
733 "FF set by hand" and "full_page_printed", see above the definition of
734 structure COLUMN. */
735static bool last_line = false;
736
737/* For long options that have no equivalent short option, use a
738 non-character as a pseudo short option, starting with CHAR_MAX + 1. */
739enum
740{
741 COLUMNS_OPTION = CHAR_MAX + 1,
742 PAGES_OPTION
743};
744
745static char const short_options[] =
746 "-0123456789D:FJN:S::TW:abcde::fh:i::l:mn::o:rs::tvw:";
747
748static struct option const long_options[] =
749{
750 {"pages", required_argument, NULL, PAGES_OPTION},
751 {"columns", required_argument, NULL, COLUMNS_OPTION},
752 {"across", no_argument, NULL, 'a'},
753 {"show-control-chars", no_argument, NULL, 'c'},
754 {"double-space", no_argument, NULL, 'd'},
755 {"date-format", required_argument, NULL, 'D'},
756 {"expand-tabs", optional_argument, NULL, 'e'},
757 {"form-feed", no_argument, NULL, 'f'},
758 {"header", required_argument, NULL, 'h'},
759 {"output-tabs", optional_argument, NULL, 'i'},
760 {"join-lines", no_argument, NULL, 'J'},
761 {"length", required_argument, NULL, 'l'},
762 {"merge", no_argument, NULL, 'm'},
763 {"number-lines", optional_argument, NULL, 'n'},
764 {"first-line-number", required_argument, NULL, 'N'},
765 {"indent", required_argument, NULL, 'o'},
766 {"no-file-warnings", no_argument, NULL, 'r'},
767 {"separator", optional_argument, NULL, 's'},
768 {"sep-string", optional_argument, NULL, 'S'},
769 {"omit-header", no_argument, NULL, 't'},
770 {"omit-pagination", no_argument, NULL, 'T'},
771 {"show-nonprinting", no_argument, NULL, 'v'},
772 {"width", required_argument, NULL, 'w'},
773 {"page-width", required_argument, NULL, 'W'},
774 {GETOPT_HELP_OPTION_DECL},
775 {GETOPT_VERSION_OPTION_DECL},
776 {NULL, 0, NULL, 0}
777};
778
779/* Return the number of columns that have either an open file or
780 stored lines. */
781
782static int
783cols_ready_to_print (void)
784{
785 COLUMN *q;
786 int i;
787 int n;
788
789 n = 0;
790 for (q = column_vector, i = 0; i < columns; ++q, ++i)
791 if (q->status == OPEN ||
792 q->status == FF_FOUND || /* With -b: To print a header only */
793 (storing_columns && q->lines_stored > 0 && q->lines_to_print > 0))
794 ++n;
795 return n;
796}
797
798/* Estimate first_ / last_page_number
799 using option +FIRST_PAGE:LAST_PAGE */
800
801static bool
802first_last_page (char const *pages)
803{
804 char *p;
805 uintmax_t first;
806 uintmax_t last = UINTMAX_MAX;
807 strtol_error err = xstrtoumax (pages, &p, 10, &first, "");
808 if (err != LONGINT_OK && err != LONGINT_INVALID_SUFFIX_CHAR)
809 _STRTOL_ERROR (EXIT_FAILURE, pages, _("page range"), err);
810
811 if (p == pages || !first)
812 return false;
813
814 if (*p == ':')
815 {
816 char const *p1 = p + 1;
817 err = xstrtoumax (p1, &p, 10, &last, "");
818 if (err != LONGINT_OK)
819 _STRTOL_ERROR (EXIT_FAILURE, pages, _("page range"), err);
820 if (p1 == p || last < first)
821 return false;
822 }
823
824 if (*p)
825 return false;
826
827 first_page_number = first;
828 last_page_number = last;
829 return true;
830}
831
832/* Parse column count string S, and if it's valid (1 or larger and
833 within range of the type of `columns') set the global variables
834 columns and explicit_columns and return true.
835 Otherwise, exit with a diagnostic. */
836static void
837parse_column_count (char const *s)
838{
839 long int tmp_long;
840 if (xstrtol (s, NULL, 10, &tmp_long, "") != LONGINT_OK
841 || !(1 <= tmp_long && tmp_long <= INT_MAX))
842 error (EXIT_FAILURE, 0,
843 _("invalid number of columns: %s"), quote (s));
844
845 columns = tmp_long;
846 explicit_columns = true;
847}
848
849/* Estimate length of col_sep_string with option -S. */
850
851static void
852separator_string (const char *optarg_S)
853{
854 col_sep_length = (int) strlen (optarg_S);
855 col_sep_string = xmalloc (col_sep_length + 1);
856 strcpy (col_sep_string, optarg_S);
857}
858
859int
860main (int argc, char **argv)
861{
862 int c;
863 int n_files;
864 bool old_options = false;
865 bool old_w = false;
866 bool old_s = false;
867 char **file_names;
868
869 /* Accumulate the digits of old-style options like -99. */
870 char *column_count_string = NULL;
871 size_t n_digits = 0;
872 size_t n_alloc = 0;
873
874 initialize_main (&argc, &argv);
875 program_name = argv[0];
876 setlocale (LC_ALL, "");
877 bindtextdomain (PACKAGE, LOCALEDIR);
878 textdomain (PACKAGE);
879
880 atexit (close_stdout);
881
882 n_files = 0;
883 file_names = (argc > 1
884 ? xmalloc ((argc - 1) * sizeof (char *))
885 : NULL);
886
887 while ((c = getopt_long (argc, argv, short_options, long_options, NULL))
888 != -1)
889 {
890 if (ISDIGIT (c))
891 {
892 /* Accumulate column-count digits specified via old-style options. */
893 if (n_digits + 1 >= n_alloc)
894 column_count_string
895 = X2REALLOC (column_count_string, &n_alloc);
896 column_count_string[n_digits++] = c;
897 column_count_string[n_digits] = '\0';
898 continue;
899 }
900
901 n_digits = 0;
902
903 switch (c)
904 {
905 case 1: /* Non-option argument. */
906 /* long option --page dominates old `+FIRST_PAGE ...'. */
907 if (! (first_page_number == 0
908 && *optarg == '+' && first_last_page (optarg + 1)))
909 file_names[n_files++] = optarg;
910 break;
911
912 case PAGES_OPTION: /* --pages=FIRST_PAGE[:LAST_PAGE] */
913 { /* dominates old opt +... */
914 if (! optarg)
915 error (EXIT_FAILURE, 0,
916 _("`--pages=FIRST_PAGE[:LAST_PAGE]' missing argument"));
917 else if (! first_last_page (optarg))
918 error (EXIT_FAILURE, 0, _("Invalid page range %s"),
919 quote (optarg));
920 break;
921 }
922
923 case COLUMNS_OPTION: /* --columns=COLUMN */
924 {
925 parse_column_count (optarg);
926
927 /* If there was a prior column count specified via the
928 short-named option syntax, e.g., -9, ensure that this
929 long-name-specified value overrides it. */
930 free (column_count_string);
931 column_count_string = NULL;
932 n_alloc = 0;
933 break;
934 }
935
936 case 'a':
937 print_across_flag = true;
938 storing_columns = false;
939 break;
940 case 'b':
941 balance_columns = true;
942 break;
943 case 'c':
944 use_cntrl_prefix = true;
945 break;
946 case 'd':
947 double_space = true;
948 break;
949 case 'D':
950 date_format = optarg;
951 break;
952 case 'e':
953 if (optarg)
954 getoptarg (optarg, 'e', &input_tab_char,
955 &chars_per_input_tab);
956 /* Could check tab width > 0. */
957 untabify_input = true;
958 break;
959 case 'f':
960 case 'F':
961 use_form_feed = true;
962 break;
963 case 'h':
964 custom_header = optarg;
965 break;
966 case 'i':
967 if (optarg)
968 getoptarg (optarg, 'i', &output_tab_char,
969 &chars_per_output_tab);
970 /* Could check tab width > 0. */
971 tabify_output = true;
972 break;
973 case 'J':
974 join_lines = true;
975 break;
976 case 'l':
977 {
978 long int tmp_long;
979 if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK
980 || tmp_long <= 0 || tmp_long > INT_MAX)
981 {
982 error (EXIT_FAILURE, 0,
983 _("`-l PAGE_LENGTH' invalid number of lines: %s"),
984 quote (optarg));
985 }
986 lines_per_page = tmp_long;
987 break;
988 }
989 case 'm':
990 parallel_files = true;
991 storing_columns = false;
992 break;
993 case 'n':
994 numbered_lines = true;
995 if (optarg)
996 getoptarg (optarg, 'n', &number_separator,
997 &chars_per_number);
998 break;
999 case 'N':
1000 skip_count = false;
1001 {
1002 long int tmp_long;
1003 if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK
1004 || tmp_long > INT_MAX)
1005 {
1006 error (EXIT_FAILURE, 0,
1007 _("`-N NUMBER' invalid starting line number: %s"),
1008 quote (optarg));
1009 }
1010 start_line_num = tmp_long;
1011 break;
1012 }
1013 case 'o':
1014 {
1015 long int tmp_long;
1016 if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK
1017 || tmp_long < 0 || tmp_long > INT_MAX)
1018 error (EXIT_FAILURE, 0,
1019 _("`-o MARGIN' invalid line offset: %s"), quote (optarg));
1020 chars_per_margin = tmp_long;
1021 break;
1022 }
1023 case 'r':
1024 ignore_failed_opens = true;
1025 break;
1026 case 's':
1027 old_options = true;
1028 old_s = true;
1029 if (!use_col_separator && optarg)
1030 separator_string (optarg);
1031 break;
1032 case 'S':
1033 old_s = false;
1034 /* Reset an additional input of -s, -S dominates -s */
1035 col_sep_string = "";
1036 col_sep_length = 0;
1037 use_col_separator = true;
1038 if (optarg)
1039 separator_string (optarg);
1040 break;
1041 case 't':
1042 extremities = false;
1043 keep_FF = true;
1044 break;
1045 case 'T':
1046 extremities = false;
1047 keep_FF = false;
1048 break;
1049 case 'v':
1050 use_esc_sequence = true;
1051 break;
1052 case 'w':
1053 old_options = true;
1054 old_w = true;
1055 {
1056 long int tmp_long;
1057 if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK
1058 || tmp_long <= 0 || tmp_long > INT_MAX)
1059 error (EXIT_FAILURE, 0,
1060 _("`-w PAGE_WIDTH' invalid number of characters: %s"),
1061 quote (optarg));
1062 if (!truncate_lines)
1063 chars_per_line = tmp_long;
1064 break;
1065 }
1066 case 'W':
1067 old_w = false; /* dominates -w */
1068 truncate_lines = true;
1069 {
1070 long int tmp_long;
1071 if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK
1072 || tmp_long <= 0 || tmp_long > INT_MAX)
1073 error (EXIT_FAILURE, 0,
1074 _("`-W PAGE_WIDTH' invalid number of characters: %s"),
1075 quote (optarg));
1076 chars_per_line = tmp_long;
1077 break;
1078 }
1079 case_GETOPT_HELP_CHAR;
1080 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
1081 default:
1082 usage (EXIT_FAILURE);
1083 break;
1084 }
1085 }
1086
1087 if (column_count_string)
1088 {
1089 parse_column_count (column_count_string);
1090 free (column_count_string);
1091 }
1092
1093 if (! date_format)
1094 date_format = (getenv ("POSIXLY_CORRECT") && !hard_locale (LC_TIME)
1095 ? "%b %e %H:%M %Y"
1096 : "%Y-%m-%d %H:%M");
1097
1098 /* Now we can set a reasonable initial value: */
1099 if (first_page_number == 0)
1100 first_page_number = 1;
1101
1102 if (parallel_files & explicit_columns)
1103 error (EXIT_FAILURE, 0,
1104 _("Cannot specify number of columns when printing in parallel."));
1105
1106 if (parallel_files & print_across_flag)
1107 error (EXIT_FAILURE, 0,
1108 _("Cannot specify both printing across and printing in parallel."));
1109
1110/* Translate some old short options to new/long options.
1111 To meet downward compatibility with other UNIX pr utilities
1112 and some POSIX specifications. */
1113
1114 if (old_options)
1115 {
1116 if (old_w)
1117 {
1118 if (parallel_files | explicit_columns)
1119 {
1120 /* activate -W */
1121 truncate_lines = true;
1122 if (old_s)
1123 /* adapt HP-UX and SunOS: -s = no separator;
1124 activate -S */
1125 use_col_separator = true;
1126 }
1127 else
1128 /* old -w sets width with columns only
1129 activate -J */
1130 join_lines = true;
1131 }
1132 else if (!use_col_separator)
1133 {
1134 /* No -S option read */
1135 if (old_s & (parallel_files | explicit_columns))
1136 {
1137 if (!truncate_lines)
1138 {
1139 /* old -s (without -w and -W) annuls column alignment,
1140 uses fields, activate -J */
1141 join_lines = true;
1142 if (col_sep_length > 0)
1143 /* activate -S */
1144 use_col_separator = true;
1145 }
1146 else
1147 /* with -W */
1148 /* adapt HP-UX and SunOS: -s = no separator;
1149 activate -S */
1150 use_col_separator = true;
1151 }
1152 }
1153 }
1154
1155 for (; optind < argc; optind++)
1156 {
1157 file_names[n_files++] = argv[optind];
1158 }
1159
1160 if (n_files == 0)
1161 {
1162 /* No file arguments specified; read from standard input. */
1163 print_files (0, NULL);
1164 }
1165 else
1166 {
1167 if (parallel_files)
1168 print_files (n_files, file_names);
1169 else
1170 {
1171 int i;
1172 for (i = 0; i < n_files; i++)
1173 print_files (1, &file_names[i]);
1174 }
1175 }
1176
1177 cleanup ();
1178
1179 if (have_read_stdin && fclose (stdin) == EOF)
1180 error (EXIT_FAILURE, errno, _("standard input"));
1181 if (failed_opens)
1182 exit (EXIT_FAILURE);
1183 exit (EXIT_SUCCESS);
1184}
1185
1186/* Parse options of the form -scNNN.
1187
1188 Example: -nck, where 'n' is the option, c is the optional number
1189 separator, and k is the optional width of the field used when printing
1190 a number. */
1191
1192static void
1193getoptarg (char *arg, char switch_char, char *character, int *number)
1194{
1195 if (!ISDIGIT (*arg))
1196 *character = *arg++;
1197 if (*arg)
1198 {
1199 long int tmp_long;
1200 if (xstrtol (arg, NULL, 10, &tmp_long, "") != LONGINT_OK
1201 || tmp_long <= 0 || tmp_long > INT_MAX)
1202 {
1203 error (0, 0,
1204 _("`-%c' extra characters or invalid number in the argument: %s"),
1205 switch_char, quote (arg));
1206 usage (EXIT_FAILURE);
1207 }
1208 *number = tmp_long;
1209 }
1210}
1211
1212
1213/* Set parameters related to formatting. */
1214
1215static void
1216init_parameters (int number_of_files)
1217{
1218 int chars_used_by_number = 0;
1219
1220 if (use_form_feed)
1221 {
1222 lines_per_header = 3;
1223 lines_per_footer = 0;
1224 }
1225
1226 lines_per_body = lines_per_page - lines_per_header - lines_per_footer;
1227 if (lines_per_body <= 0)
1228 {
1229 extremities = false;
1230 keep_FF = true;
1231 }
1232 if (extremities == false)
1233 lines_per_body = lines_per_page;
1234
1235 if (double_space)
1236 lines_per_body = lines_per_body / 2;
1237
1238 /* If input is stdin, cannot print parallel files. BSD dumps core
1239 on this. */
1240 if (number_of_files == 0)
1241 parallel_files = false;
1242
1243 if (parallel_files)
1244 columns = number_of_files;
1245
1246 /* One file, multi columns down: -b option is set to get a consistent
1247 formulation with "FF set by hand" in input files. */
1248 if (storing_columns)
1249 balance_columns = true;
1250
1251 /* Tabification is assumed for multiple columns. */
1252 if (columns > 1)
1253 {
1254 if (!use_col_separator)
1255 {
1256 /* Use default separator */
1257 if (join_lines)
1258 col_sep_string = line_separator;
1259 else
1260 col_sep_string = column_separator;
1261
1262 col_sep_length = 1;
1263 use_col_separator = true;
1264 }
1265 /* It's rather pointless to define a TAB separator with column
1266 alignment */
1267 else if (!join_lines && *col_sep_string == '\t')
1268 col_sep_string = column_separator;
1269
1270 truncate_lines = true;
1271 untabify_input = true;
1272 tabify_output = true;
1273 }
1274 else
1275 storing_columns = false;
1276
1277 /* -J dominates -w in any case */
1278 if (join_lines)
1279 truncate_lines = false;
1280
1281 if (numbered_lines)
1282 {
1283 int tmp_i;
1284 int chars_per_default_tab = 8;
1285
1286 line_count = start_line_num;
1287
1288 /* To allow input tab-expansion (-e sensitive) use:
1289 if (number_separator == input_tab_char)
1290 number_width = chars_per_number +
1291 TAB_WIDTH (chars_per_input_tab, chars_per_number); */
1292
1293 /* Estimate chars_per_text without any margin and keep it constant. */
1294 if (number_separator == '\t')
1295 number_width = chars_per_number +
1296 TAB_WIDTH (chars_per_default_tab, chars_per_number);
1297 else
1298 number_width = chars_per_number + 1;
1299
1300 /* The number is part of the column width unless we are
1301 printing files in parallel. */
1302 if (parallel_files)
1303 chars_used_by_number = number_width;
1304
1305 /* We use power_10 to cut off the higher-order digits of the
1306 line_number in function add_line_number */
1307 tmp_i = chars_per_number;
1308 for (power_10 = 1; tmp_i > 0; --tmp_i)
1309 power_10 = 10 * power_10;
1310 }
1311
1312 chars_per_column = (chars_per_line - chars_used_by_number -
1313 (columns - 1) * col_sep_length) / columns;
1314
1315 if (chars_per_column < 1)
1316 error (EXIT_FAILURE, 0, _("page width too narrow"));
1317
1318 if (numbered_lines)
1319 {
1320 free (number_buff);
1321 number_buff = xmalloc (2 * chars_per_number);
1322 }
1323
1324 /* Pick the maximum between the tab width and the width of an
1325 escape sequence.
1326 The width of an escape sequence (4) isn't the lower limit any longer.
1327 We've to use 8 as the lower limit, if we use chars_per_default_tab = 8
1328 to expand a tab which is not an input_tab-char. */
1329 free (clump_buff);
1330 clump_buff = xmalloc (MAX (8, chars_per_input_tab));
1331}
1332
1333
1334/* Open the necessary files,
1335 maintaining a COLUMN structure for each column.
1336
1337 With multiple files, each column p has a different p->fp.
1338 With single files, each column p has the same p->fp.
1339 Return false if (number_of_files > 0) and no files can be opened,
1340 true otherwise.
1341
1342 With each column/file p, p->full_page_printed is initialized,
1343 see also open_file. */
1344
1345static bool
1346init_fps (int number_of_files, char **av)
1347{
1348 int i, files_left;
1349 COLUMN *p;
1350 FILE *firstfp;
1351 char const *firstname;
1352
1353 total_files = 0;
1354
1355 free (column_vector);
1356 column_vector = xnmalloc (columns, sizeof (COLUMN));
1357
1358 if (parallel_files)
1359 {
1360 files_left = number_of_files;
1361 for (p = column_vector; files_left--; ++p, ++av)
1362 {
1363 if (! open_file (*av, p))
1364 {
1365 --p;
1366 --columns;
1367 }
1368 }
1369 if (columns == 0)
1370 return false;
1371 init_header ("", -1);
1372 }
1373 else
1374 {
1375 p = column_vector;
1376 if (number_of_files > 0)
1377 {
1378 if (! open_file (*av, p))
1379 return false;
1380 init_header (*av, fileno (p->fp));
1381 p->lines_stored = 0;
1382 }
1383 else
1384 {
1385 p->name = _("standard input");
1386 p->fp = stdin;
1387 have_read_stdin = true;
1388 p->status = OPEN;
1389 p->full_page_printed = false;
1390 ++total_files;
1391 init_header ("", -1);
1392 p->lines_stored = 0;
1393 }
1394
1395 firstname = p->name;
1396 firstfp = p->fp;
1397 for (i = columns - 1, ++p; i; --i, ++p)
1398 {
1399 p->name = firstname;
1400 p->fp = firstfp;
1401 p->status = OPEN;
1402 p->full_page_printed = false;
1403 p->lines_stored = 0;
1404 }
1405 }
1406 files_ready_to_read = total_files;
1407 return true;
1408}
1409
1410
1411/* Determine print_func and char_func, the functions
1412 used by each column for printing and/or storing.
1413
1414 Determine the horizontal position desired when we begin
1415 printing a column (p->start_position). */
1416
1417static void
1418init_funcs (void)
1419{
1420 int i, h, h_next;
1421 COLUMN *p;
1422
1423 h = chars_per_margin;
1424
1425 if (!truncate_lines)
1426 h_next = ANYWHERE;
1427 else
1428 {
1429 /* When numbering lines of parallel files, we enlarge the
1430 first column to accomodate the number. Looks better than
1431 the Sys V approach. */
1432 if (parallel_files & numbered_lines)
1433 h_next = h + chars_per_column + number_width;
1434 else
1435 h_next = h + chars_per_column;
1436 }
1437
1438 /* Enlarge p->start_position of first column to use the same form of
1439 padding_not_printed with all columns. */
1440 h = h + col_sep_length;
1441
1442 /* This loop takes care of all but the rightmost column. */
1443
1444 for (p = column_vector, i = 1; i < columns; ++p, ++i)
1445 {
1446 if (storing_columns) /* One file, multi columns down. */
1447 {
1448 p->char_func = store_char;
1449 p->print_func = print_stored;
1450 }
1451 else
1452 /* One file, multi columns across; or parallel files. */
1453 {
1454 p->char_func = print_char;
1455 p->print_func = read_line;
1456 }
1457
1458 /* Number only the first column when printing files in
1459 parallel. */
1460 p->numbered = numbered_lines && (!parallel_files || i == 1);
1461 p->start_position = h;
1462
1463 /* If we don't truncate lines, all start_positions are
1464 ANYWHERE, except the first column's start_position when
1465 using a margin. */
1466
1467 if (!truncate_lines)
1468 {
1469 h = ANYWHERE;
1470 h_next = ANYWHERE;
1471 }
1472 else
1473 {
1474 h = h_next + col_sep_length;
1475 h_next = h + chars_per_column;
1476 }
1477 }
1478
1479 /* The rightmost column.
1480
1481 Doesn't need to be stored unless we intend to balance
1482 columns on the last page. */
1483 if (storing_columns & balance_columns)
1484 {
1485 p->char_func = store_char;
1486 p->print_func = print_stored;
1487 }
1488 else
1489 {
1490 p->char_func = print_char;
1491 p->print_func = read_line;
1492 }
1493
1494 p->numbered = numbered_lines && (!parallel_files || i == 1);
1495 p->start_position = h;
1496}
1497
1498
1499/* Open a file. Return true if successful.
1500
1501 With each file p, p->full_page_printed is initialized,
1502 see also init_fps. */
1503
1504static bool
1505open_file (char *name, COLUMN *p)
1506{
1507 if (STREQ (name, "-"))
1508 {
1509 p->name = _("standard input");
1510 p->fp = stdin;
1511 have_read_stdin = true;
1512 }
1513 else
1514 {
1515 p->name = name;
1516 p->fp = fopen (name, "r");
1517 }
1518 if (p->fp == NULL)
1519 {
1520 failed_opens = true;
1521 if (!ignore_failed_opens)
1522 error (0, errno, "%s", name);
1523 return false;
1524 }
1525 p->status = OPEN;
1526 p->full_page_printed = false;
1527 ++total_files;
1528 return true;
1529}
1530
1531/* Close the file in P.
1532
1533 If we aren't dealing with multiple files in parallel, we change
1534 the status of all columns in the column list to reflect the close. */
1535
1536static void
1537close_file (COLUMN *p)
1538{
1539 COLUMN *q;
1540 int i;
1541
1542 if (p->status == CLOSED)
1543 return;
1544 if (ferror (p->fp))
1545 error (EXIT_FAILURE, errno, "%s", p->name);
1546 if (fileno (p->fp) != STDIN_FILENO && fclose (p->fp) != 0)
1547 error (EXIT_FAILURE, errno, "%s", p->name);
1548
1549 if (!parallel_files)
1550 {
1551 for (q = column_vector, i = columns; i; ++q, --i)
1552 {
1553 q->status = CLOSED;
1554 if (q->lines_stored == 0)
1555 {
1556 q->lines_to_print = 0;
1557 }
1558 }
1559 }
1560 else
1561 {
1562 p->status = CLOSED;
1563 p->lines_to_print = 0;
1564 }
1565
1566 --files_ready_to_read;
1567}
1568
1569/* Put a file on hold until we start a new page,
1570 since we've hit a form feed.
1571
1572 If we aren't dealing with parallel files, we must change the
1573 status of all columns in the column list. */
1574
1575static void
1576hold_file (COLUMN *p)
1577{
1578 COLUMN *q;
1579 int i;
1580
1581 if (!parallel_files)
1582 for (q = column_vector, i = columns; i; ++q, --i)
1583 {
1584 if (storing_columns)
1585 q->status = FF_FOUND;
1586 else
1587 q->status = ON_HOLD;
1588 }
1589 else
1590 p->status = ON_HOLD;
1591
1592 p->lines_to_print = 0;
1593 --files_ready_to_read;
1594}
1595
1596/* Undo hold_file -- go through the column list and change any
1597 ON_HOLD columns to OPEN. Used at the end of each page. */
1598
1599static void
1600reset_status (void)
1601{
1602 int i = columns;
1603 COLUMN *p;
1604
1605 for (p = column_vector; i; --i, ++p)
1606 if (p->status == ON_HOLD)
1607 {
1608 p->status = OPEN;
1609 files_ready_to_read++;
1610 }
1611
1612 if (storing_columns)
1613 {
1614 if (column_vector->status == CLOSED)
1615 /* We use the info to output an error message in skip_to_page. */
1616 files_ready_to_read = 0;
1617 else
1618 files_ready_to_read = 1;
1619 }
1620}
1621
1622
1623/* Print a single file, or multiple files in parallel.
1624
1625 Set up the list of columns, opening the necessary files.
1626 Allocate space for storing columns, if necessary.
1627 Skip to first_page_number, if user has asked to skip leading pages.
1628 Determine which functions are appropriate to store/print lines
1629 in each column.
1630 Print the file(s). */
1631
1632static void
1633print_files (int number_of_files, char **av)
1634{
1635 init_parameters (number_of_files);
1636 if (! init_fps (number_of_files, av))
1637 return;
1638 if (storing_columns)
1639 init_store_cols ();
1640
1641 if (first_page_number > 1)
1642 {
1643 if (!skip_to_page (first_page_number))
1644 return;
1645 else
1646 page_number = first_page_number;
1647 }
1648 else
1649 page_number = 1;
1650
1651 init_funcs ();
1652
1653 line_number = line_count;
1654 while (print_page ())
1655 ;
1656}
1657
1658
1659/* Initialize header information.
1660 If DESC is non-negative, it is a file descriptor open to
1661 FILENAME for reading. */
1662
1663static void
1664init_header (char *filename, int desc)
1665{
1666 char *buf = NULL;
1667 struct stat st;
1668 struct timespec t;
1669 int ns;
1670 struct tm *tm;
1671
1672 /* If parallel files or standard input, use current date. */
1673 if (STREQ (filename, "-"))
1674 desc = -1;
1675 if (0 <= desc && fstat (desc, &st) == 0)
1676 t = get_stat_mtime (&st);
1677 else
1678 {
1679 static struct timespec timespec;
1680 if (! timespec.tv_sec)
1681 gettime (&timespec);
1682 t = timespec;
1683 }
1684
1685 ns = t.tv_nsec;
1686 tm = localtime (&t.tv_sec);
1687 if (tm == NULL)
1688 {
1689 buf = xmalloc (INT_BUFSIZE_BOUND (long int)
1690 + MAX (10, INT_BUFSIZE_BOUND (int)));
1691 sprintf (buf, "%ld.%09d", (long int) t.tv_sec, ns);
1692 }
1693 else
1694 {
1695 size_t bufsize = nstrftime (NULL, SIZE_MAX, date_format, tm, 0, ns) + 1;
1696 buf = xmalloc (bufsize);
1697 nstrftime (buf, bufsize, date_format, tm, 0, ns);
1698 }
1699
1700 free (date_text);
1701 date_text = buf;
1702 file_text = custom_header ? custom_header : desc < 0 ? "" : filename;
1703 header_width_available = (chars_per_line
1704 - mbswidth (date_text, 0)
1705 - mbswidth (file_text, 0));
1706}
1707
1708
1709/* Set things up for printing a page
1710
1711 Scan through the columns ...
1712 Determine which are ready to print
1713 (i.e., which have lines stored or open files)
1714 Set p->lines_to_print appropriately
1715 (to p->lines_stored if we're storing, or lines_per_body
1716 if we're reading straight from the file)
1717 Keep track of this total so we know when to stop printing */
1718
1719static void
1720init_page (void)
1721{
1722 int j;
1723 COLUMN *p;
1724
1725 if (storing_columns)
1726 {
1727 store_columns ();
1728 for (j = columns - 1, p = column_vector; j; --j, ++p)
1729 {
1730 p->lines_to_print = p->lines_stored;
1731 }
1732
1733 /* Last column. */
1734 if (balance_columns)
1735 {
1736 p->lines_to_print = p->lines_stored;
1737 }
1738 /* Since we're not balancing columns, we don't need to store
1739 the rightmost column. Read it straight from the file. */
1740 else
1741 {
1742 if (p->status == OPEN)
1743 {
1744 p->lines_to_print = lines_per_body;
1745 }
1746 else
1747 p->lines_to_print = 0;
1748 }
1749 }
1750 else
1751 for (j = columns, p = column_vector; j; --j, ++p)
1752 if (p->status == OPEN)
1753 {
1754 p->lines_to_print = lines_per_body;
1755 }
1756 else
1757 p->lines_to_print = 0;
1758}
1759
1760/* Align empty columns and print separators.
1761 Empty columns will be formed by files with status ON_HOLD or CLOSED
1762 when printing multiple files in parallel. */
1763
1764static void
1765align_column (COLUMN *p)
1766{
1767 padding_not_printed = p->start_position;
1768 if (padding_not_printed - col_sep_length > 0)
1769 {
1770 pad_across_to (padding_not_printed - col_sep_length);
1771 padding_not_printed = ANYWHERE;
1772 }
1773
1774 if (use_col_separator)
1775 print_sep_string ();
1776
1777 if (p->numbered)
1778 add_line_number (p);
1779}
1780
1781/* Print one page.
1782
1783 As long as there are lines left on the page and columns ready to print,
1784 Scan across the column list
1785 if the column has stored lines or the file is open
1786 pad to the appropriate spot
1787 print the column
1788 pad the remainder of the page with \n or \f as requested
1789 reset the status of all files -- any files which where on hold because
1790 of formfeeds are now put back into the lineup. */
1791
1792static bool
1793print_page (void)
1794{
1795 int j;
1796 int lines_left_on_page;
1797 COLUMN *p;
1798
1799 /* Used as an accumulator (with | operator) of successive values of
1800 pad_vertically. The trick is to set pad_vertically
1801 to false before each run through the inner loop, then after that
1802 loop, it tells us whether a line was actually printed (whether a
1803 newline needs to be output -- or two for double spacing). But those
1804 values have to be accumulated (in pv) so we can invoke pad_down
1805 properly after the outer loop completes. */
1806 bool pv;
1807
1808 init_page ();
1809
1810 if (cols_ready_to_print () == 0)
1811 return false;
1812
1813 if (extremities)
1814 print_a_header = true;
1815
1816 /* Don't pad unless we know a page was printed. */
1817 pad_vertically = false;
1818 pv = false;
1819
1820 lines_left_on_page = lines_per_body;
1821 if (double_space)
1822 lines_left_on_page *= 2;
1823
1824 while (lines_left_on_page > 0 && cols_ready_to_print () > 0)
1825 {
1826 output_position = 0;
1827 spaces_not_printed = 0;
1828 separators_not_printed = 0;
1829 pad_vertically = false;
1830 align_empty_cols = false;
1831 empty_line = true;
1832
1833 for (j = 1, p = column_vector; j <= columns; ++j, ++p)
1834 {
1835 input_position = 0;
1836 if (p->lines_to_print > 0 || p->status == FF_FOUND)
1837 {
1838 FF_only = false;
1839 padding_not_printed = p->start_position;
1840 if (!(p->print_func) (p))
1841 read_rest_of_line (p);
1842 pv |= pad_vertically;
1843
1844 --p->lines_to_print;
1845 if (p->lines_to_print <= 0)
1846 {
1847 if (cols_ready_to_print () <= 0)
1848 break;
1849 }
1850
1851 /* File p changed its status to ON_HOLD or CLOSED */
1852 if (parallel_files && p->status != OPEN)
1853 {
1854 if (empty_line)
1855 align_empty_cols = true;
1856 else if (p->status == CLOSED ||
1857 (p->status == ON_HOLD && FF_only))
1858 align_column (p);
1859 }
1860 }
1861 else if (parallel_files)
1862 {
1863 /* File status ON_HOLD or CLOSED */
1864 if (empty_line)
1865 align_empty_cols = true;
1866 else
1867 align_column (p);
1868 }
1869
1870 /* We need it also with an empty column */
1871 if (use_col_separator)
1872 ++separators_not_printed;
1873 }
1874
1875 if (pad_vertically)
1876 {
1877 putchar ('\n');
1878 --lines_left_on_page;
1879 }
1880
1881 if (cols_ready_to_print () <= 0 && !extremities)
1882 break;
1883
1884 if (double_space & pv)
1885 {
1886 putchar ('\n');
1887 --lines_left_on_page;
1888 }
1889 }
1890
1891 if (lines_left_on_page == 0)
1892 for (j = 1, p = column_vector; j <= columns; ++j, ++p)
1893 if (p->status == OPEN)
1894 p->full_page_printed = true;
1895
1896 pad_vertically = pv;
1897
1898 if (pad_vertically & extremities)
1899 pad_down (lines_left_on_page + lines_per_footer);
1900 else if (keep_FF & print_a_FF)
1901 {
1902 putchar ('\f');
1903 print_a_FF = false;
1904 }
1905
1906 if (last_page_number < page_number)
1907 return false; /* Stop printing with LAST_PAGE */
1908
1909 reset_status (); /* Change ON_HOLD to OPEN. */
1910
1911 return true; /* More pages to go. */
1912}
1913
1914
1915/* Allocate space for storing columns.
1916
1917 This is necessary when printing multiple columns from a single file.
1918 Lines are stored consecutively in buff, separated by '\0'.
1919
1920 The following doesn't apply any longer - any tuning possible?
1921 (We can't use a fixed offset since with the '-s' flag lines aren't
1922 truncated.)
1923
1924 We maintain a list (line_vector) of pointers to the beginnings
1925 of lines in buff. We allocate one more than the number of lines
1926 because the last entry tells us the index of the last character,
1927 which we need to know in order to print the last line in buff. */
1928
1929static void
1930init_store_cols (void)
1931{
1932 int total_lines = lines_per_body * columns;
1933 int chars_if_truncate = total_lines * (chars_per_column + 1);
1934
1935 free (line_vector);
1936 /* FIXME: here's where it was allocated. */
1937 line_vector = xmalloc ((total_lines + 1) * sizeof (int *));
1938
1939 free (end_vector);
1940 end_vector = xmalloc (total_lines * sizeof (int *));
1941
1942 free (buff);
1943 buff_allocated = (use_col_separator
1944 ? 2 * chars_if_truncate
1945 : chars_if_truncate); /* Tune this. */
1946 buff = xmalloc (buff_allocated);
1947}
1948
1949/* Store all but the rightmost column.
1950 (Used when printing a single file in multiple downward columns)
1951
1952 For each column
1953 set p->current_line to be the index in line_vector of the
1954 first line in the column
1955 For each line in the column
1956 store the line in buff
1957 add to line_vector the index of the line's first char
1958 buff_start is the index in buff of the first character in the
1959 current line. */
1960
1961static void
1962store_columns (void)
1963{
1964 int i, j;
1965 int line = 0;
1966 int buff_start;
1967 int last_col; /* The rightmost column which will be saved in buff */
1968 COLUMN *p;
1969
1970 buff_current = 0;
1971 buff_start = 0;
1972
1973 if (balance_columns)
1974 last_col = columns;
1975 else
1976 last_col = columns - 1;
1977
1978 for (i = 1, p = column_vector; i <= last_col; ++i, ++p)
1979 p->lines_stored = 0;
1980
1981 for (i = 1, p = column_vector; i <= last_col && files_ready_to_read;
1982 ++i, ++p)
1983 {
1984 p->current_line = line;
1985 for (j = lines_per_body; j && files_ready_to_read; --j)
1986
1987 if (p->status == OPEN) /* Redundant. Clean up. */
1988 {
1989 input_position = 0;
1990
1991 if (!read_line (p))
1992 read_rest_of_line (p);
1993
1994 if (p->status == OPEN
1995 || buff_start != buff_current)
1996 {
1997 ++p->lines_stored;
1998 line_vector[line] = buff_start;
1999 end_vector[line++] = input_position;
2000 buff_start = buff_current;
2001 }
2002 }
2003 }
2004
2005 /* Keep track of the location of the last char in buff. */
2006 line_vector[line] = buff_start;
2007
2008 if (balance_columns)
2009 balance (line);
2010}
2011
2012static void
2013balance (int total_stored)
2014{
2015 COLUMN *p;
2016 int i, lines;
2017 int first_line = 0;
2018
2019 for (i = 1, p = column_vector; i <= columns; ++i, ++p)
2020 {
2021 lines = total_stored / columns;
2022 if (i <= total_stored % columns)
2023 ++lines;
2024
2025 p->lines_stored = lines;
2026 p->current_line = first_line;
2027
2028 first_line += lines;
2029 }
2030}
2031
2032/* Store a character in the buffer. */
2033
2034static void
2035store_char (char c)
2036{
2037 if (buff_current >= buff_allocated)
2038 {
2039 /* May be too generous. */
2040 buff = X2REALLOC (buff, &buff_allocated);
2041 }
2042 buff[buff_current++] = c;
2043}
2044
2045static void
2046add_line_number (COLUMN *p)
2047{
2048 int i;
2049 char *s;
2050 int left_cut;
2051
2052 /* Cutting off the higher-order digits is more informative than
2053 lower-order cut off*/
2054 if (line_number < power_10)
2055 sprintf (number_buff, "%*d", chars_per_number, line_number);
2056 else
2057 {
2058 left_cut = line_number % power_10;
2059 sprintf (number_buff, "%0*d", chars_per_number, left_cut);
2060 }
2061 line_number++;
2062 s = number_buff;
2063 for (i = chars_per_number; i > 0; i--)
2064 (p->char_func) (*s++);
2065
2066 if (columns > 1)
2067 {
2068 /* Tabification is assumed for multiple columns, also for n-separators,
2069 but `default n-separator = TAB' hasn't been given priority over
2070 equal column_width also specified by POSIX. */
2071 if (number_separator == '\t')
2072 {
2073 i = number_width - chars_per_number;
2074 while (i-- > 0)
2075 (p->char_func) (' ');
2076 }
2077 else
2078 (p->char_func) (number_separator);
2079 }
2080 else
2081 /* To comply with POSIX, we avoid any expansion of default TAB
2082 separator with a single column output. No column_width requirement
2083 has to be considered. */
2084 {
2085 (p->char_func) (number_separator);
2086 if (number_separator == '\t')
2087 output_position = POS_AFTER_TAB (chars_per_output_tab,
2088 output_position);
2089 }
2090
2091 if (truncate_lines & !parallel_files)
2092 input_position += number_width;
2093}
2094
2095
2096/* Print (or store) padding until the current horizontal position
2097 is position. */
2098
2099static void
2100pad_across_to (int position)
2101{
2102 int h = output_position;
2103
2104 if (tabify_output)
2105 spaces_not_printed = position - output_position;
2106 else
2107 {
2108 while (++h <= position)
2109 putchar (' ');
2110 output_position = position;
2111 }
2112}
2113
2114/* Pad to the bottom of the page.
2115
2116 If the user has requested a formfeed, use one.
2117 Otherwise, use newlines. */
2118
2119static void
2120pad_down (int lines)
2121{
2122 int i;
2123
2124 if (use_form_feed)
2125 putchar ('\f');
2126 else
2127 for (i = lines; i; --i)
2128 putchar ('\n');
2129}
2130
2131/* Read the rest of the line.
2132
2133 Read from the current column's file until an end of line is
2134 hit. Used when we've truncated a line and we no longer need
2135 to print or store its characters. */
2136
2137static void
2138read_rest_of_line (COLUMN *p)
2139{
2140 int c;
2141 FILE *f = p->fp;
2142
2143 while ((c = getc (f)) != '\n')
2144 {
2145 if (c == '\f')
2146 {
2147 if ((c = getc (f)) != '\n')
2148 ungetc (c, f);
2149 if (keep_FF)
2150 print_a_FF = true;
2151 hold_file (p);
2152 break;
2153 }
2154 else if (c == EOF)
2155 {
2156 close_file (p);
2157 break;
2158 }
2159 }
2160}
2161
2162/* Read a line with skip_to_page.
2163
2164 Read from the current column's file until an end of line is
2165 hit. Used when we read full lines to skip pages.
2166 With skip_to_page we have to check for FF-coincidence which is done
2167 in function read_line otherwise.
2168 Count lines of skipped pages to find the line number of 1st page
2169 printed relative to 1st line of input file (start_line_num). */
2170
2171static void
2172skip_read (COLUMN *p, int column_number)
2173{
2174 int c;
2175 FILE *f = p->fp;
2176 int i;
2177 bool single_ff = false;
2178 COLUMN *q;
2179
2180 /* Read 1st character in a line or any character succeeding a FF */
2181 if ((c = getc (f)) == '\f' && p->full_page_printed)
2182 /* A FF-coincidence with a previous full_page_printed.
2183 To avoid an additional empty page, eliminate the FF */
2184 if ((c = getc (f)) == '\n')
2185 c = getc (f);
2186
2187 p->full_page_printed = false;
2188
2189 /* 1st character a FF means a single FF without any printable
2190 characters. Don't count it as a line with -n option. */
2191 if (c == '\f')
2192 single_ff = true;
2193
2194 /* Preparing for a FF-coincidence: Maybe we finish that page
2195 without a FF found */
2196 if (last_line)
2197 p->full_page_printed = true;
2198
2199 while (c != '\n')
2200 {
2201 if (c == '\f')
2202 {
2203 /* No FF-coincidence possible,
2204 no catching up of a FF-coincidence with next page */
2205 if (last_line)
2206 {
2207 if (!parallel_files)
2208 for (q = column_vector, i = columns; i; ++q, --i)
2209 q->full_page_printed = false;
2210 else
2211 p->full_page_printed = false;
2212 }
2213
2214 if ((c = getc (f)) != '\n')
2215 ungetc (c, f);
2216 hold_file (p);
2217 break;
2218 }
2219 else if (c == EOF)
2220 {
2221 close_file (p);
2222 break;
2223 }
2224 c = getc (f);
2225 }
2226
2227 if (skip_count)
2228 if ((!parallel_files || column_number == 1) && !single_ff)
2229 ++line_count;
2230}
2231
2232
2233/* If we're tabifying output,
2234
2235 When print_char encounters white space it keeps track
2236 of our desired horizontal position and delays printing
2237 until this function is called. */
2238
2239static void
2240print_white_space (void)
2241{
2242 int h_new;
2243 int h_old = output_position;
2244 int goal = h_old + spaces_not_printed;
2245
2246 while (goal - h_old > 1
2247 && (h_new = POS_AFTER_TAB (chars_per_output_tab, h_old)) <= goal)
2248 {
2249 putchar (output_tab_char);
2250 h_old = h_new;
2251 }
2252 while (++h_old <= goal)
2253 putchar (' ');
2254
2255 output_position = goal;
2256 spaces_not_printed = 0;
2257}
2258
2259/* Print column separators.
2260
2261 We keep a count until we know that we'll be printing a line,
2262 then print_sep_string() is called. */
2263
2264static void
2265print_sep_string (void)
2266{
2267 char *s;
2268 int l = col_sep_length;
2269
2270 s = col_sep_string;
2271
2272 if (separators_not_printed <= 0)
2273 {
2274 /* We'll be starting a line with chars_per_margin, anything else? */
2275 if (spaces_not_printed > 0)
2276 print_white_space ();
2277 }
2278 else
2279 {
2280 for (; separators_not_printed > 0; --separators_not_printed)
2281 {
2282 while (l-- > 0)
2283 {
2284 /* 3 types of sep_strings: spaces only, spaces and chars,
2285 chars only */
2286 if (*s == ' ')
2287 {
2288 /* We're tabifying output; consecutive spaces in
2289 sep_string may have to be converted to tabs */
2290 s++;
2291 ++spaces_not_printed;
2292 }
2293 else
2294 {
2295 if (spaces_not_printed > 0)
2296 print_white_space ();
2297 putchar (*s++);
2298 ++output_position;
2299 }
2300 }
2301 /* sep_string ends with some spaces */
2302 if (spaces_not_printed > 0)
2303 print_white_space ();
2304 }
2305 }
2306}
2307
2308/* Print (or store, depending on p->char_func) a clump of N
2309 characters. */
2310
2311static void
2312print_clump (COLUMN *p, int n, char *clump)
2313{
2314 while (n--)
2315 (p->char_func) (*clump++);
2316}
2317
2318/* Print a character.
2319
2320 Update the following comment: process-char hasn't been used any
2321 longer.
2322 If we're tabifying, all tabs have been converted to spaces by
2323 process_char(). Keep a count of consecutive spaces, and when
2324 a nonspace is encountered, call print_white_space() to print the
2325 required number of tabs and spaces. */
2326
2327static void
2328print_char (char c)
2329{
2330 if (tabify_output)
2331 {
2332 if (c == ' ')
2333 {
2334 ++spaces_not_printed;
2335 return;
2336 }
2337 else if (spaces_not_printed > 0)
2338 print_white_space ();
2339
2340 /* Nonprintables are assumed to have width 0, except '\b'. */
2341 if (!ISPRINT (to_uchar (c)))
2342 {
2343 if (c == '\b')
2344 --output_position;
2345 }
2346 else
2347 ++output_position;
2348 }
2349 putchar (c);
2350}
2351
2352/* Skip to page PAGE before printing.
2353 PAGE may be larger than total number of pages. */
2354
2355static bool
2356skip_to_page (uintmax_t page)
2357{
2358 uintmax_t n;
2359 int i;
2360 int j;
2361 COLUMN *p;
2362
2363 for (n = 1; n < page; ++n)
2364 {
2365 for (i = 1; i < lines_per_body; ++i)
2366 {
2367 for (j = 1, p = column_vector; j <= columns; ++j, ++p)
2368 if (p->status == OPEN)
2369 skip_read (p, j);
2370 }
2371 last_line = true;
2372 for (j = 1, p = column_vector; j <= columns; ++j, ++p)
2373 if (p->status == OPEN)
2374 skip_read (p, j);
2375
2376 if (storing_columns) /* change FF_FOUND to ON_HOLD */
2377 for (j = 1, p = column_vector; j <= columns; ++j, ++p)
2378 if (p->status != CLOSED)
2379 p->status = ON_HOLD;
2380
2381 reset_status ();
2382 last_line = false;
2383
2384 if (files_ready_to_read < 1)
2385 {
2386 /* It's very helpful, normally the total number of pages is
2387 not known in advance. */
2388 error (0, 0,
2389 _("starting page number %"PRIuMAX
2390 " exceeds page count %"PRIuMAX),
2391 page, n);
2392 break;
2393 }
2394 }
2395 return files_ready_to_read > 0;
2396}
2397
2398/* Print a header.
2399
2400 Formfeeds are assumed to use up two lines at the beginning of
2401 the page. */
2402
2403static void
2404print_header (void)
2405{
2406 char page_text[256 + INT_STRLEN_BOUND (page_number)];
2407 int available_width;
2408 int lhs_spaces;
2409 int rhs_spaces;
2410
2411 if (!use_form_feed)
2412 printf ("\n\n");
2413
2414 output_position = 0;
2415 pad_across_to (chars_per_margin);
2416 print_white_space ();
2417
2418 if (page_number == 0)
2419 error (EXIT_FAILURE, 0, _("Page number overflow"));
2420
2421 /* The translator must ensure that formatting the translation of
2422 "Page %"PRIuMAX does not generate more than (sizeof page_text - 1)
2423 bytes. */
2424 sprintf (page_text, _("Page %"PRIuMAX), page_number++);
2425 available_width = header_width_available - mbswidth (page_text, 0);
2426 available_width = MAX (0, available_width);
2427 lhs_spaces = available_width >> 1;
2428 rhs_spaces = available_width - lhs_spaces;
2429
2430 printf ("%s%*s%s%*s%s\n\n\n",
2431 date_text, lhs_spaces, " ", file_text, rhs_spaces, " ", page_text);
2432
2433 print_a_header = false;
2434 output_position = 0;
2435}
2436
2437/* Print (or store, if p->char_func is store_char()) a line.
2438
2439 Read a character to determine whether we have a line or not.
2440 (We may hit EOF, \n, or \f)
2441
2442 Once we know we have a line,
2443 set pad_vertically = true, meaning it's safe
2444 to pad down at the end of the page, since we do have a page.
2445 print a header if needed.
2446 pad across to padding_not_printed if needed.
2447 print any separators which need to be printed.
2448 print a line number if it needs to be printed.
2449
2450 Print the clump which corresponds to the first character.
2451
2452 Enter a loop and keep printing until an end of line condition
2453 exists, or until we exceed chars_per_column.
2454
2455 Return false if we exceed chars_per_column before reading
2456 an end of line character, true otherwise. */
2457
2458static bool
2459read_line (COLUMN *p)
2460{
2461 int c;
2462 int chars IF_LINT (= 0);
2463 int last_input_position;
2464 int j, k;
2465 COLUMN *q;
2466
2467 /* read 1st character in each line or any character succeeding a FF: */
2468 c = getc (p->fp);
2469
2470 last_input_position = input_position;
2471
2472 if (c == '\f' && p->full_page_printed)
2473 if ((c = getc (p->fp)) == '\n')
2474 c = getc (p->fp);
2475 p->full_page_printed = false;
2476
2477 switch (c)
2478 {
2479 case '\f':
2480 if ((c = getc (p->fp)) != '\n')
2481 ungetc (c, p->fp);
2482 FF_only = true;
2483 if (print_a_header & !storing_columns)
2484 {
2485 pad_vertically = true;
2486 print_header ();
2487 }
2488 else if (keep_FF)
2489 print_a_FF = true;
2490 hold_file (p);
2491 return true;
2492 case EOF:
2493 close_file (p);
2494 return true;
2495 case '\n':
2496 break;
2497 default:
2498 chars = char_to_clump (c);
2499 }
2500
2501 if (truncate_lines && input_position > chars_per_column)
2502 {
2503 input_position = last_input_position;
2504 return false;
2505 }
2506
2507 if (p->char_func != store_char)
2508 {
2509 pad_vertically = true;
2510
2511 if (print_a_header & !storing_columns)
2512 print_header ();
2513
2514 if (parallel_files & align_empty_cols)
2515 {
2516 /* We have to align empty columns at the beginning of a line. */
2517 k = separators_not_printed;
2518 separators_not_printed = 0;
2519 for (j = 1, q = column_vector; j <= k; ++j, ++q)
2520 {
2521 align_column (q);
2522 separators_not_printed += 1;
2523 }
2524 padding_not_printed = p->start_position;
2525 if (truncate_lines)
2526 spaces_not_printed = chars_per_column;
2527 else
2528 spaces_not_printed = 0;
2529 align_empty_cols = false;
2530 }
2531
2532 if (padding_not_printed - col_sep_length > 0)
2533 {
2534 pad_across_to (padding_not_printed - col_sep_length);
2535 padding_not_printed = ANYWHERE;
2536 }
2537
2538 if (use_col_separator)
2539 print_sep_string ();
2540 }
2541
2542 if (p->numbered)
2543 add_line_number (p);
2544
2545 empty_line = false;
2546 if (c == '\n')
2547 return true;
2548
2549 print_clump (p, chars, clump_buff);
2550
2551 for (;;)
2552 {
2553 c = getc (p->fp);
2554
2555 switch (c)
2556 {
2557 case '\n':
2558 return true;
2559 case '\f':
2560 if ((c = getc (p->fp)) != '\n')
2561 ungetc (c, p->fp);
2562 if (keep_FF)
2563 print_a_FF = true;
2564 hold_file (p);
2565 return true;
2566 case EOF:
2567 close_file (p);
2568 return true;
2569 }
2570
2571 last_input_position = input_position;
2572 chars = char_to_clump (c);
2573 if (truncate_lines && input_position > chars_per_column)
2574 {
2575 input_position = last_input_position;
2576 return false;
2577 }
2578
2579 print_clump (p, chars, clump_buff);
2580 }
2581}
2582
2583/* Print a line from buff.
2584
2585 If this function has been called, we know we have "something to
2586 print". But it remains to be seen whether we have a real text page
2587 or an empty page (a single form feed) with/without a header only.
2588 Therefore first we set pad_vertically to true and print a header
2589 if necessary.
2590 If FF_FOUND and we are using -t|-T option we omit any newline by
2591 setting pad_vertically to false (see print_page).
2592 Otherwise we pad across if necessary, print separators if necessary
2593 and text of COLUMN *p.
2594
2595 Return true, meaning there is no need to call read_rest_of_line. */
2596
2597static bool
2598print_stored (COLUMN *p)
2599{
2600 COLUMN *q;
2601 int i;
2602
2603 int line = p->current_line++;
2604 char *first = &buff[line_vector[line]];
2605 /* FIXME
2606 UMR: Uninitialized memory read:
2607 * This is occurring while in:
2608 print_stored [pr.c:2239]
2609 * Reading 4 bytes from 0x5148c in the heap.
2610 * Address 0x5148c is 4 bytes into a malloc'd block at 0x51488 of 676 bytes
2611 * This block was allocated from:
2612 malloc [rtlib.o]
2613 xmalloc [xmalloc.c:94]
2614 init_store_cols [pr.c:1648]
2615 */
2616 char *last = &buff[line_vector[line + 1]];
2617
2618 pad_vertically = true;
2619
2620 if (print_a_header)
2621 print_header ();
2622
2623 if (p->status == FF_FOUND)
2624 {
2625 for (i = 1, q = column_vector; i <= columns; ++i, ++q)
2626 q->status = ON_HOLD;
2627 if (column_vector->lines_to_print <= 0)
2628 {
2629 if (!extremities)
2630 pad_vertically = false;
2631 return true; /* print a header only */
2632 }
2633 }
2634
2635 if (padding_not_printed - col_sep_length > 0)
2636 {
2637 pad_across_to (padding_not_printed - col_sep_length);
2638 padding_not_printed = ANYWHERE;
2639 }
2640
2641 if (use_col_separator)
2642 print_sep_string ();
2643
2644 while (first != last)
2645 print_char (*first++);
2646
2647 if (spaces_not_printed == 0)
2648 {
2649 output_position = p->start_position + end_vector[line];
2650 if (p->start_position - col_sep_length == chars_per_margin)
2651 output_position -= col_sep_length;
2652 }
2653
2654 return true;
2655}
2656
2657/* Convert a character to the proper format and return the number of
2658 characters in the resulting clump. Increment input_position by
2659 the width of the clump.
2660
2661 Tabs are converted to clumps of spaces.
2662 Nonprintable characters may be converted to clumps of escape
2663 sequences or control prefixes.
2664
2665 Note: the width of a clump is not necessarily equal to the number of
2666 characters in clump_buff. (e.g, the width of '\b' is -1, while the
2667 number of characters is 1.) */
2668
2669static int
2670char_to_clump (char c)
2671{
2672 unsigned char uc = c;
2673 char *s = clump_buff;
2674 int i;
2675 char esc_buff[4];
2676 int width;
2677 int chars;
2678 int chars_per_c = 8;
2679
2680 if (c == input_tab_char)
2681 chars_per_c = chars_per_input_tab;
2682
2683 if (c == input_tab_char || c == '\t')
2684 {
2685 width = TAB_WIDTH (chars_per_c, input_position);
2686
2687 if (untabify_input)
2688 {
2689 for (i = width; i; --i)
2690 *s++ = ' ';
2691 chars = width;
2692 }
2693 else
2694 {
2695 *s = c;
2696 chars = 1;
2697 }
2698
2699 }
2700 else if (!ISPRINT (uc))
2701 {
2702 if (use_esc_sequence)
2703 {
2704 width = 4;
2705 chars = 4;
2706 *s++ = '\\';
2707 sprintf (esc_buff, "%03o", uc);
2708 for (i = 0; i <= 2; ++i)
2709 *s++ = esc_buff[i];
2710 }
2711 else if (use_cntrl_prefix)
2712 {
2713 if (uc < 0200)
2714 {
2715 width = 2;
2716 chars = 2;
2717 *s++ = '^';
2718 *s++ = c ^ 0100;
2719 }
2720 else
2721 {
2722 width = 4;
2723 chars = 4;
2724 *s++ = '\\';
2725 sprintf (esc_buff, "%03o", uc);
2726 for (i = 0; i <= 2; ++i)
2727 *s++ = esc_buff[i];
2728 }
2729 }
2730 else if (c == '\b')
2731 {
2732 width = -1;
2733 chars = 1;
2734 *s = c;
2735 }
2736 else
2737 {
2738 width = 0;
2739 chars = 1;
2740 *s = c;
2741 }
2742 }
2743 else
2744 {
2745 width = 1;
2746 chars = 1;
2747 *s = c;
2748 }
2749
2750 input_position += width;
2751 return chars;
2752}
2753
2754/* We've just printed some files and need to clean up things before
2755 looking for more options and printing the next batch of files.
2756
2757 Free everything we've xmalloc'ed, except `header'. */
2758
2759static void
2760cleanup (void)
2761{
2762 free (number_buff);
2763 free (clump_buff);
2764 free (column_vector);
2765 free (line_vector);
2766 free (end_vector);
2767 free (buff);
2768}
2769
2770
2771/* Complain, print a usage message, and die. */
2772
2773void
2774usage (int status)
2775{
2776 if (status != EXIT_SUCCESS)
2777 fprintf (stderr, _("Try `%s --help' for more information.\n"),
2778 program_name);
2779 else
2780 {
2781 printf (_("\
2782Usage: %s [OPTION]... [FILE]...\n\
2783"),
2784 program_name);
2785
2786 fputs (_("\
2787Paginate or columnate FILE(s) for printing.\n\
2788\n\
2789"), stdout);
2790 fputs (_("\
2791Mandatory arguments to long options are mandatory for short options too.\n\
2792"), stdout);
2793 fputs (_("\
2794 +FIRST_PAGE[:LAST_PAGE], --pages=FIRST_PAGE[:LAST_PAGE]\n\
2795 begin [stop] printing with page FIRST_[LAST_]PAGE\n\
2796 -COLUMN, --columns=COLUMN\n\
2797 output COLUMN columns and print columns down,\n\
2798 unless -a is used. Balance number of lines in the\n\
2799 columns on each page.\n\
2800"), stdout);
2801 fputs (_("\
2802 -a, --across print columns across rather than down, used together\n\
2803 with -COLUMN\n\
2804 -c, --show-control-chars\n\
2805 use hat notation (^G) and octal backslash notation\n\
2806 -d, --double-space\n\
2807 double space the output\n\
2808"), stdout);
2809 fputs (_("\
2810 -D, --date-format=FORMAT\n\
2811 use FORMAT for the header date\n\
2812 -e[CHAR[WIDTH]], --expand-tabs[=CHAR[WIDTH]]\n\
2813 expand input CHARs (TABs) to tab WIDTH (8)\n\
2814 -F, -f, --form-feed\n\
2815 use form feeds instead of newlines to separate pages\n\
2816 (by a 3-line page header with -F or a 5-line header\n\
2817 and trailer without -F)\n\
2818"), stdout);
2819 fputs (_("\
2820 -h HEADER, --header=HEADER\n\
2821 use a centered HEADER instead of filename in page header,\n\
2822 -h \"\" prints a blank line, don't use -h\"\"\n\
2823 -i[CHAR[WIDTH]], --output-tabs[=CHAR[WIDTH]]\n\
2824 replace spaces with CHARs (TABs) to tab WIDTH (8)\n\
2825 -J, --join-lines merge full lines, turns off -W line truncation, no column\n\
2826 alignment, --sep-string[=STRING] sets separators\n\
2827"), stdout);
2828 fputs (_("\
2829 -l PAGE_LENGTH, --length=PAGE_LENGTH\n\
2830 set the page length to PAGE_LENGTH (66) lines\n\
2831 (default number of lines of text 56, and with -F 63)\n\
2832 -m, --merge print all files in parallel, one in each column,\n\
2833 truncate lines, but join lines of full length with -J\n\
2834"), stdout);
2835 fputs (_("\
2836 -n[SEP[DIGITS]], --number-lines[=SEP[DIGITS]]\n\
2837 number lines, use DIGITS (5) digits, then SEP (TAB),\n\
2838 default counting starts with 1st line of input file\n\
2839 -N NUMBER, --first-line-number=NUMBER\n\
2840 start counting with NUMBER at 1st line of first\n\
2841 page printed (see +FIRST_PAGE)\n\
2842"), stdout);
2843 fputs (_("\
2844 -o MARGIN, --indent=MARGIN\n\
2845 offset each line with MARGIN (zero) spaces, do not\n\
2846 affect -w or -W, MARGIN will be added to PAGE_WIDTH\n\
2847 -r, --no-file-warnings\n\
2848 omit warning when a file cannot be opened\n\
2849"), stdout);
2850 fputs (_("\
2851 -s[CHAR],--separator[=CHAR]\n\
2852 separate columns by a single character, default for CHAR\n\
2853 is the <TAB> character without -w and \'no char\' with -w\n\
2854 -s[CHAR] turns off line truncation of all 3 column\n\
2855 options (-COLUMN|-a -COLUMN|-m) except -w is set\n\
2856"), stdout);
2857 fputs (_("\
2858 -SSTRING, --sep-string[=STRING]\n\
2859"), stdout);
2860 fputs (_("\
2861 separate columns by STRING,\n\
2862 without -S: Default separator <TAB> with -J and <space>\n\
2863 otherwise (same as -S\" \"), no effect on column options\n\
2864 -t, --omit-header omit page headers and trailers\n\
2865"), stdout);
2866 fputs (_("\
2867 -T, --omit-pagination\n\
2868 omit page headers and trailers, eliminate any pagination\n\
2869 by form feeds set in input files\n\
2870 -v, --show-nonprinting\n\
2871 use octal backslash notation\n\
2872 -w PAGE_WIDTH, --width=PAGE_WIDTH\n\
2873 set page width to PAGE_WIDTH (72) characters for\n\
2874 multiple text-column output only, -s[char] turns off (72)\n\
2875"), stdout);
2876 fputs (_("\
2877 -W PAGE_WIDTH, --page-width=PAGE_WIDTH\n\
2878 set page width to PAGE_WIDTH (72) characters always,\n\
2879 truncate lines, except -J option is set, no interference\n\
2880 with -S or -s\n\
2881"), stdout);
2882 fputs (HELP_OPTION_DESCRIPTION, stdout);
2883 fputs (VERSION_OPTION_DESCRIPTION, stdout);
2884 fputs (_("\
2885\n\
2886-T implied by -l nn when nn <= 10 or <= 3 with -F. With no FILE, or when\n\
2887FILE is -, read standard input.\n\
2888"), stdout);
2889 printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
2890 }
2891 exit (status);
2892}
Note: See TracBrowser for help on using the repository browser.