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