diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2016-01-20 10:55:18 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2016-01-20 10:55:18 +0000 |
commit | 70e9163c9c18e995515598085cb824e554eb7ae7 (patch) | |
tree | a42dc8b2a6c031354bf31472de888bfc8a060132 /src/pr.c | |
parent | cbf5993c43f49281173f185863577d86bfac6eae (diff) | |
download | coreutils-tarball-70e9163c9c18e995515598085cb824e554eb7ae7.tar.gz |
coreutils-8.25HEADcoreutils-8.25master
Diffstat (limited to 'src/pr.c')
-rw-r--r-- | src/pr.c | 1821 |
1 files changed, 888 insertions, 933 deletions
@@ -1,10 +1,10 @@ /* pr -- convert text files for printing. - Copyright (C) 88, 91, 1995-2007 Free Software Foundation, Inc. + Copyright (C) 1988-2016 Free Software Foundation, Inc. - This program is free software; you can redistribute it and/or modify + This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -12,11 +12,10 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + along with this program. If not, see <http://www.gnu.org/licenses/>. */ /* By Pete TerMaat, with considerable refinement by Roland Huebner. */ - + /* Things to watch: Sys V screws up on ... pr -n -3 -s: /usr/dict/words pr -m -o10 -n /usr/dict/words{,,,} @@ -35,26 +34,26 @@ Concept: If the input_tab_char differs from the default value TAB - (`-e[CHAR[...]]' is used), any input text tab is expanded to the + ('-e[CHAR[...]]' is used), any input text tab is expanded to the default width of 8 spaces (compare char_to_clump). - Same as SunOS does. The treatment of the number_separator (compare add_line_number): - The default value TAB of the number_separator (`-n[SEP[...]]') doesn't - be thought to be an input character. An optional `-e'-input has no + The default value TAB of the number_separator ('-n[SEP[...]]') doesn't + be thought to be an input character. An optional '-e'-input has no effect. - With single column output only one POSIX requirement has to be met: The default n-separator should be a TAB. The consequence is a different width between the number and the text if the output position - of the separator changes, i.e. it depends upon the left margin used. + of the separator changes, i.e., it depends upon the left margin used. That's not nice but easy-to-use together with the defaults of other utilities, e.g. sort or cut. - Same as SunOS does. - With multicolumn output two conflicting POSIX requirements exist: - First `default n-separator is TAB', second `output text columns shall - be of equal width'. Moreover POSIX specifies the number+separator a - part of the column, together with `-COLUMN' and `-a -COLUMN'. + First "default n-separator is TAB", second "output text columns shall + be of equal width". Moreover POSIX specifies the number+separator a + part of the column, together with '-COLUMN' and '-a -COLUMN'. (With -m output the number shall occupy each line only once. Exactly the same situation as single column output exists.) GNU pr gives priority to the 2nd requirement and observes POSIX @@ -73,9 +72,9 @@ PAGE_WIDTH may occur. The interference of the POSIX-compliant small letter options -w and -s: - (`interference' means `setting a _separator_ with -s switches off the - column sturctur and the default - not generally - page_width, - acts on -w option') + ("interference" means "setting a _separator_ with -s switches off the + column structure and the default - not generally - page_width, + acts on -w option") options: text form / separator: equivalent new options: -w l -s[x] -------------------------------------------------------------------- @@ -93,7 +92,7 @@ Options: Including version 1.22i: - Some SMALL LETTER options has been redefined with the object of a + Some SMALL LETTER options have been redefined with the object of a better POSIX compliance. The output of some further cases has been adapted to other UNIXes. A violation of downward compatibility has to be accepted. @@ -113,201 +112,200 @@ form feeds produce empty pages. +FIRST_PAGE[:LAST_PAGE], --pages=FIRST_PAGE[:LAST_PAGE] - begin [stop] printing with page FIRST_[LAST_]PAGE + begin [stop] printing with page FIRST_[LAST_]PAGE -COLUMN, --columns=COLUMN - Produce output that is COLUMN columns wide and - print columns down, unless -a is used. Balance number of - lines in the columns on each page. + Produce output that is COLUMN columns wide and + print columns down, unless -a is used. Balance number of + lines in the columns on each page. -a, --across Print columns across rather than down, used - together with -COLUMN. The input - one - two - three - four - will be printed with `-a -3' as - one two three - four + together with -COLUMN. The input + one + two + three + four + will be printed with '-a -3' as + one two three + four -b Balance columns on the last page. - -b is no longer an independent option. It's always used - together with -COLUMN (unless -a is used) to get a - consistent formulation with "FF set by hand" in input - files. Each formfeed found terminates the number of lines - to be read with the actual page. The situation for - printing columns down is equivalent to that on the last - page. So we need a balancing. - - Keeping -b as an underground option guarantees some - downward compatibility. Utilities using pr with -b - (a most frequently used form) still work as usual. + -b is no longer an independent option. It's always used + together with -COLUMN (unless -a is used) to get a + consistent formulation with "FF set by hand" in input + files. Each formfeed found terminates the number of lines + to be read with the actual page. The situation for + printing columns down is equivalent to that on the last + page. So we need a balancing. + + Keeping -b as an underground option guarantees some + downward compatibility. Utilities using pr with -b + (a most frequently used form) still work as usual. -c, --show-control-chars - Print unprintable characters as control prefixes. - Control-g is printed as ^G (use hat notation) and - octal backslash notation. + Print unprintable characters as control prefixes. + Control-g is printed as ^G (use hat notation) and + octal backslash notation. -d, --double-space Double space the output. -D FORMAT, --date-format=FORMAT Use FORMAT for the header date. -e[CHAR[WIDTH]], --expand-tabs[=CHAR[WIDTH]] - Expand tabs to spaces on input. Optional argument CHAR - is the input TAB character. (Default is TAB). Optional - argument WIDTH is the input TAB character's width. - (Default is 8.) + Expand tabs to spaces on input. Optional argument CHAR + is the input TAB character. (Default is TAB). Optional + argument WIDTH is the input TAB character's width. + (Default is 8.) -F, -f, --form-feed Use formfeeds instead of newlines to separate - pages. A three line HEADER is used, no TRAILER with -F, - without -F both HEADER and TRAILER are made of five lines. + pages. A three line HEADER is used, no TRAILER with -F, + without -F both HEADER and TRAILER are made of five lines. -h HEADER, --header=HEADER - Replace the filename in the header with the string HEADER. - A centered header is used. + Replace the filename in the header with the string HEADER. + A centered header is used. -i[CHAR[WIDTH]], --output-tabs[=CHAR[WIDTH]] - Replace spaces with tabs on output. Optional argument - CHAR is the output TAB character. (Default is TAB). - Optional argument WIDTH is the output TAB character's - width. (Default is 8) + Replace spaces with tabs on output. Optional argument + CHAR is the output TAB character. (Default is TAB). + Optional argument WIDTH is the output TAB character's + width. (Default is 8) -J, --join-lines Merge lines of full length, turns off -W/-w - line truncation, no column alignment, --sep-string[=STRING] - sets separators, works with all column options - (-COLUMN | -a -COLUMN | -m). - -J has been introduced (together with -W and --sep-string) to - disentangle the old (POSIX compliant) options -w, -s - along with the 3 column options. + line truncation, no column alignment, --sep-string[=STRING] + sets separators, works with all column options + (-COLUMN | -a -COLUMN | -m). + -J has been introduced (together with -W and --sep-string) to + disentangle the old (POSIX compliant) options -w, -s + along with the 3 column options. -l PAGE_LENGTH, --length=PAGE_LENGTH - Set the page length to PAGE_LENGTH lines. Default is 66, - including 5 lines of HEADER and 5 lines of TRAILER - without -F, but only 3 lines of HEADER and no TRAILER - with -F (i.e the number of text lines defaults to 56 or - 63 respectively). + Set the page length to PAGE_LENGTH lines. Default is 66, + including 5 lines of HEADER and 5 lines of TRAILER + without -F, but only 3 lines of HEADER and no TRAILER + with -F (i.e the number of text lines defaults to 56 or + 63 respectively). -m, --merge Print files in parallel; pad_across_to align - columns; truncate lines and print separator strings; - Do it also with empty columns to get a continuous line - numbering and column marking by separators throughout - the whole merged file. + columns; truncate lines and print separator strings; + Do it also with empty columns to get a continuous line + numbering and column marking by separators throughout + the whole merged file. - Empty pages in some input files produce empty columns - [marked by separators] in the merged pages. Completely - empty merged pages show no column separators at all. + Empty pages in some input files produce empty columns + [marked by separators] in the merged pages. Completely + empty merged pages show no column separators at all. - The layout of a merged page is ruled by the largest form - feed distance of the single pages at that page. Shorter - columns will be filled up with empty lines. + The layout of a merged page is ruled by the largest form + feed distance of the single pages at that page. Shorter + columns will be filled up with empty lines. - Together with -J option join lines of full length and - set separators when -S option is used. + Together with -J option join lines of full length and + set separators when -S option is used. -n[SEP[DIGITS]], --number-lines[=SEP[DIGITS]] - Provide DIGITS digit line numbering (default for DIGITS - is 5). With multicolumn output the number occupies the - first DIGITS column positions of each text column or only - each line of -m output. - With single column output the number precedes each line - just as -m output. - Optional argument SEP is the character appended to the - line number to separate it from the text followed. - The default separator is a TAB. In a strict sense a TAB - is always printed with single column output only. The - TAB-width varies with the TAB-position, e.g. with the - left margin specified by -o option. - With multicolumn output priority is given to `equal width - of output columns' (a POSIX specification). The TAB-width - is fixed to the value of the 1st column and does not - change with different values of left margin. That means a - fixed number of spaces is always printed in the place of - a TAB. The tabification depends upon the output - position. - - Default counting of the line numbers starts with 1st - line of the input file (not the 1st line printed, - compare the --page option and -N option). + Provide DIGITS digit line numbering (default for DIGITS + is 5). With multicolumn output the number occupies the + first DIGITS column positions of each text column or only + each line of -m output. + With single column output the number precedes each line + just as -m output. + Optional argument SEP is the character appended to the + line number to separate it from the text followed. + The default separator is a TAB. In a strict sense a TAB + is always printed with single column output only. The + TAB-width varies with the TAB-position, e.g. with the + left margin specified by -o option. + With multicolumn output priority is given to "equal width + of output columns" (a POSIX specification). The TAB-width + is fixed to the value of the 1st column and does not + change with different values of left margin. That means a + fixed number of spaces is always printed in the place of + a TAB. The tabification depends upon the output + position. + + Default counting of the line numbers starts with 1st + line of the input file (not the 1st line printed, + compare the --page option and -N option). -N NUMBER, --first-line-number=NUMBER - Start line counting with the number NUMBER at the 1st - line of first page printed (mostly not the 1st line of - the input file). + Start line counting with the number NUMBER at the 1st + line of first page printed (mostly not the 1st line of + the input file). -o MARGIN, --indent=MARGIN - Offset each line with a margin MARGIN spaces wide. - Total page width is the size of the margin plus the - PAGE_WIDTH set with -W/-w option. + Offset each line with a margin MARGIN spaces wide. + Total page width is the size of the margin plus the + PAGE_WIDTH set with -W/-w option. -r, --no-file-warnings - Omit warning when a file cannot be opened. + Omit warning when a file cannot be opened. -s[CHAR], --separator[=CHAR] - Separate columns by a single character CHAR, default for - CHAR is the TAB character without -w and 'no char' with -w. - Without `-s' default separator `space' is set. - -s[CHAR] turns off line truncation of all 3 column options - (-COLUMN|-a -COLUMN|-m) except -w is set. That is a POSIX - compliant formulation. The source code translates -s into - the new options -S and -J, also -W if required. - - -S STRING, --sep-string[=STRING] - Separate columns by any string STRING. The -S option - doesn't react upon the -W/-w option (unlike -s option - does). It defines a separator nothing else. - Without -S: Default separator TAB is used with -J and - `space' otherwise (same as -S" "). - With -S "": No separator is used. - Quotes should be used with blanks and some shell active - characters. - -S is problematic because in its obsolete form you - cannot use -S "STRING", but in its standard form you - must use -S "STRING" if STRING is empty. Use - --sep-string to avoid the ambiguity. + Separate columns by a single character CHAR, default for + CHAR is the TAB character without -w and 'no char' with -w. + Without '-s' default separator 'space' is set. + -s[CHAR] turns off line truncation of all 3 column options + (-COLUMN|-a -COLUMN|-m) except -w is set. That is a POSIX + compliant formulation. The source code translates -s into + the new options -S and -J, also -W if required. + + -S[STRING], --sep-string[=STRING] + Separate columns by any string STRING. The -S option + doesn't react upon the -W/-w option (unlike -s option + does). It defines a separator nothing else. + Without -S: Default separator TAB is used with -J and + 'space' otherwise (same as -S" "). + With -S "": No separator is used. + Quotes should be used with blanks and some shell active + characters. + -S is problematic because in its obsolete form you + cannot use -S "STRING", but in its standard form you + must use -S "STRING" if STRING is empty. Use + --sep-string to avoid the ambiguity. -t, --omit-header Do not print headers or footers but retain form - feeds set in the input files. + feeds set in the input files. -T, --omit-pagination - Do not print headers or footers, eliminate any pagination - by form feeds set in the input files. + Do not print headers or footers, eliminate any pagination + by form feeds set in the input files. -v, --show-nonprinting - Print unprintable characters as escape sequences. Use - octal backslash notation. Control-G becomes \007. + Print unprintable characters as escape sequences. Use + octal backslash notation. Control-G becomes \007. -w PAGE_WIDTH, --width=PAGE_WIDTH - Set page width to PAGE_WIDTH characters for multiple - text-column output only (default for PAGE_WIDTH is 72). - -s[CHAR] turns off the default page width and any line - truncation. Lines of full length will be merged, - regardless of the column options set. A POSIX compliant - formulation. + Set page width to PAGE_WIDTH characters for multiple + text-column output only (default for PAGE_WIDTH is 72). + -s[CHAR] turns off the default page width and any line + truncation. Lines of full length will be merged, + regardless of the column options set. A POSIX compliant + formulation. -W PAGE_WIDTH, --page-width=PAGE_WIDTH - Set the page width to PAGE_WIDTH characters. That's valid - with and without a column option. Text lines will be - truncated, unless -J is used. Together with one of the - column options (-COLUMN| -a -COLUMN| -m) column alignment - is always used. - Default is 72 characters. - Without -W PAGE_WIDTH - - but with one of the column options default truncation of - 72 characters is used (to keep downward compatibility - and to simplify most frequently met column tasks). - Column alignment and column separators are used. - - and without any of the column options NO line truncation - is used (to keep downward compatibility and to meet most - frequent tasks). That's equivalent to -W 72 -J . - - With/without -W PAGE_WIDTH the header line is always - truncated to avoid line overflow. - - (In pr versions newer than 1.14 -S option does no longer - affect -W option.) + Set the page width to PAGE_WIDTH characters. That's valid + with and without a column option. Text lines will be + truncated, unless -J is used. Together with one of the + column options (-COLUMN| -a -COLUMN| -m) column alignment + is always used. + Default is 72 characters. + Without -W PAGE_WIDTH + - but with one of the column options default truncation of + 72 characters is used (to keep downward compatibility + and to simplify most frequently met column tasks). + Column alignment and column separators are used. + - and without any of the column options NO line truncation + is used (to keep downward compatibility and to meet most + frequent tasks). That's equivalent to -W 72 -J . + + With/without -W PAGE_WIDTH the header line is always + truncated to avoid line overflow. + + (In pr versions newer than 1.14 -S option does no longer + affect -W option.) */ - #include <config.h> @@ -315,19 +313,22 @@ #include <sys/types.h> #include "system.h" #include "error.h" +#include "fadvise.h" #include "hard-locale.h" -#include "inttostr.h" #include "mbswidth.h" #include "quote.h" #include "stat-time.h" #include "stdio--.h" #include "strftime.h" #include "xstrtol.h" +#include "xdectoint.h" -/* The official name of this program (e.g., no `g' prefix). */ +/* The official name of this program (e.g., no 'g' prefix). */ #define PROGRAM_NAME "pr" -#define AUTHORS "Pete TerMaat", "Roland Huebner" +#define AUTHORS \ + proper_name ("Pete TerMaat"), \ + proper_name ("Roland Huebner") /* Used with start_position in the struct COLUMN described below. If start_position == ANYWHERE, we aren't truncating columns and @@ -349,27 +350,27 @@ fit the same printing loop. print_func Function used to print lines in this column. - If we're storing this column it will be - print_stored(), Otherwise it will be read_line(). + If we're storing this column it will be + print_stored(), Otherwise it will be read_line(). char_func Function used to process characters in this column. - If we're storing this column it will be store_char(), - otherwise it will be print_char(). + If we're storing this column it will be store_char(), + otherwise it will be print_char(). current_line Index of the current entry in line_vector, which - contains the index of the first character of the - current line in buff[]. + contains the index of the first character of the + current line in buff[]. lines_stored Number of lines in this column which are stored in - buff. + buff. lines_to_print If we're storing this column, lines_to_print is - the number of stored_lines which remain to be - printed. Otherwise it is the number of lines - we can print without exceeding lines_per_body. + the number of stored_lines which remain to be + printed. Otherwise it is the number of lines + we can print without exceeding lines_per_body. start_position The horizontal position we want to be in before we - print the first character in this column. + print the first character in this column. numbered True means precede this column with a line number. */ @@ -385,11 +386,11 @@ struct COLUMN char const *name; /* File name. */ enum { - OPEN, - FF_FOUND, /* used with -b option, set with \f, changed - to ON_HOLD after print_header */ - ON_HOLD, /* Hit a form feed. */ - CLOSED + OPEN, + FF_FOUND, /* used with -b option, set with \f, changed + to ON_HOLD after print_header */ + ON_HOLD, /* Hit a form feed. */ + CLOSED } status; /* Status of the file pointer. */ @@ -414,8 +415,6 @@ struct COLUMN typedef struct COLUMN COLUMN; -#define NULLCOL (COLUMN *)0 - static int char_to_clump (char c); static bool read_line (COLUMN *p); static bool print_page (void); @@ -425,9 +424,10 @@ static bool skip_to_page (uintmax_t page); static void print_header (void); static void pad_across_to (int position); static void add_line_number (COLUMN *p); +static void getoptnum (const char *n_str, int min, int *num, + const char *errfmt); static void getoptarg (char *arg, char switch_char, char *character, - int *number); -void usage (int status); + int *number); static void print_files (int number_of_files, char **av); static void init_parameters (int number_of_files); static void init_header (char const *filename, int desc); @@ -437,7 +437,7 @@ static void init_store_cols (void); static void store_columns (void); static void balance (int total_stored); static void store_char (char c); -static void pad_down (int lines); +static void pad_down (unsigned int lines); static void read_rest_of_line (COLUMN *p); static void skip_read (COLUMN *p, int column_number); static void print_char (char c); @@ -445,9 +445,6 @@ static void cleanup (void); static void print_sep_string (void); static void separator_string (const char *optarg_S); -/* The name under which this program was invoked. */ -char *program_name; - /* All of the columns to print. */ static COLUMN *column_vector; @@ -459,7 +456,7 @@ static char *buff; /* Index of the position in buff where the next character will be stored. */ -static int buff_current; +static unsigned int buff_current; /* The number of characters in buff. Used for allocation of buff and to detect overflow of buff. */ @@ -471,7 +468,7 @@ static size_t buff_allocated; we do column balancing on the last page. */ static int *line_vector; -/* Array of horizonal positions. +/* Array of horizontal positions. For each line in line_vector, end_vector[line] is the horizontal position we are in after printing that line. We keep track of this so that we know how much we need to pad to prepare for the next @@ -536,9 +533,9 @@ static int lines_per_page = 66; /* Number of lines in the header and footer can be reset to 0 using the -t flag. */ -static int lines_per_header = 5; +enum { lines_per_header = 5 }; static int lines_per_body; -static int lines_per_footer = 5; +enum { lines_per_footer = 5 }; /* (-w|-W) Width in characters of the page. Does not include the width of the margin. */ @@ -635,10 +632,6 @@ static uintmax_t page_number; 2 moo 4 hoo 6 zoo */ static int line_number; -/* With line_number overflow, we use power_10 to cut off the higher-order - digits of the line_number */ -static int power_10; - /* (-n) True means lines should be preceded by numbers. */ static bool numbered_lines = false; @@ -693,11 +686,11 @@ static bool use_col_separator = false; /* String used to separate columns if the -S option has been specified. Default without -S but together with one of the column options - -a|COLUMN|-m is a `space' and with the -J option a `tab'. */ -static char *col_sep_string = ""; + -a|COLUMN|-m is a 'space' and with the -J option a 'tab'. */ +static char *col_sep_string = (char *) ""; static int col_sep_length = 0; -static char *column_separator = " "; -static char *line_separator = "\t"; +static char *column_separator = (char *) " "; +static char *line_separator = (char *) "\t"; /* Number of separator characters waiting to be printed as soon as we know that we have any input remaining to be printed. */ @@ -777,18 +770,18 @@ static struct option const long_options[] = /* Return the number of columns that have either an open file or stored lines. */ -static int +static unsigned int _GL_ATTRIBUTE_PURE cols_ready_to_print (void) { COLUMN *q; - int i; - int n; + unsigned int i; + unsigned int n; n = 0; for (q = column_vector, i = 0; i < columns; ++q, ++i) - if (q->status == OPEN || - q->status == FF_FOUND || /* With -b: To print a header only */ - (storing_columns && q->lines_stored > 0 && q->lines_to_print > 0)) + if (q->status == OPEN + || q->status == FF_FOUND /* With -b: To print a header only */ + || (storing_columns && q->lines_stored > 0 && q->lines_to_print > 0)) ++n; return n; } @@ -797,14 +790,14 @@ cols_ready_to_print (void) using option +FIRST_PAGE:LAST_PAGE */ static bool -first_last_page (char const *pages) +first_last_page (int oi, char c, char const *pages) { char *p; uintmax_t first; uintmax_t last = UINTMAX_MAX; strtol_error err = xstrtoumax (pages, &p, 10, &first, ""); if (err != LONGINT_OK && err != LONGINT_INVALID_SUFFIX_CHAR) - _STRTOL_ERROR (EXIT_FAILURE, pages, _("page range"), err); + xstrtol_fatal (err, oi, c, long_options, pages); if (p == pages || !first) return false; @@ -814,9 +807,9 @@ first_last_page (char const *pages) char const *p1 = p + 1; err = xstrtoumax (p1, &p, 10, &last, ""); if (err != LONGINT_OK) - _STRTOL_ERROR (EXIT_FAILURE, pages, _("page range"), err); + xstrtol_fatal (err, oi, c, long_options, pages); if (p1 == p || last < first) - return false; + return false; } if (*p) @@ -828,19 +821,13 @@ first_last_page (char const *pages) } /* Parse column count string S, and if it's valid (1 or larger and - within range of the type of `columns') set the global variables - columns and explicit_columns and return true. - Otherwise, exit with a diagnostic. */ + within range of the type of 'columns') set the global variables + columns and explicit_columns. Otherwise, exit with a diagnostic. */ + static void parse_column_count (char const *s) { - long int tmp_long; - if (xstrtol (s, NULL, 10, &tmp_long, "") != LONGINT_OK - || !(1 <= tmp_long && tmp_long <= INT_MAX)) - error (EXIT_FAILURE, 0, - _("invalid number of columns: %s"), quote (s)); - - columns = tmp_long; + getoptnum (s, 1, &columns, _("invalid number of columns")); explicit_columns = true; } @@ -857,7 +844,6 @@ separator_string (const char *optarg_S) int main (int argc, char **argv) { - int c; int n_files; bool old_options = false; bool old_w = false; @@ -870,7 +856,7 @@ main (int argc, char **argv) size_t n_alloc = 0; initialize_main (&argc, &argv); - program_name = argv[0]; + set_program_name (argv[0]); setlocale (LC_ALL, ""); bindtextdomain (PACKAGE, LOCALEDIR); textdomain (PACKAGE); @@ -879,207 +865,177 @@ main (int argc, char **argv) n_files = 0; file_names = (argc > 1 - ? xmalloc ((argc - 1) * sizeof (char *)) - : NULL); + ? xmalloc ((argc - 1) * sizeof (char *)) + : NULL); - while ((c = getopt_long (argc, argv, short_options, long_options, NULL)) - != -1) + while (true) { + int oi = -1; + int c = getopt_long (argc, argv, short_options, long_options, &oi); + if (c == -1) + break; + if (ISDIGIT (c)) - { - /* Accumulate column-count digits specified via old-style options. */ - if (n_digits + 1 >= n_alloc) - column_count_string - = X2REALLOC (column_count_string, &n_alloc); - column_count_string[n_digits++] = c; - column_count_string[n_digits] = '\0'; - continue; - } + { + /* Accumulate column-count digits specified via old-style options. */ + if (n_digits + 1 >= n_alloc) + column_count_string + = X2REALLOC (column_count_string, &n_alloc); + column_count_string[n_digits++] = c; + column_count_string[n_digits] = '\0'; + continue; + } n_digits = 0; switch (c) - { - case 1: /* Non-option argument. */ - /* long option --page dominates old `+FIRST_PAGE ...'. */ - if (! (first_page_number == 0 - && *optarg == '+' && first_last_page (optarg + 1))) - file_names[n_files++] = optarg; - break; - - case PAGES_OPTION: /* --pages=FIRST_PAGE[:LAST_PAGE] */ - { /* dominates old opt +... */ - if (! optarg) - error (EXIT_FAILURE, 0, - _("`--pages=FIRST_PAGE[:LAST_PAGE]' missing argument")); - else if (! first_last_page (optarg)) - error (EXIT_FAILURE, 0, _("Invalid page range %s"), - quote (optarg)); - break; - } - - case COLUMNS_OPTION: /* --columns=COLUMN */ - { - parse_column_count (optarg); - - /* If there was a prior column count specified via the - short-named option syntax, e.g., -9, ensure that this - long-name-specified value overrides it. */ - free (column_count_string); - column_count_string = NULL; - n_alloc = 0; - break; - } - - case 'a': - print_across_flag = true; - storing_columns = false; - break; - case 'b': - balance_columns = true; - break; - case 'c': - use_cntrl_prefix = true; - break; - case 'd': - double_space = true; - break; - case 'D': - date_format = optarg; - break; - case 'e': - if (optarg) - getoptarg (optarg, 'e', &input_tab_char, - &chars_per_input_tab); - /* Could check tab width > 0. */ - untabify_input = true; - break; - case 'f': - case 'F': - use_form_feed = true; - break; - case 'h': - custom_header = optarg; - break; - case 'i': - if (optarg) - getoptarg (optarg, 'i', &output_tab_char, - &chars_per_output_tab); - /* Could check tab width > 0. */ - tabify_output = true; - break; - case 'J': - join_lines = true; - break; - case 'l': - { - long int tmp_long; - if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK - || tmp_long <= 0 || tmp_long > INT_MAX) - { - error (EXIT_FAILURE, 0, - _("`-l PAGE_LENGTH' invalid number of lines: %s"), - quote (optarg)); - } - lines_per_page = tmp_long; - break; - } - case 'm': - parallel_files = true; - storing_columns = false; - break; - case 'n': - numbered_lines = true; - if (optarg) - getoptarg (optarg, 'n', &number_separator, - &chars_per_number); - break; - case 'N': - skip_count = false; - { - long int tmp_long; - if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK - || tmp_long > INT_MAX) - { - error (EXIT_FAILURE, 0, - _("`-N NUMBER' invalid starting line number: %s"), - quote (optarg)); - } - start_line_num = tmp_long; - break; - } - case 'o': - { - long int tmp_long; - if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK - || tmp_long < 0 || tmp_long > INT_MAX) - error (EXIT_FAILURE, 0, - _("`-o MARGIN' invalid line offset: %s"), quote (optarg)); - chars_per_margin = tmp_long; - break; - } - case 'r': - ignore_failed_opens = true; - break; - case 's': - old_options = true; - old_s = true; - if (!use_col_separator && optarg) - separator_string (optarg); - break; - case 'S': - old_s = false; - /* Reset an additional input of -s, -S dominates -s */ - col_sep_string = ""; - col_sep_length = 0; - use_col_separator = true; - if (optarg) - separator_string (optarg); - break; - case 't': - extremities = false; - keep_FF = true; - break; - case 'T': - extremities = false; - keep_FF = false; - break; - case 'v': - use_esc_sequence = true; - break; - case 'w': - old_options = true; - old_w = true; - { - long int tmp_long; - if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK - || tmp_long <= 0 || tmp_long > INT_MAX) - error (EXIT_FAILURE, 0, - _("`-w PAGE_WIDTH' invalid number of characters: %s"), - quote (optarg)); - if (!truncate_lines) - chars_per_line = tmp_long; - break; - } - case 'W': - old_w = false; /* dominates -w */ - truncate_lines = true; - { - long int tmp_long; - if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK - || tmp_long <= 0 || tmp_long > INT_MAX) - error (EXIT_FAILURE, 0, - _("`-W PAGE_WIDTH' invalid number of characters: %s"), - quote (optarg)); - chars_per_line = tmp_long; - break; - } - case_GETOPT_HELP_CHAR; - case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); - default: - usage (EXIT_FAILURE); - break; - } + { + case 1: /* Non-option argument. */ + /* long option --page dominates old '+FIRST_PAGE ...'. */ + if (! (first_page_number == 0 + && *optarg == '+' && first_last_page (-2, '+', optarg + 1))) + file_names[n_files++] = optarg; + break; + + case PAGES_OPTION: /* --pages=FIRST_PAGE[:LAST_PAGE] */ + { /* dominates old opt +... */ + if (! optarg) + error (EXIT_FAILURE, 0, + _("'--pages=FIRST_PAGE[:LAST_PAGE]' missing argument")); + else if (! first_last_page (oi, 0, optarg)) + error (EXIT_FAILURE, 0, _("invalid page range %s"), + quote (optarg)); + break; + } + + case COLUMNS_OPTION: /* --columns=COLUMN */ + { + parse_column_count (optarg); + + /* If there was a prior column count specified via the + short-named option syntax, e.g., -9, ensure that this + long-name-specified value overrides it. */ + free (column_count_string); + column_count_string = NULL; + n_alloc = 0; + break; + } + + case 'a': + print_across_flag = true; + storing_columns = false; + break; + case 'b': + balance_columns = true; + break; + case 'c': + use_cntrl_prefix = true; + break; + case 'd': + double_space = true; + break; + case 'D': + date_format = optarg; + break; + case 'e': + if (optarg) + getoptarg (optarg, 'e', &input_tab_char, + &chars_per_input_tab); + /* Could check tab width > 0. */ + untabify_input = true; + break; + case 'f': + case 'F': + use_form_feed = true; + break; + case 'h': + custom_header = optarg; + break; + case 'i': + if (optarg) + getoptarg (optarg, 'i', &output_tab_char, + &chars_per_output_tab); + /* Could check tab width > 0. */ + tabify_output = true; + break; + case 'J': + join_lines = true; + break; + case 'l': + getoptnum (optarg, 1, &lines_per_page, + _("'-l PAGE_LENGTH' invalid number of lines")); + break; + case 'm': + parallel_files = true; + storing_columns = false; + break; + case 'n': + numbered_lines = true; + if (optarg) + getoptarg (optarg, 'n', &number_separator, + &chars_per_number); + break; + case 'N': + skip_count = false; + getoptnum (optarg, INT_MIN, &start_line_num, + _("'-N NUMBER' invalid starting line number")); + break; + case 'o': + getoptnum (optarg, 0, &chars_per_margin, + _("'-o MARGIN' invalid line offset")); + break; + case 'r': + ignore_failed_opens = true; + break; + case 's': + old_options = true; + old_s = true; + if (!use_col_separator && optarg) + separator_string (optarg); + break; + case 'S': + old_s = false; + /* Reset an additional input of -s, -S dominates -s */ + col_sep_string = bad_cast (""); + col_sep_length = 0; + use_col_separator = true; + if (optarg) + separator_string (optarg); + break; + case 't': + extremities = false; + keep_FF = true; + break; + case 'T': + extremities = false; + keep_FF = false; + break; + case 'v': + use_esc_sequence = true; + break; + case 'w': + old_options = true; + old_w = true; + { + int tmp_cpl; + getoptnum (optarg, 1, &tmp_cpl, + _("'-w PAGE_WIDTH' invalid number of characters")); + if (! truncate_lines) + chars_per_line = tmp_cpl; + } + break; + case 'W': + old_w = false; /* dominates -w */ + truncate_lines = true; + getoptnum (optarg, 1, &chars_per_line, + _("'-W PAGE_WIDTH' invalid number of characters")); + break; + case_GETOPT_HELP_CHAR; + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + default: + usage (EXIT_FAILURE); + break; + } } if (column_count_string) @@ -1090,20 +1046,20 @@ main (int argc, char **argv) if (! date_format) date_format = (getenv ("POSIXLY_CORRECT") && !hard_locale (LC_TIME) - ? "%b %e %H:%M %Y" - : "%Y-%m-%d %H:%M"); + ? "%b %e %H:%M %Y" + : "%Y-%m-%d %H:%M"); /* Now we can set a reasonable initial value: */ if (first_page_number == 0) first_page_number = 1; - if (parallel_files & explicit_columns) + if (parallel_files && explicit_columns) error (EXIT_FAILURE, 0, - _("Cannot specify number of columns when printing in parallel.")); + _("cannot specify number of columns when printing in parallel")); - if (parallel_files & print_across_flag) + if (parallel_files && print_across_flag) error (EXIT_FAILURE, 0, - _("Cannot specify both printing across and printing in parallel.")); + _("cannot specify both printing across and printing in parallel")); /* Translate some old short options to new/long options. To meet downward compatibility with other UNIX pr utilities @@ -1113,41 +1069,41 @@ main (int argc, char **argv) { if (old_w) { - if (parallel_files | explicit_columns) - { - /* activate -W */ - truncate_lines = true; - if (old_s) - /* adapt HP-UX and SunOS: -s = no separator; - activate -S */ - use_col_separator = true; - } - else - /* old -w sets width with columns only - activate -J */ - join_lines = true; - } + if (parallel_files || explicit_columns) + { + /* activate -W */ + truncate_lines = true; + if (old_s) + /* adapt HP-UX and SunOS: -s = no separator; + activate -S */ + use_col_separator = true; + } + else + /* old -w sets width with columns only + activate -J */ + join_lines = true; + } else if (!use_col_separator) { - /* No -S option read */ - if (old_s & (parallel_files | explicit_columns)) - { - if (!truncate_lines) - { - /* old -s (without -w and -W) annuls column alignment, - uses fields, activate -J */ - join_lines = true; - if (col_sep_length > 0) - /* activate -S */ - use_col_separator = true; - } - else - /* with -W */ - /* adapt HP-UX and SunOS: -s = no separator; - activate -S */ - use_col_separator = true; - } - } + /* No -S option read */ + if (old_s && (parallel_files || explicit_columns)) + { + if (!truncate_lines) + { + /* old -s (without -w and -W) annuls column alignment, + uses fields, activate -J */ + join_lines = true; + if (col_sep_length > 0) + /* activate -S */ + use_col_separator = true; + } + else + /* with -W */ + /* adapt HP-UX and SunOS: -s = no separator; + activate -S */ + use_col_separator = true; + } + } } for (; optind < argc; optind++) @@ -1163,22 +1119,30 @@ main (int argc, char **argv) else { if (parallel_files) - print_files (n_files, file_names); + print_files (n_files, file_names); else - { - int i; - for (i = 0; i < n_files; i++) - print_files (1, &file_names[i]); - } + { + unsigned int i; + for (i = 0; i < n_files; i++) + print_files (1, &file_names[i]); + } } cleanup (); + IF_LINT (free (file_names)); if (have_read_stdin && fclose (stdin) == EOF) error (EXIT_FAILURE, errno, _("standard input")); - if (failed_opens) - exit (EXIT_FAILURE); - exit (EXIT_SUCCESS); + return failed_opens ? EXIT_FAILURE : EXIT_SUCCESS; +} + +/* Parse numeric arguments, ensuring MIN <= number <= INT_MAX. */ + +static void +getoptnum (const char *n_str, int min, int *num, const char *err) +{ + intmax_t tnum = xdectoimax (n_str, min, INT_MAX, "", err, 0); + *num = tnum; } /* Parse options of the form -scNNN. @@ -1196,17 +1160,17 @@ getoptarg (char *arg, char switch_char, char *character, int *number) { long int tmp_long; if (xstrtol (arg, NULL, 10, &tmp_long, "") != LONGINT_OK - || tmp_long <= 0 || tmp_long > INT_MAX) - { - error (0, 0, - _("`-%c' extra characters or invalid number in the argument: %s"), - switch_char, quote (arg)); - usage (EXIT_FAILURE); - } + || tmp_long <= 0 || INT_MAX < tmp_long) + { + error (0, INT_MAX < tmp_long ? EOVERFLOW : errno, + _("'-%c' extra characters or invalid number in the argument: %s"), + switch_char, quote (arg)); + usage (EXIT_FAILURE); + } *number = tmp_long; } } - + /* Set parameters related to formatting. */ static void @@ -1214,12 +1178,6 @@ init_parameters (int number_of_files) { int chars_used_by_number = 0; - if (use_form_feed) - { - lines_per_header = 3; - lines_per_footer = 0; - } - lines_per_body = lines_per_page - lines_per_header - lines_per_footer; if (lines_per_body <= 0) { @@ -1249,16 +1207,16 @@ init_parameters (int number_of_files) if (columns > 1) { if (!use_col_separator) - { - /* Use default separator */ - if (join_lines) - col_sep_string = line_separator; - else - col_sep_string = column_separator; - - col_sep_length = 1; - use_col_separator = true; - } + { + /* Use default separator */ + if (join_lines) + col_sep_string = line_separator; + else + col_sep_string = column_separator; + + col_sep_length = 1; + use_col_separator = true; + } /* It's rather pointless to define a TAB separator with column alignment */ else if (!join_lines && *col_sep_string == '\t') @@ -1276,37 +1234,30 @@ init_parameters (int number_of_files) if (numbered_lines) { - int tmp_i; int chars_per_default_tab = 8; line_count = start_line_num; /* To allow input tab-expansion (-e sensitive) use: - if (number_separator == input_tab_char) - number_width = chars_per_number + - TAB_WIDTH (chars_per_input_tab, chars_per_number); */ + if (number_separator == input_tab_char) + number_width = chars_per_number + + TAB_WIDTH (chars_per_input_tab, chars_per_number); */ /* Estimate chars_per_text without any margin and keep it constant. */ if (number_separator == '\t') - number_width = chars_per_number + - TAB_WIDTH (chars_per_default_tab, chars_per_number); + number_width = (chars_per_number + + TAB_WIDTH (chars_per_default_tab, chars_per_number)); else - number_width = chars_per_number + 1; + number_width = chars_per_number + 1; /* The number is part of the column width unless we are - printing files in parallel. */ + printing files in parallel. */ if (parallel_files) - chars_used_by_number = number_width; - - /* We use power_10 to cut off the higher-order digits of the - line_number in function add_line_number */ - tmp_i = chars_per_number; - for (power_10 = 1; tmp_i > 0; --tmp_i) - power_10 = 10 * power_10; + chars_used_by_number = number_width; } - chars_per_column = (chars_per_line - chars_used_by_number - - (columns - 1) * col_sep_length) / columns; + chars_per_column = (chars_per_line - chars_used_by_number + - (columns - 1) * col_sep_length) / columns; if (chars_per_column < 1) error (EXIT_FAILURE, 0, _("page width too narrow")); @@ -1314,7 +1265,8 @@ init_parameters (int number_of_files) if (numbered_lines) { free (number_buff); - number_buff = xmalloc (2 * chars_per_number); + number_buff = xmalloc (MAX (chars_per_number, + INT_STRLEN_BOUND (line_number)) + 1); } /* Pick the maximum between the tab width and the width of an @@ -1325,7 +1277,7 @@ init_parameters (int number_of_files) free (clump_buff); clump_buff = xmalloc (MAX (8, chars_per_input_tab)); } - + /* Open the necessary files, maintaining a COLUMN structure for each column. @@ -1354,54 +1306,54 @@ init_fps (int number_of_files, char **av) { files_left = number_of_files; for (p = column_vector; files_left--; ++p, ++av) - { - if (! open_file (*av, p)) - { - --p; - --columns; - } - } + { + if (! open_file (*av, p)) + { + --p; + --columns; + } + } if (columns == 0) - return false; + return false; init_header ("", -1); } else { p = column_vector; if (number_of_files > 0) - { - if (! open_file (*av, p)) - return false; - init_header (*av, fileno (p->fp)); - p->lines_stored = 0; - } + { + if (! open_file (*av, p)) + return false; + init_header (*av, fileno (p->fp)); + p->lines_stored = 0; + } else - { - p->name = _("standard input"); - p->fp = stdin; - have_read_stdin = true; - p->status = OPEN; - p->full_page_printed = false; - ++total_files; - init_header ("", -1); - p->lines_stored = 0; - } + { + p->name = _("standard input"); + p->fp = stdin; + have_read_stdin = true; + p->status = OPEN; + p->full_page_printed = false; + ++total_files; + init_header ("", -1); + p->lines_stored = 0; + } firstname = p->name; firstfp = p->fp; for (i = columns - 1, ++p; i; --i, ++p) - { - p->name = firstname; - p->fp = firstfp; - p->status = OPEN; - p->full_page_printed = false; - p->lines_stored = 0; - } + { + p->name = firstname; + p->fp = firstfp; + p->status = OPEN; + p->full_page_printed = false; + p->lines_stored = 0; + } } files_ready_to_read = total_files; return true; } - + /* Determine print_func and char_func, the functions used by each column for printing and/or storing. @@ -1421,12 +1373,12 @@ init_funcs (void) else { /* When numbering lines of parallel files, we enlarge the - first column to accomodate the number. Looks better than + first column to accommodate the number. Looks better than the Sys V approach. */ - if (parallel_files & numbered_lines) - h_next = h + chars_per_column + number_width; + if (parallel_files && numbered_lines) + h_next = h + chars_per_column + number_width; else - h_next = h + chars_per_column; + h_next = h + chars_per_column; } /* Enlarge p->start_position of first column to use the same form of @@ -1438,16 +1390,16 @@ init_funcs (void) for (p = column_vector, i = 1; i < columns; ++p, ++i) { if (storing_columns) /* One file, multi columns down. */ - { - p->char_func = store_char; - p->print_func = print_stored; - } + { + p->char_func = store_char; + p->print_func = print_stored; + } else - /* One file, multi columns across; or parallel files. */ - { - p->char_func = print_char; - p->print_func = read_line; - } + /* One file, multi columns across; or parallel files. */ + { + p->char_func = print_char; + p->print_func = read_line; + } /* Number only the first column when printing files in parallel. */ @@ -1459,22 +1411,22 @@ init_funcs (void) using a margin. */ if (!truncate_lines) - { - h = ANYWHERE; - h_next = ANYWHERE; - } + { + h = ANYWHERE; + h_next = ANYWHERE; + } else - { - h = h_next + col_sep_length; - h_next = h + chars_per_column; - } + { + h = h_next + col_sep_length; + h_next = h + chars_per_column; + } } /* The rightmost column. Doesn't need to be stored unless we intend to balance columns on the last page. */ - if (storing_columns & balance_columns) + if (storing_columns && balance_columns) { p->char_func = store_char; p->print_func = print_stored; @@ -1488,7 +1440,7 @@ init_funcs (void) p->numbered = numbered_lines && (!parallel_files || i == 1); p->start_position = h; } - + /* Open a file. Return true if successful. With each file p, p->full_page_printed is initialized, @@ -1512,9 +1464,10 @@ open_file (char *name, COLUMN *p) { failed_opens = true; if (!ignore_failed_opens) - error (0, errno, "%s", name); + error (0, errno, "%s", quotef (name)); return false; } + fadvise (p->fp, FADVISE_SEQUENTIAL); p->status = OPEN; p->full_page_printed = false; ++total_files; @@ -1535,20 +1488,20 @@ close_file (COLUMN *p) if (p->status == CLOSED) return; if (ferror (p->fp)) - error (EXIT_FAILURE, errno, "%s", p->name); + error (EXIT_FAILURE, errno, "%s", quotef (p->name)); if (fileno (p->fp) != STDIN_FILENO && fclose (p->fp) != 0) - error (EXIT_FAILURE, errno, "%s", p->name); + error (EXIT_FAILURE, errno, "%s", quotef (p->name)); if (!parallel_files) { for (q = column_vector, i = columns; i; ++q, --i) - { - q->status = CLOSED; - if (q->lines_stored == 0) - { - q->lines_to_print = 0; - } - } + { + q->status = CLOSED; + if (q->lines_stored == 0) + { + q->lines_to_print = 0; + } + } } else { @@ -1574,10 +1527,10 @@ hold_file (COLUMN *p) if (!parallel_files) for (q = column_vector, i = columns; i; ++q, --i) { - if (storing_columns) - q->status = FF_FOUND; - else - q->status = ON_HOLD; + if (storing_columns) + q->status = FF_FOUND; + else + q->status = ON_HOLD; } else p->status = ON_HOLD; @@ -1598,8 +1551,8 @@ reset_status (void) for (p = column_vector; i; --i, ++p) if (p->status == ON_HOLD) { - p->status = OPEN; - files_ready_to_read++; + p->status = OPEN; + files_ready_to_read++; } if (storing_columns) @@ -1611,7 +1564,7 @@ reset_status (void) files_ready_to_read = 1; } } - + /* Print a single file, or multiple files in parallel. Set up the list of columns, opening the necessary files. @@ -1633,9 +1586,9 @@ print_files (int number_of_files, char **av) if (first_page_number > 1) { if (!skip_to_page (first_page_number)) - return; + return; else - page_number = first_page_number; + page_number = first_page_number; } else page_number = 1; @@ -1646,7 +1599,7 @@ print_files (int number_of_files, char **av) while (print_page ()) ; } - + /* Initialize header information. If DESC is non-negative, it is a file descriptor open to FILENAME for reading. */ @@ -1669,7 +1622,7 @@ init_header (char const *filename, int desc) { static struct timespec timespec; if (! timespec.tv_sec) - gettime (×pec); + gettime (×pec); t = timespec; } @@ -1678,7 +1631,7 @@ init_header (char const *filename, int desc) if (tm == NULL) { buf = xmalloc (INT_BUFSIZE_BOUND (long int) - + MAX (10, INT_BUFSIZE_BOUND (int))); + + MAX (10, INT_BUFSIZE_BOUND (int))); sprintf (buf, "%ld.%09d", (long int) t.tv_sec, ns); } else @@ -1692,10 +1645,10 @@ init_header (char const *filename, int desc) date_text = buf; file_text = custom_header ? custom_header : desc < 0 ? "" : filename; header_width_available = (chars_per_line - - mbswidth (date_text, 0) - - mbswidth (file_text, 0)); + - mbswidth (date_text, 0) + - mbswidth (file_text, 0)); } - + /* Set things up for printing a page Scan through the columns ... @@ -1716,35 +1669,35 @@ init_page (void) { store_columns (); for (j = columns - 1, p = column_vector; j; --j, ++p) - { - p->lines_to_print = p->lines_stored; - } + { + p->lines_to_print = p->lines_stored; + } /* Last column. */ if (balance_columns) - { - p->lines_to_print = p->lines_stored; - } + { + p->lines_to_print = p->lines_stored; + } /* Since we're not balancing columns, we don't need to store the rightmost column. Read it straight from the file. */ else - { - if (p->status == OPEN) - { - p->lines_to_print = lines_per_body; - } - else - p->lines_to_print = 0; - } + { + if (p->status == OPEN) + { + p->lines_to_print = lines_per_body; + } + else + p->lines_to_print = 0; + } } else for (j = columns, p = column_vector; j; --j, ++p) if (p->status == OPEN) - { - p->lines_to_print = lines_per_body; - } + { + p->lines_to_print = lines_per_body; + } else - p->lines_to_print = 0; + p->lines_to_print = 0; } /* Align empty columns and print separators. @@ -1821,86 +1774,86 @@ print_page (void) empty_line = true; for (j = 1, p = column_vector; j <= columns; ++j, ++p) - { - input_position = 0; - if (p->lines_to_print > 0 || p->status == FF_FOUND) - { - FF_only = false; - padding_not_printed = p->start_position; - if (!(p->print_func) (p)) - read_rest_of_line (p); - pv |= pad_vertically; - - --p->lines_to_print; - if (p->lines_to_print <= 0) - { - if (cols_ready_to_print () <= 0) - break; - } - - /* File p changed its status to ON_HOLD or CLOSED */ - if (parallel_files && p->status != OPEN) - { - if (empty_line) - align_empty_cols = true; - else if (p->status == CLOSED || - (p->status == ON_HOLD && FF_only)) - align_column (p); - } - } - else if (parallel_files) - { - /* File status ON_HOLD or CLOSED */ - if (empty_line) - align_empty_cols = true; - else - align_column (p); - } - - /* We need it also with an empty column */ - if (use_col_separator) - ++separators_not_printed; - } + { + input_position = 0; + if (p->lines_to_print > 0 || p->status == FF_FOUND) + { + FF_only = false; + padding_not_printed = p->start_position; + if (!(p->print_func) (p)) + read_rest_of_line (p); + pv |= pad_vertically; + + --p->lines_to_print; + if (p->lines_to_print <= 0) + { + if (cols_ready_to_print () == 0) + break; + } + + /* File p changed its status to ON_HOLD or CLOSED */ + if (parallel_files && p->status != OPEN) + { + if (empty_line) + align_empty_cols = true; + else if (p->status == CLOSED + || (p->status == ON_HOLD && FF_only)) + align_column (p); + } + } + else if (parallel_files) + { + /* File status ON_HOLD or CLOSED */ + if (empty_line) + align_empty_cols = true; + else + align_column (p); + } + + /* We need it also with an empty column */ + if (use_col_separator) + ++separators_not_printed; + } if (pad_vertically) - { - putchar ('\n'); - --lines_left_on_page; - } - - if (cols_ready_to_print () <= 0 && !extremities) - break; - - if (double_space & pv) - { - putchar ('\n'); - --lines_left_on_page; - } + { + putchar ('\n'); + --lines_left_on_page; + } + + if (cols_ready_to_print () == 0 && !extremities) + break; + + if (double_space && pv) + { + putchar ('\n'); + --lines_left_on_page; + } } if (lines_left_on_page == 0) for (j = 1, p = column_vector; j <= columns; ++j, ++p) if (p->status == OPEN) - p->full_page_printed = true; + p->full_page_printed = true; pad_vertically = pv; - if (pad_vertically & extremities) + if (pad_vertically && extremities) pad_down (lines_left_on_page + lines_per_footer); - else if (keep_FF & print_a_FF) + else if (keep_FF && print_a_FF) { putchar ('\f'); print_a_FF = false; } - if (last_page_number < page_number) + if (last_page_number < ++page_number) return false; /* Stop printing with LAST_PAGE */ reset_status (); /* Change ON_HOLD to OPEN. */ return true; /* More pages to go. */ } - + /* Allocate space for storing columns. This is necessary when printing multiple columns from a single file. @@ -1923,15 +1876,15 @@ init_store_cols (void) free (line_vector); /* FIXME: here's where it was allocated. */ - line_vector = xmalloc ((total_lines + 1) * sizeof (int *)); + line_vector = xmalloc ((total_lines + 1) * sizeof *line_vector); free (end_vector); - end_vector = xmalloc (total_lines * sizeof (int *)); + end_vector = xmalloc (total_lines * sizeof *end_vector); free (buff); buff_allocated = (use_col_separator - ? 2 * chars_if_truncate - : chars_if_truncate); /* Tune this. */ + ? 2 * chars_if_truncate + : chars_if_truncate); /* Tune this. */ buff = xmalloc (buff_allocated); } @@ -1951,8 +1904,8 @@ static void store_columns (void) { int i, j; - int line = 0; - int buff_start; + unsigned int line = 0; + unsigned int buff_start; int last_col; /* The rightmost column which will be saved in buff */ COLUMN *p; @@ -1973,22 +1926,22 @@ store_columns (void) p->current_line = line; for (j = lines_per_body; j && files_ready_to_read; --j) - if (p->status == OPEN) /* Redundant. Clean up. */ - { - input_position = 0; - - if (!read_line (p)) - read_rest_of_line (p); - - if (p->status == OPEN - || buff_start != buff_current) - { - ++p->lines_stored; - line_vector[line] = buff_start; - end_vector[line++] = input_position; - buff_start = buff_current; - } - } + if (p->status == OPEN) /* Redundant. Clean up. */ + { + input_position = 0; + + if (!read_line (p)) + read_rest_of_line (p); + + if (p->status == OPEN + || buff_start != buff_current) + { + ++p->lines_stored; + line_vector[line] = buff_start; + end_vector[line++] = input_position; + buff_start = buff_current; + } + } } /* Keep track of the location of the last char in buff. */ @@ -2009,7 +1962,7 @@ balance (int total_stored) { lines = total_stored / columns; if (i <= total_stored % columns) - ++lines; + ++lines; p->lines_stored = lines; p->current_line = first_line; @@ -2036,32 +1989,26 @@ add_line_number (COLUMN *p) { int i; char *s; - int left_cut; + int num_width; /* Cutting off the higher-order digits is more informative than - lower-order cut off*/ - if (line_number < power_10) - sprintf (number_buff, "%*d", chars_per_number, line_number); - else - { - left_cut = line_number % power_10; - sprintf (number_buff, "%0*d", chars_per_number, left_cut); - } + lower-order cut off. */ + num_width = sprintf (number_buff, "%*d", chars_per_number, line_number); line_number++; - s = number_buff; + s = number_buff + (num_width - chars_per_number); for (i = chars_per_number; i > 0; i--) (p->char_func) (*s++); if (columns > 1) { /* Tabification is assumed for multiple columns, also for n-separators, - but `default n-separator = TAB' hasn't been given priority over - equal column_width also specified by POSIX. */ + but 'default n-separator = TAB' hasn't been given priority over + equal column_width also specified by POSIX. */ if (number_separator == '\t') { i = number_width - chars_per_number; while (i-- > 0) - (p->char_func) (' '); + (p->char_func) (' '); } else (p->char_func) (number_separator); @@ -2074,13 +2021,13 @@ add_line_number (COLUMN *p) (p->char_func) (number_separator); if (number_separator == '\t') output_position = POS_AFTER_TAB (chars_per_output_tab, - output_position); + output_position); } - if (truncate_lines & !parallel_files) + if (truncate_lines && !parallel_files) input_position += number_width; } - + /* Print (or store) padding until the current horizontal position is position. */ @@ -2094,7 +2041,7 @@ pad_across_to (int position) else { while (++h <= position) - putchar (' '); + putchar (' '); output_position = position; } } @@ -2105,9 +2052,9 @@ pad_across_to (int position) Otherwise, use newlines. */ static void -pad_down (int lines) +pad_down (unsigned int lines) { - int i; + unsigned int i; if (use_form_feed) putchar ('\f'); @@ -2131,19 +2078,19 @@ read_rest_of_line (COLUMN *p) while ((c = getc (f)) != '\n') { if (c == '\f') - { - if ((c = getc (f)) != '\n') - ungetc (c, f); - if (keep_FF) - print_a_FF = true; - hold_file (p); - break; - } + { + if ((c = getc (f)) != '\n') + ungetc (c, f); + if (keep_FF) + print_a_FF = true; + hold_file (p); + break; + } else if (c == EOF) - { - close_file (p); - break; - } + { + close_file (p); + break; + } } } @@ -2187,28 +2134,28 @@ skip_read (COLUMN *p, int column_number) while (c != '\n') { if (c == '\f') - { - /* No FF-coincidence possible, - no catching up of a FF-coincidence with next page */ - if (last_line) - { - if (!parallel_files) - for (q = column_vector, i = columns; i; ++q, --i) - q->full_page_printed = false; - else - p->full_page_printed = false; - } - - if ((c = getc (f)) != '\n') - ungetc (c, f); - hold_file (p); - break; - } + { + /* No FF-coincidence possible, + no catching up of a FF-coincidence with next page */ + if (last_line) + { + if (!parallel_files) + for (q = column_vector, i = columns; i; ++q, --i) + q->full_page_printed = false; + else + p->full_page_printed = false; + } + + if ((c = getc (f)) != '\n') + ungetc (c, f); + hold_file (p); + break; + } else if (c == EOF) - { - close_file (p); - break; - } + { + close_file (p); + break; + } c = getc (f); } @@ -2216,7 +2163,7 @@ skip_read (COLUMN *p, int column_number) if ((!parallel_files || column_number == 1) && !single_ff) ++line_count; } - + /* If we're tabifying output, When print_char encounters white space it keeps track @@ -2231,7 +2178,7 @@ print_white_space (void) int goal = h_old + spaces_not_printed; while (goal - h_old > 1 - && (h_new = POS_AFTER_TAB (chars_per_output_tab, h_old)) <= goal) + && (h_new = POS_AFTER_TAB (chars_per_output_tab, h_old)) <= goal) { putchar (output_tab_char); h_old = h_new; @@ -2260,35 +2207,35 @@ print_sep_string (void) { /* We'll be starting a line with chars_per_margin, anything else? */ if (spaces_not_printed > 0) - print_white_space (); + print_white_space (); } else { for (; separators_not_printed > 0; --separators_not_printed) - { - while (l-- > 0) - { - /* 3 types of sep_strings: spaces only, spaces and chars, - chars only */ - if (*s == ' ') - { - /* We're tabifying output; consecutive spaces in - sep_string may have to be converted to tabs */ - s++; - ++spaces_not_printed; - } - else - { - if (spaces_not_printed > 0) - print_white_space (); - putchar (*s++); - ++output_position; - } - } + { + while (l-- > 0) + { + /* 3 types of sep_strings: spaces only, spaces and chars, + chars only */ + if (*s == ' ') + { + /* We're tabifying output; consecutive spaces in + sep_string may have to be converted to tabs */ + s++; + ++spaces_not_printed; + } + else + { + if (spaces_not_printed > 0) + print_white_space (); + putchar (*s++); + ++output_position; + } + } /* sep_string ends with some spaces */ - if (spaces_not_printed > 0) - print_white_space (); - } + if (spaces_not_printed > 0) + print_white_space (); + } } } @@ -2317,21 +2264,21 @@ print_char (char c) if (tabify_output) { if (c == ' ') - { - ++spaces_not_printed; - return; - } + { + ++spaces_not_printed; + return; + } else if (spaces_not_printed > 0) - print_white_space (); + print_white_space (); /* Nonprintables are assumed to have width 0, except '\b'. */ if (! isprint (to_uchar (c))) - { - if (c == '\b') - --output_position; - } + { + if (c == '\b') + --output_position; + } else - ++output_position; + ++output_position; } putchar (c); } @@ -2350,34 +2297,34 @@ skip_to_page (uintmax_t page) for (n = 1; n < page; ++n) { for (i = 1; i < lines_per_body; ++i) - { - for (j = 1, p = column_vector; j <= columns; ++j, ++p) - if (p->status == OPEN) - skip_read (p, j); - } + { + for (j = 1, p = column_vector; j <= columns; ++j, ++p) + if (p->status == OPEN) + skip_read (p, j); + } last_line = true; for (j = 1, p = column_vector; j <= columns; ++j, ++p) - if (p->status == OPEN) - skip_read (p, j); + if (p->status == OPEN) + skip_read (p, j); if (storing_columns) /* change FF_FOUND to ON_HOLD */ - for (j = 1, p = column_vector; j <= columns; ++j, ++p) - if (p->status != CLOSED) - p->status = ON_HOLD; + for (j = 1, p = column_vector; j <= columns; ++j, ++p) + if (p->status != CLOSED) + p->status = ON_HOLD; reset_status (); last_line = false; if (files_ready_to_read < 1) { - /* It's very helpful, normally the total number of pages is - not known in advance. */ - error (0, 0, - _("starting page number %"PRIuMAX - " exceeds page count %"PRIuMAX), - page, n); + /* It's very helpful, normally the total number of pages is + not known in advance. */ + error (0, 0, + _("starting page number %"PRIuMAX + " exceeds page count %"PRIuMAX), + page, n); break; - } + } } return files_ready_to_read > 0; } @@ -2395,27 +2342,26 @@ print_header (void) int lhs_spaces; int rhs_spaces; - if (!use_form_feed) - printf ("\n\n"); - output_position = 0; pad_across_to (chars_per_margin); print_white_space (); if (page_number == 0) - error (EXIT_FAILURE, 0, _("Page number overflow")); + error (EXIT_FAILURE, 0, _("page number overflow")); /* The translator must ensure that formatting the translation of "Page %"PRIuMAX does not generate more than (sizeof page_text - 1) bytes. */ - sprintf (page_text, _("Page %"PRIuMAX), page_number++); + sprintf (page_text, _("Page %"PRIuMAX), page_number); available_width = header_width_available - mbswidth (page_text, 0); available_width = MAX (0, available_width); lhs_spaces = available_width >> 1; rhs_spaces = available_width - lhs_spaces; - printf ("%s%*s%s%*s%s\n\n\n", - date_text, lhs_spaces, " ", file_text, rhs_spaces, " ", page_text); + printf ("\n\n%*s%s%*s%s%*s%s\n\n\n", + chars_per_margin, "", + date_text, lhs_spaces, " ", + file_text, rhs_spaces, " ", page_text); print_a_header = false; output_position = 0; @@ -2446,7 +2392,7 @@ static bool read_line (COLUMN *p) { int c; - int chars IF_LINT (= 0); + int chars IF_LINT ( = 0); int last_input_position; int j, k; COLUMN *q; @@ -2465,15 +2411,15 @@ read_line (COLUMN *p) { case '\f': if ((c = getc (p->fp)) != '\n') - ungetc (c, p->fp); + ungetc (c, p->fp); FF_only = true; - if (print_a_header & !storing_columns) - { - pad_vertically = true; - print_header (); - } + if (print_a_header && !storing_columns) + { + pad_vertically = true; + print_header (); + } else if (keep_FF) - print_a_FF = true; + print_a_FF = true; hold_file (p); return true; case EOF: @@ -2495,35 +2441,35 @@ read_line (COLUMN *p) { pad_vertically = true; - if (print_a_header & !storing_columns) - print_header (); - - if (parallel_files & align_empty_cols) - { - /* We have to align empty columns at the beginning of a line. */ - k = separators_not_printed; - separators_not_printed = 0; - for (j = 1, q = column_vector; j <= k; ++j, ++q) - { - align_column (q); - separators_not_printed += 1; - } - padding_not_printed = p->start_position; - if (truncate_lines) - spaces_not_printed = chars_per_column; - else - spaces_not_printed = 0; - align_empty_cols = false; - } + if (print_a_header && !storing_columns) + print_header (); + + if (parallel_files && align_empty_cols) + { + /* We have to align empty columns at the beginning of a line. */ + k = separators_not_printed; + separators_not_printed = 0; + for (j = 1, q = column_vector; j <= k; ++j, ++q) + { + align_column (q); + separators_not_printed += 1; + } + padding_not_printed = p->start_position; + if (truncate_lines) + spaces_not_printed = chars_per_column; + else + spaces_not_printed = 0; + align_empty_cols = false; + } if (padding_not_printed - col_sep_length > 0) - { - pad_across_to (padding_not_printed - col_sep_length); - padding_not_printed = ANYWHERE; - } + { + pad_across_to (padding_not_printed - col_sep_length); + padding_not_printed = ANYWHERE; + } if (use_col_separator) - print_sep_string (); + print_sep_string (); } if (p->numbered) @@ -2535,33 +2481,33 @@ read_line (COLUMN *p) print_clump (p, chars, clump_buff); - for (;;) + while (true) { c = getc (p->fp); switch (c) - { - case '\n': - return true; - case '\f': - if ((c = getc (p->fp)) != '\n') - ungetc (c, p->fp); - if (keep_FF) - print_a_FF = true; - hold_file (p); - return true; - case EOF: - close_file (p); - return true; - } + { + case '\n': + return true; + case '\f': + if ((c = getc (p->fp)) != '\n') + ungetc (c, p->fp); + if (keep_FF) + print_a_FF = true; + hold_file (p); + return true; + case EOF: + close_file (p); + return true; + } last_input_position = input_position; chars = char_to_clump (c); if (truncate_lines && input_position > chars_per_column) - { - input_position = last_input_position; - return false; - } + { + input_position = last_input_position; + return false; + } print_clump (p, chars, clump_buff); } @@ -2610,13 +2556,13 @@ print_stored (COLUMN *p) if (p->status == FF_FOUND) { for (i = 1, q = column_vector; i <= columns; ++i, ++q) - q->status = ON_HOLD; + q->status = ON_HOLD; if (column_vector->lines_to_print <= 0) - { - if (!extremities) - pad_vertically = false; - return true; /* print a header only */ - } + { + if (!extremities) + pad_vertically = false; + return true; /* print a header only */ + } } if (padding_not_printed - col_sep_length > 0) @@ -2635,7 +2581,7 @@ print_stored (COLUMN *p) { output_position = p->start_position + end_vector[line]; if (p->start_position - col_sep_length == chars_per_margin) - output_position -= col_sep_length; + output_position -= col_sep_length; } return true; @@ -2672,60 +2618,60 @@ char_to_clump (char c) width = TAB_WIDTH (chars_per_c, input_position); if (untabify_input) - { - for (i = width; i; --i) - *s++ = ' '; - chars = width; - } + { + for (i = width; i; --i) + *s++ = ' '; + chars = width; + } else - { - *s = c; - chars = 1; - } + { + *s = c; + chars = 1; + } } else if (! isprint (uc)) { if (use_esc_sequence) - { - width = 4; - chars = 4; - *s++ = '\\'; - sprintf (esc_buff, "%03o", uc); - for (i = 0; i <= 2; ++i) - *s++ = esc_buff[i]; - } + { + width = 4; + chars = 4; + *s++ = '\\'; + sprintf (esc_buff, "%03o", uc); + for (i = 0; i <= 2; ++i) + *s++ = esc_buff[i]; + } else if (use_cntrl_prefix) - { - if (uc < 0200) - { - width = 2; - chars = 2; - *s++ = '^'; - *s++ = c ^ 0100; - } - else - { - width = 4; - chars = 4; - *s++ = '\\'; - sprintf (esc_buff, "%03o", uc); - for (i = 0; i <= 2; ++i) - *s++ = esc_buff[i]; - } - } + { + if (uc < 0200) + { + width = 2; + chars = 2; + *s++ = '^'; + *s = c ^ 0100; + } + else + { + width = 4; + chars = 4; + *s++ = '\\'; + sprintf (esc_buff, "%03o", uc); + for (i = 0; i <= 2; ++i) + *s++ = esc_buff[i]; + } + } else if (c == '\b') - { - width = -1; - chars = 1; - *s = c; - } + { + width = -1; + chars = 1; + *s = c; + } else - { - width = 0; - chars = 1; - *s = c; - } + { + width = 0; + chars = 1; + *s = c; + } } else { @@ -2734,14 +2680,24 @@ char_to_clump (char c) *s = c; } - input_position += width; + /* Too many backspaces must put us in position 0 -- never negative. */ + if (width < 0 && input_position == 0) + { + chars = 0; + input_position = 0; + } + else if (width < 0 && input_position <= -width) + input_position = 0; + else + input_position += width; + return chars; } /* We've just printed some files and need to clean up things before looking for more options and printing the next batch of files. - Free everything we've xmalloc'ed, except `header'. */ + Free everything we've xmalloc'ed, except 'header'. */ static void cleanup (void) @@ -2753,36 +2709,35 @@ cleanup (void) free (end_vector); free (buff); } - + /* Complain, print a usage message, and die. */ void usage (int status) { if (status != EXIT_SUCCESS) - fprintf (stderr, _("Try `%s --help' for more information.\n"), - program_name); + emit_try_help (); else { printf (_("\ Usage: %s [OPTION]... [FILE]...\n\ "), - program_name); + program_name); fputs (_("\ Paginate or columnate FILE(s) for printing.\n\ -\n\ -"), stdout); - fputs (_("\ -Mandatory arguments to long options are mandatory for short options too.\n\ "), stdout); + + emit_stdin_note (); + emit_mandatory_arg_note (); + fputs (_("\ +FIRST_PAGE[:LAST_PAGE], --pages=FIRST_PAGE[:LAST_PAGE]\n\ begin [stop] printing with page FIRST_[LAST_]PAGE\n\ -COLUMN, --columns=COLUMN\n\ output COLUMN columns and print columns down,\n\ unless -a is used. Balance number of lines in the\n\ - columns on each page.\n\ + columns on each page\n\ "), stdout); fputs (_("\ -a, --across print columns across rather than down, used together\n\ @@ -2803,7 +2758,7 @@ Mandatory arguments to long options are mandatory for short options too.\n\ and trailer without -F)\n\ "), stdout); fputs (_("\ - -h HEADER, --header=HEADER\n\ + -h, --header=HEADER\n\ use a centered HEADER instead of filename in page header,\n\ -h \"\" prints a blank line, don't use -h\"\"\n\ -i[CHAR[WIDTH]], --output-tabs[=CHAR[WIDTH]]\n\ @@ -2812,9 +2767,12 @@ Mandatory arguments to long options are mandatory for short options too.\n\ alignment, --sep-string[=STRING] sets separators\n\ "), stdout); fputs (_("\ - -l PAGE_LENGTH, --length=PAGE_LENGTH\n\ + -l, --length=PAGE_LENGTH\n\ set the page length to PAGE_LENGTH (66) lines\n\ - (default number of lines of text 56, and with -F 63)\n\ + (default number of lines of text 56, and with -F 63).\n\ + implies -t if PAGE_LENGTH <= 10\n\ +"), stdout); + fputs (_("\ -m, --merge print all files in parallel, one in each column,\n\ truncate lines, but join lines of full length with -J\n\ "), stdout); @@ -2822,32 +2780,34 @@ Mandatory arguments to long options are mandatory for short options too.\n\ -n[SEP[DIGITS]], --number-lines[=SEP[DIGITS]]\n\ number lines, use DIGITS (5) digits, then SEP (TAB),\n\ default counting starts with 1st line of input file\n\ - -N NUMBER, --first-line-number=NUMBER\n\ + -N, --first-line-number=NUMBER\n\ start counting with NUMBER at 1st line of first\n\ page printed (see +FIRST_PAGE)\n\ "), stdout); fputs (_("\ - -o MARGIN, --indent=MARGIN\n\ + -o, --indent=MARGIN\n\ offset each line with MARGIN (zero) spaces, do not\n\ affect -w or -W, MARGIN will be added to PAGE_WIDTH\n\ -r, --no-file-warnings\n\ omit warning when a file cannot be opened\n\ "), stdout); fputs (_("\ - -s[CHAR],--separator[=CHAR]\n\ + -s[CHAR], --separator[=CHAR]\n\ separate columns by a single character, default for CHAR\n\ - is the <TAB> character without -w and \'no char\' with -w\n\ + is the <TAB> character without -w and \'no char\' with -w.\ +\n\ -s[CHAR] turns off line truncation of all 3 column\n\ options (-COLUMN|-a -COLUMN|-m) except -w is set\n\ "), stdout); fputs (_("\ - -SSTRING, --sep-string[=STRING]\n\ -"), stdout); - fputs (_("\ + -S[STRING], --sep-string[=STRING]\n\ separate columns by STRING,\n\ without -S: Default separator <TAB> with -J and <space>\n\ otherwise (same as -S\" \"), no effect on column options\n\ - -t, --omit-header omit page headers and trailers\n\ +"), stdout); + fputs (_("\ + -t, --omit-header omit page headers and trailers;\n\ + implied if PAGE_LENGTH <= 10\n\ "), stdout); fputs (_("\ -T, --omit-pagination\n\ @@ -2855,24 +2815,19 @@ Mandatory arguments to long options are mandatory for short options too.\n\ by form feeds set in input files\n\ -v, --show-nonprinting\n\ use octal backslash notation\n\ - -w PAGE_WIDTH, --width=PAGE_WIDTH\n\ + -w, --width=PAGE_WIDTH\n\ set page width to PAGE_WIDTH (72) characters for\n\ multiple text-column output only, -s[char] turns off (72)\n\ "), stdout); fputs (_("\ - -W PAGE_WIDTH, --page-width=PAGE_WIDTH\n\ + -W, --page-width=PAGE_WIDTH\n\ set page width to PAGE_WIDTH (72) characters always,\n\ truncate lines, except -J option is set, no interference\n\ with -S or -s\n\ "), stdout); fputs (HELP_OPTION_DESCRIPTION, stdout); fputs (VERSION_OPTION_DESCRIPTION, stdout); - fputs (_("\ -\n\ --T implied by -l nn when nn <= 10 or <= 3 with -F. With no FILE, or when\n\ -FILE is -, read standard input.\n\ -"), stdout); - printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + emit_ancillary_info (PROGRAM_NAME); } exit (status); } |