/* pr -- convert text files for printing.                                       This is the pr utility
   Copyright (C) 1988-2018 Free Software Foundation, Inc.                       
                                                                                
   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 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               
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                
   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, see <https://www.gnu.org/licenses/>.  */   The GNUv3 license
                                                                                
/*  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{,,,}                                           
   pr -6 -a -n -o5 /usr/dict/words                                              
                                                                                
   Ideas:                                                                       
                                                                                
   Keep a things_to_do list of functions to call when we know we have           
   something to print.  Cleaner than current series of checks.                  
                                                                                
   Improve the printing of control prefixes.                                    
                                                                                
   Expand the file name in the centered header line to a full file name.        
                                                                                
                                                                                
   Concept:                                                                     
                                                                                
   If the input_tab_char differs from the default value TAB                     
   ('-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           
   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.        
   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'.                
   (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           
   column definition. The n-separator TAB is expanded to the same number        
   of spaces in each column using the default value 8. Tabification is          
   only performed if it is compatible with the output position.                 
   Consequence: The output text columns are of equal width. The layout          
   of a page does not change if the left margin varies. - Looks better          
   than the SunOS approach.                                                     
      SunOS pr gives priority to the 1st requirement. n-separator TAB           
   width varies with each column. Only the width of text part of the            
   column is fixed.                                                             
   Consequence: The output text columns don't have equal width. The             
   widths and the layout of the whole page varies with the left margin.         
   An overflow of the line length (without margin) over the input value         
   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 structure and the default - not generally - page_width,               
   acts on -w option")                                                          
       options:       text form  / separator:     equivalent new options:       
       -w l   -s[x]                                                             
    --------------------------------------------------------------------        
    1.  --     --     columns    / space          --                            
                      trunc. to page_width = 72                                 
    2.  --    -s[:]   full lines / TAB[:]         -J  --sep-string[="<TAB>"|:]  
                      no truncation                                             
    3.  -w l   --     columns    / space          -W l                          
                      trunc. to page_width = l                                  
    4.  -w l  -s[:]   columns    / no sep.[:]     -W l  --sep-string[=:]        
                      trunc. to page_width = l                                  
    --------------------------------------------------------------------        
                                                                                
                                                                                
   Options:                                                                     
                                                                                
   Including version 1.22i:                                                     
   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.                                                                 
   Some NEW CAPITAL LETTER options ( -J, -S, -W) has been introduced to         
   turn off unexpected interferences of small letter options (-s and -w         
   together with the three column options).                                     
   -N option and the second argument LAST_PAGE of +FIRST_PAGE offer more        
   flexibility; The detailed handling of form feeds set in the input            
   files requires -T option.                                                    
                                                                                
   Capital letter options dominate small letter ones.                           
                                                                                
   Some of the option-arguments cannot be specified as separate arguments       
   from the preceding option letter (already stated in POSIX specification).    
                                                                                
   Form feeds in the input cause page breaks in the output. Multiple            
   form feeds produce empty pages.                                              
                                                                                
   +FIRST_PAGE[:LAST_PAGE], --pages=FIRST_PAGE[: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.                              
                                                                                
   -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                                                            
                                                                                
   -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.              
                                                                                
   -c, --show-control-chars                                                     
                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.)                                                 
                                                                                
   -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.      
                                                                                
   -h HEADER, --header=HEADER                                                   
                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)                                           
                                                                                
   -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.                                
                                                                                
   -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).                                               
                                                                                
   -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.                                          
                                                                                
                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.                     
                                                                                
                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).                       
                                                                                
   -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).                                                
                                                                                
   -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.                               
                                                                                
   -r, --no-file-warnings                                                       
                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.                            
                                                                                
   -t, --omit-header Do not print headers or footers but retain form            
                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.                           
                                                                                
   -v, --show-nonprinting                                                       
                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.                                                    
                                                                                
   -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.)                                              
                                                                                
*/                                                                              
                                                                                
#include <config.h>                                                             Provides system specific information
                                                                                
#include <getopt.h>                                                             ...!includes auto-comment...
#include <sys/types.h>                                                          Provides system data types
#include "system.h"                                                             ...!includes auto-comment...
#include "die.h"                                                                ...!includes auto-comment...
#include "error.h"                                                              ...!includes auto-comment...
#include "fadvise.h"                                                            ...!includes auto-comment...
#include "hard-locale.h"                                                        ...!includes auto-comment...
#include "mbswidth.h"                                                           ...!includes auto-comment...
#include "quote.h"                                                              ...!includes auto-comment...
#include "stat-time.h"                                                          ...!includes auto-comment...
#include "stdio--.h"                                                            ...!includes auto-comment...
#include "strftime.h"                                                           ...!includes auto-comment...
#include "xstrtol.h"                                                            ...!includes auto-comment...
#include "xdectoint.h"                                                          ...!includes auto-comment...
                                                                                
/* The official name of this program (e.g., no 'g' prefix).  */                 
#define PROGRAM_NAME "pr"                                                       Line 328
                                                                                
#define AUTHORS \                                                               Line 330
  proper_name ("Pete TerMaat"), \                                               Line 331
  proper_name ("Roland Huebner")                                                Line 332
                                                                                
/* Used with start_position in the struct COLUMN described below.               
   If start_position == ANYWHERE, we aren't truncating columns and              
   can begin printing a column anywhere.  Otherwise we must pad to              
   the horizontal position start_position. */                                   
#define ANYWHERE 0                                                              Line 338
                                                                                
/* Each column has one of these structures allocated for it.                    
   If we're only dealing with one file, fp is the same for all                  
   columns.                                                                     
                                                                                
   The general strategy is to spend time setting up these column                
   structures (storing columns if necessary), after which printing              
   is a matter of flitting from column to column and calling                    
   print_func.                                                                  
                                                                                
   Parallel files, single files printing across in multiple                     
   columns, and single files printing down in multiple columns all              
   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().       
                                                                                
   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().                      
                                                                                
   current_line  Index of the current entry in line_vector, which               
                        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.                                                   
                                                                                
   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.          
                                                                                
   start_position The horizontal position we want to be in before we            
                        print the first character in this column.               
                                                                                
   numbered  True means precede this column with a line number. */              
                                                                                
/* FIXME: There are many unchecked integer overflows in this file,              
   that will cause this command to misbehave given large inputs or              
   options.  Many of the "int" values below should be "size_t" or               
   something else like that.  */                                                
                                                                                
struct COLUMN;                                                                  Line 383
struct COLUMN                                                                   Line 384
  {                                                                             
    FILE *fp;   /* Input stream for this column. */                             Line 386
    char const *name;  /* File name. */                                         Line 387
    enum                                                                        Line 388
      {                                                                         
        OPEN,                                                                   Line 390
        FF_FOUND,  /* used with -b option, set with \f, changed                 Line 391
                                   to ON_HOLD after print_header */             
        ON_HOLD,  /* Hit a form feed. */                                        Line 393
        CLOSED                                                                  Line 394
      }                                                                         
    status;   /* Status of the file pointer. */                                 Line 396
                                                                                
    /* Func to print lines in this col. */                                      
    bool (*print_func) (struct COLUMN *);                                       Line 399
                                                                                
    /* Func to print/store chars in this col. */                                
    void (*char_func) (char);                                                   Line 402
                                                                                
    int current_line;  /* Index of current place in line_vector. */             Line 404
    int lines_stored;  /* Number of lines stored in buff. */                    Line 405
    int lines_to_print;  /* No. lines stored or space left on page. */          Line 406
    int start_position;  /* Horizontal position of first char. */               Line 407
    bool numbered;                                                              Line 408
    bool full_page_printed; /* True means printed without a FF found. */        Line 409
                                                                                
    /* p->full_page_printed  controls a special case of "FF set by hand":       
       True means a full page has been printed without FF found. To avoid an    
       additional empty page we have to ignore a FF immediately following in    
       the next line. */                                                        
  };                                                                            Block 1
                                                                                
typedef struct COLUMN COLUMN;                                                   Line 417
                                                                                
static int char_to_clump (char c);                                              Line 419
static bool read_line (COLUMN *p);                                              Line 420
static bool print_page (void);                                                  Line 421
static bool print_stored (COLUMN *p);                                           Line 422
static bool open_file (char *name, COLUMN *p);                                  Line 423
static bool skip_to_page (uintmax_t page);                                      Line 424
static void print_header (void);                                                Line 425
static void pad_across_to (int position);                                       Line 426
static void add_line_number (COLUMN *p);                                        Line 427
static void getoptnum (const char *n_str, int min, int *num,                    Line 428
                       const char *errfmt);                                     Line 429
static void getoptarg (char *arg, char switch_char, char *character,            Line 430
                       int *number);                                            Line 431
static void print_files (int number_of_files, char **av);                       Line 432
static void init_parameters (int number_of_files);                              Line 433
static void init_header (char const *filename, int desc);                       Line 434
static bool init_fps (int number_of_files, char **av);                          Line 435
static void init_funcs (void);                                                  Line 436
static void init_store_cols (void);                                             Line 437
static void store_columns (void);                                               Line 438
static void balance (int total_stored);                                         Line 439
static void store_char (char c);                                                Line 440
static void pad_down (unsigned int lines);                                      Line 441
static void read_rest_of_line (COLUMN *p);                                      Line 442
static void skip_read (COLUMN *p, int column_number);                           Line 443...!syscalls auto-comment...
static void print_char (char c);                                                Line 444
static void cleanup (void);                                                     Line 445
static void print_sep_string (void);                                            Line 446
static void separator_string (const char *optarg_S);                            Line 447
                                                                                
/* All of the columns to print.  */                                             
static COLUMN *column_vector;                                                   Line 450
                                                                                
/* When printing a single file in multiple downward columns,                    
   we store the leftmost columns contiguously in buff.                          
   To print a line from buff, get the index of the first character              
   from line_vector[i], and print up to line_vector[i + 1]. */                  
static char *buff;                                                              Line 456
                                                                                
/* Index of the position in buff where the next character                       
   will be stored. */                                                           
static unsigned int buff_current;                                               Line 460
                                                                                
/* The number of characters in buff.                                            
   Used for allocation of buff and to detect overflow of buff. */               
static size_t buff_allocated;                                                   Line 464
                                                                                
/* Array of indices into buff.                                                  
   Each entry is an index of the first character of a line.                     
   This is used when storing lines to facilitate shuffling when                 
   we do column balancing on the last page. */                                  
static int *line_vector;                                                        Line 470
                                                                                
/* 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              
   column. */                                                                   
static int *end_vector;                                                         Line 477
                                                                                
/* (-m) True means we're printing multiple files in parallel. */                
static bool parallel_files = false;                                             Line 480
                                                                                
/* (-m) True means a line starts with some empty columns (some files            
   already CLOSED or ON_HOLD) which we have to align. */                        
static bool align_empty_cols;                                                   Line 484
                                                                                
/* (-m) True means we have not yet found any printable column in a line.        
   align_empty_cols = true  has to be maintained. */                            
static bool empty_line;                                                         Line 488
                                                                                
/* (-m) False means printable column output precedes a form feed found.         
   Column alignment is done only once. No additional action with that form      
   feed.                                                                        
   True means we found only a form feed in a column. Maybe we have to do        
   some column alignment with that form feed. */                                
static bool FF_only;                                                            Line 495
                                                                                
/* (-[0-9]+) True means we're given an option explicitly specifying             
   number of columns.  Used to detect when this option is used with -m          
   and when translating old options to new/long options. */                     
static bool explicit_columns = false;                                           Line 500
                                                                                
/* (-t|-T) False means we aren't printing headers and footers. */               
static bool extremities = true;                                                 Line 503
                                                                                
/* (-t) True means we retain all FF set by hand in input files.                 
   False is set with -T option. */                                              
static bool keep_FF = false;                                                    Line 507
static bool print_a_FF = false;                                                 Line 508
                                                                                
/* True means we need to print a header as soon as we know we've got input      
   to print after it. */                                                        
static bool print_a_header;                                                     Line 512
                                                                                
/* (-f) True means use formfeeds instead of newlines to separate pages. */      
static bool use_form_feed = false;                                              Line 515
                                                                                
/* True means we have read the standard input. */                               
static bool have_read_stdin = false;                                            Line 518
                                                                                
/* True means the -a flag has been given. */                                    
static bool print_across_flag = false;                                          Line 521
                                                                                
/* True means we're printing one file in multiple (>1) downward columns. */     
static bool storing_columns = true;                                             Line 524
                                                                                
/* (-b) True means balance columns on the last page as Sys V does. */           
/* That's no longer an independent option. With storing_columns = true          
   balance_columns = true is used too (s. function init_parameters).            
   We get a consistent formulation with "FF set by hand" in input files. */     
static bool balance_columns = false;                                            Line 530
                                                                                
/* (-l) Number of lines on a page, including header and footer lines. */        
static int lines_per_page = 66;                                                 Line 533
                                                                                
/* Number of lines in the header and footer can be reset to 0 using             
   the -t flag. */                                                              
enum { lines_per_header = 5 };                                                  Line 537Block 2
static int lines_per_body;                                                      Line 538
enum { lines_per_footer = 5 };                                                  Line 539
                                                                                
/* (-w|-W) Width in characters of the page.  Does not include the width of      
   the margin. */                                                               
static int chars_per_line = 72;                                                 Line 543
                                                                                
/* (-w|W) True means we truncate lines longer than chars_per_column. */         
static bool truncate_lines = false;                                             Line 546
                                                                                
/* (-J) True means we join lines without any line truncation. -J                
   dominates -w option. */                                                      
static bool join_lines = false;                                                 Line 550
                                                                                
/* Number of characters in a column.  Based on col_sep_length and               
   page width. */                                                               
static int chars_per_column;                                                    Line 554
                                                                                
/* (-e) True means convert tabs to spaces on input. */                          
static bool untabify_input = false;                                             Line 557
                                                                                
/* (-e) The input tab character. */                                             
static char input_tab_char = '\t';                                              Line 560
                                                                                
/* (-e) Tabstops are at chars_per_tab, 2*chars_per_tab, 3*chars_per_tab, ...    
   where the leftmost column is 1. */                                           
static int chars_per_input_tab = 8;                                             Line 564
                                                                                
/* (-i) True means convert spaces to tabs on output. */                         
static bool tabify_output = false;                                              Line 567
                                                                                
/* (-i) The output tab character. */                                            
static char output_tab_char = '\t';                                             Line 570
                                                                                
/* (-i) The width of the output tab. */                                         
static int chars_per_output_tab = 8;                                            Line 573
                                                                                
/* Keeps track of pending white space.  When we hit a nonspace                  
   character after some whitespace, we print whitespace, tabbing                
   if necessary to get to output_position + spaces_not_printed. */              
static int spaces_not_printed;                                                  Line 578
                                                                                
/* (-o) Number of spaces in the left margin (tabs used when possible). */       
static int chars_per_margin = 0;                                                Line 581
                                                                                
/* Position where the next character will fall.                                 
   Leftmost position is 0 + chars_per_margin.                                   
   Rightmost position is chars_per_margin + chars_per_line - 1.                 
   This is important for converting spaces to tabs on output. */                
static int output_position;                                                     Line 587
                                                                                
/* Horizontal position relative to the current file.                            
   (output_position depends on where we are on the page;                        
   input_position depends on where we are in the file.)                         
   Important for converting tabs to spaces on input. */                         
static int input_position;                                                      Line 593
                                                                                
/* True if there were any failed opens so we can exit with nonzero              
   status.  */                                                                  
static bool failed_opens = false;                                               Line 597
                                                                                
/* The number of spaces taken up if we print a tab character with width         
   c_ from position h_. */                                                      
#define TAB_WIDTH(c_, h_) ((c_) - ((h_) % (c_)))                                Line 601
                                                                                
/* The horizontal position we'll be at after printing a tab character           
   of width c_ from the position h_. */                                         
#define POS_AFTER_TAB(c_, h_) ((h_) + TAB_WIDTH (c_, h_))                       Line 605
                                                                                
/* (-NNN) Number of columns of text to print. */                                
static int columns = 1;                                                         Line 608
                                                                                
/* (+NNN:MMM) Page numbers on which to begin and stop printing.                 
   first_page_number = 0  will be used to check input only. */                  
static uintmax_t first_page_number = 0;                                         Line 612
static uintmax_t last_page_number = UINTMAX_MAX;                                Line 613
                                                                                
/* Number of files open (not closed, not on hold). */                           
static int files_ready_to_read = 0;                                             Line 616
                                                                                
/* Current page number.  Displayed in header. */                                
static uintmax_t page_number;                                                   Line 619
                                                                                
/* Current line number.  Displayed when -n flag is specified.                   
                                                                                
   When printing files in parallel (-m flag), line numbering is as follows:     
   1    foo     goo     moo                                                     
   2    hoo     too     zoo                                                     
                                                                                
   When printing files across (-a flag), ...                                    
   1    foo     2       moo     3       goo                                     
   4    hoo     5       too     6       zoo                                     
                                                                                
   Otherwise, line numbering is as follows:                                     
   1    foo     3       goo     5       too                                     
   2    moo     4       hoo     6       zoo */                                  
static int line_number;                                                         Line 634
                                                                                
/* (-n) True means lines should be preceded by numbers. */                      
static bool numbered_lines = false;                                             Line 637
                                                                                
/* (-n) Character which follows each line number. */                            
static char number_separator = '\t';                                            Line 640
                                                                                
/* (-n) line counting starts with 1st line of input file (not with 1st          
   line of 1st page printed). */                                                
static int line_count = 1;                                                      Line 644
                                                                                
/* (-n) True means counting of skipped lines starts with 1st line of            
   input file. False means -N option is used in addition, counting of           
   skipped lines not required. */                                               
static bool skip_count = true;                                                  Line 649
                                                                                
/* (-N) Counting starts with start_line_number = NUMBER at 1st line of          
   first page printed, usually not 1st page of input file. */                   
static int start_line_num = 1;                                                  Line 653
                                                                                
/* (-n) Width in characters of a line number. */                                
static int chars_per_number = 5;                                                Line 656
                                                                                
/* Used when widening the first column to accommodate numbers -- only           
   needed when printing files in parallel.  Includes width of both the          
   number and the number_separator. */                                          
static int number_width;                                                        Line 661
                                                                                
/* Buffer sprintf uses to format a line number. */                              
static char *number_buff;                                                       Line 664
                                                                                
/* (-v) True means unprintable characters are printed as escape sequences.      
   control-g becomes \007. */                                                   
static bool use_esc_sequence = false;                                           Line 668
                                                                                
/* (-c) True means unprintable characters are printed as control prefixes.      
   control-g becomes ^G. */                                                     
static bool use_cntrl_prefix = false;                                           Line 672
                                                                                
/* (-d) True means output is double spaced. */                                  
static bool double_space = false;                                               Line 675
                                                                                
/* Number of files opened initially in init_files.  Should be 1                 
   unless we're printing multiple files in parallel. */                         
static int total_files = 0;                                                     Line 679
                                                                                
/* (-r) True means don't complain if we can't open a file. */                   
static bool ignore_failed_opens = false;                                        Line 682
                                                                                
/* (-S) True means we separate columns with a specified string.                 
   -S option does not affect line truncation nor column alignment. */           
static bool use_col_separator = false;                                          Line 686
                                                                                
/* 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 const *col_sep_string = "";                                         Line 691
static int col_sep_length = 0;                                                  Line 692
static char *column_separator = (char *) " ";                                   Line 693
static char *line_separator = (char *) "\t";                                    Line 694
                                                                                
/* Number of separator characters waiting to be printed as soon as we           
   know that we have any input remaining to be printed. */                      
static int separators_not_printed;                                              Line 698
                                                                                
/* Position we need to pad to, as soon as we know that we have input            
   remaining to be printed. */                                                  
static int padding_not_printed;                                                 Line 702
                                                                                
/* True means we should pad the end of the page.  Remains false until we        
   know we have a page to print. */                                             
static bool pad_vertically;                                                     Line 706
                                                                                
/* (-h) String of characters used in place of the filename in the header. */    
static char *custom_header;                                                     Line 709
                                                                                
/* (-D) Date format for the header.  */                                         
static char const *date_format;                                                 Line 712
                                                                                
/* The local time zone rules, as per the TZ environment variable.  */           
static timezone_t localtz;                                                      Line 715
                                                                                
/* Date and file name for the header.  */                                       
static char *date_text;                                                         Line 718
static char const *file_text;                                                   Line 719
                                                                                
/* Output columns available, not counting the date and file name.  */           
static int header_width_available;                                              Line 722
                                                                                
static char *clump_buff;                                                        Line 724
                                                                                
/* True means we read the line no. lines_per_body in skip_read                  
   called by skip_to_page. That variable controls the coincidence of a          
   "FF set by hand" and "full_page_printed", see above the definition of        
   structure COLUMN. */                                                         
static bool last_line = false;                                                  Line 730
                                                                                
/* For long options that have no equivalent short option, use a                 
   non-character as a pseudo short option, starting with CHAR_MAX + 1.  */      
enum                                                                            Line 734
{                                                                               
  COLUMNS_OPTION = CHAR_MAX + 1,                                                Line 736
  PAGES_OPTION                                                                  Line 737
};                                                                              Block 4
                                                                                
static char const short_options[] =                                             Line 740
  "-0123456789D:FJN:S::TW:abcde::fh:i::l:mn::o:rs::tvw:";                       Line 741
                                                                                
static struct option const long_options[] =                                     Line 743
{                                                                               
  {"pages", required_argument, NULL, PAGES_OPTION},                             Line 745
  {"columns", required_argument, NULL, COLUMNS_OPTION},                         Line 746
  {"across", no_argument, NULL, 'a'},                                           Line 747
  {"show-control-chars", no_argument, NULL, 'c'},                               Line 748
  {"double-space", no_argument, NULL, 'd'},                                     Line 749
  {"date-format", required_argument, NULL, 'D'},                                Line 750
  {"expand-tabs", optional_argument, NULL, 'e'},                                Line 751
  {"form-feed", no_argument, NULL, 'f'},                                        Line 752
  {"header", required_argument, NULL, 'h'},                                     Line 753
  {"output-tabs", optional_argument, NULL, 'i'},                                Line 754
  {"join-lines", no_argument, NULL, 'J'},                                       Line 755
  {"length", required_argument, NULL, 'l'},                                     Line 756
  {"merge", no_argument, NULL, 'm'},                                            Line 757
  {"number-lines", optional_argument, NULL, 'n'},                               Line 758
  {"first-line-number", required_argument, NULL, 'N'},                          Line 759
  {"indent", required_argument, NULL, 'o'},                                     Line 760
  {"no-file-warnings", no_argument, NULL, 'r'},                                 Line 761
  {"separator", optional_argument, NULL, 's'},                                  Line 762
  {"sep-string", optional_argument, NULL, 'S'},                                 Line 763
  {"omit-header", no_argument, NULL, 't'},                                      Line 764
  {"omit-pagination", no_argument, NULL, 'T'},                                  Line 765
  {"show-nonprinting", no_argument, NULL, 'v'},                                 Line 766
  {"width", required_argument, NULL, 'w'},                                      Line 767
  {"page-width", required_argument, NULL, 'W'},                                 Line 768
  {GETOPT_HELP_OPTION_DECL},                                                    Line 769
  {GETOPT_VERSION_OPTION_DECL},                                                 Line 770
  {NULL, 0, NULL, 0}                                                            Line 771
};                                                                              Block 5
                                                                                
static void                                                                     Line 774
integer_overflow (void)                                                         Line 775
{                                                                               
  die (EXIT_FAILURE, 0, _("integer overflow"));                                 Line 777
}                                                                               Block 6
                                                                                
/* Return the number of columns that have either an open file or                
   stored lines. */                                                             
                                                                                
static unsigned int _GL_ATTRIBUTE_PURE                                          Line 783
cols_ready_to_print (void)                                                      Line 784
{                                                                               
  COLUMN *q;                                                                    Line 786
  unsigned int i;                                                               Line 787
  unsigned int n;                                                               Line 788
                                                                                
  n = 0;                                                                        Line 790
  for (q = column_vector, i = 0; i < columns; ++q, ++i)                         Line 791
    if (q->status == OPEN                                                       Line 792
        || q->status == FF_FOUND /* With -b: To print a header only */          Line 793
        || (storing_columns && q->lines_stored > 0 && q->lines_to_print > 0))   Line 794
      ++n;                                                                      Line 795
  return n;                                                                     Line 796
}                                                                               Block 7
                                                                                
/* Estimate first_ / last_page_number                                           
   using option +FIRST_PAGE:LAST_PAGE */                                        
                                                                                
static bool                                                                     Line 802
first_last_page (int oi, char c, char const *pages)                             Line 803
{                                                                               
  char *p;                                                                      Line 805
  uintmax_t first;                                                              Line 806
  uintmax_t last = UINTMAX_MAX;                                                 Line 807
  strtol_error err = xstrtoumax (pages, &p, 10, &first, "");                    Line 808
  if (err != LONGINT_OK && err != LONGINT_INVALID_SUFFIX_CHAR)                  Line 809
    xstrtol_fatal (err, oi, c, long_options, pages);                            Line 810
                                                                                
  if (p == pages || !first)                                                     Line 812
    return false;                                                               Line 813
                                                                                
  if (*p == ':')                                                                Line 815
    {                                                                           
      char const *p1 = p + 1;                                                   Line 817
      err = xstrtoumax (p1, &p, 10, &last, "");                                 Line 818
      if (err != LONGINT_OK)                                                    Line 819
        xstrtol_fatal (err, oi, c, long_options, pages);                        Line 820
      if (p1 == p || last < first)                                              Line 821
        return false;                                                           Line 822
    }                                                                           
                                                                                
  if (*p)                                                                       Line 825
    return false;                                                               Line 826
                                                                                
  first_page_number = first;                                                    Line 828
  last_page_number = last;                                                      Line 829
  return true;                                                                  Line 830
}                                                                               Block 8
                                                                                
/* 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.  Otherwise, exit with a diagnostic.  */        
                                                                                
static void                                                                     Line 837
parse_column_count (char const *s)                                              Line 838
{                                                                               
  getoptnum (s, 1, &columns, _("invalid number of columns"));                   Line 840
  explicit_columns = true;                                                      Line 841
}                                                                               Block 9
                                                                                
/* Estimate length of col_sep_string with option -S.  */                        
                                                                                
static void                                                                     Line 846
separator_string (const char *optarg_S)                                         Line 847
{                                                                               
  size_t len = strlen (optarg_S);                                               Line 849
  if (INT_MAX < len)                                                            Line 850
    integer_overflow ();                                                        Line 851
  col_sep_length = len;                                                         Line 852
  col_sep_string = optarg_S;                                                    Line 853
}                                                                               Block 10
                                                                                
int                                                                             
main (int argc, char **argv)                                                    Line 857
{                                                                               
  unsigned int n_files;                                                         Line 859
  bool old_options = false;                                                     Line 860
  bool old_w = false;                                                           Line 861
  bool old_s = false;                                                           Line 862
  char **file_names;                                                            Line 863
                                                                                
  /* Accumulate the digits of old-style options like -99.  */                   
  char *column_count_string = NULL;                                             Line 866
  size_t n_digits = 0;                                                          Line 867
  size_t n_alloc = 0;                                                           Line 868
                                                                                
  initialize_main (&argc, &argv);                                               VMS-specific entry point handling wildcard expansion
  set_program_name (argv[0]);                                                   Retains program name and discards path
  setlocale (LC_ALL, "");                                                       Sets up internationalization (i18n)
  bindtextdomain (PACKAGE, LOCALEDIR);                                          Assigns i18n directorySets text domain for _() [gettext()] function
  textdomain (PACKAGE);                                                         Sets text domain for _() [gettext()] function
                                                                                
  atexit (close_stdout);                                                        Close stdout on exit (see gnulib)
                                                                                
  n_files = 0;                                                                  Line 878
  file_names = (argc > 1                                                        Line 879
                ? xnmalloc (argc - 1, sizeof (char *))                          Line 880
                : NULL);                                                        Line 881
                                                                                
  while (true)                                                                  Line 883
    {                                                                           
      int oi = -1;                                                              Line 885
      int c = getopt_long (argc, argv, short_options, long_options, &oi);       Line 886
      if (c == -1)                                                              Line 887
        break;                                                                  Line 888
                                                                                
      if (ISDIGIT (c))                                                          Line 890
        {                                                                       
          /* Accumulate column-count digits specified via old-style options. */ 
          if (n_digits + 1 >= n_alloc)                                          Line 893
            column_count_string                                                 Line 894
              = X2REALLOC (column_count_string, &n_alloc);                      Line 895
          column_count_string[n_digits++] = c;                                  Line 896
          column_count_string[n_digits] = '\0';                                 Line 897
          continue;                                                             Line 898
        }                                                                       
                                                                                
      n_digits = 0;                                                             Line 901
                                                                                
      switch (c)                                                                Line 903
        {                                                                       
        case 1:   /* Non-option argument. */                                    Line 905
          /* long option --page dominates old '+FIRST_PAGE ...'.  */            
          if (! (first_page_number == 0                                         Line 907
                 && *optarg == '+' && first_last_page (-2, '+', optarg + 1)))   Line 908
            file_names[n_files++] = optarg;                                     Line 909
          break;                                                                Line 910
                                                                                
        case PAGES_OPTION: /* --pages=FIRST_PAGE[:LAST_PAGE] */                 Line 912
          {   /* dominates old opt +... */                                      Line 913
            if (! optarg)                                                       Line 914
              die (EXIT_FAILURE, 0,                                             Line 915
                   _("'--pages=FIRST_PAGE[:LAST_PAGE]' missing argument"));     Line 916
            else if (! first_last_page (oi, 0, optarg))                         Line 917
              die (EXIT_FAILURE, 0, _("invalid page range %s"),                 Line 918
                   quote (optarg));                                             Line 919
            break;                                                              Line 920
          }                                                                     
                                                                                
        case COLUMNS_OPTION: /* --columns=COLUMN */                             Line 923
          {                                                                     
            parse_column_count (optarg);                                        Line 925
                                                                                
            /* 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);                                         Line 930
            column_count_string = NULL;                                         Line 931
            n_alloc = 0;                                                        Line 932
            break;                                                              Line 933
          }                                                                     
                                                                                
        case 'a':                                                               Line 936
          print_across_flag = true;                                             Line 937
          storing_columns = false;                                              Line 938
          break;                                                                Line 939
        case 'b':                                                               Line 940
          balance_columns = true;                                               Line 941
          break;                                                                Line 942
        case 'c':                                                               Line 943
          use_cntrl_prefix = true;                                              Line 944
          break;                                                                Line 945
        case 'd':                                                               Line 946
          double_space = true;                                                  Line 947
          break;                                                                Line 948
        case 'D':                                                               Line 949
          date_format = optarg;                                                 Line 950
          break;                                                                Line 951
        case 'e':                                                               Line 952
          if (optarg)                                                           Line 953
            getoptarg (optarg, 'e', &input_tab_char,                            Line 954
                       &chars_per_input_tab);                                   Line 955
          /* Could check tab width > 0. */                                      
          untabify_input = true;                                                Line 957
          break;                                                                Line 958
        case 'f':                                                               Line 959
        case 'F':                                                               Line 960
          use_form_feed = true;                                                 Line 961
          break;                                                                Line 962
        case 'h':                                                               Line 963
          custom_header = optarg;                                               Line 964
          break;                                                                Line 965
        case 'i':                                                               Line 966
          if (optarg)                                                           Line 967
            getoptarg (optarg, 'i', &output_tab_char,                           Line 968
                       &chars_per_output_tab);                                  Line 969
          /* Could check tab width > 0. */                                      
          tabify_output = true;                                                 Line 971
          break;                                                                Line 972
        case 'J':                                                               Line 973
          join_lines = true;                                                    Line 974
          break;                                                                Line 975
        case 'l':                                                               Line 976
          getoptnum (optarg, 1, &lines_per_page,                                Line 977
                     _("'-l PAGE_LENGTH' invalid number of lines"));            Line 978
          break;                                                                Line 979
        case 'm':                                                               Line 980
          parallel_files = true;                                                Line 981
          storing_columns = false;                                              Line 982
          break;                                                                Line 983
        case 'n':                                                               Line 984
          numbered_lines = true;                                                Line 985
          if (optarg)                                                           Line 986
            getoptarg (optarg, 'n', &number_separator,                          Line 987
                       &chars_per_number);                                      Line 988
          break;                                                                Line 989
        case 'N':                                                               Line 990
          skip_count = false;                                                   Line 991
          getoptnum (optarg, INT_MIN, &start_line_num,                          Line 992
                     _("'-N NUMBER' invalid starting line number"));            Line 993
          break;                                                                Line 994
        case 'o':                                                               Line 995
          getoptnum (optarg, 0, &chars_per_margin,                              Line 996
                     _("'-o MARGIN' invalid line offset"));                     Line 997
          break;                                                                Line 998
        case 'r':                                                               Line 999
          ignore_failed_opens = true;                                           Line 1000
          break;                                                                Line 1001
        case 's':                                                               Line 1002
          old_options = true;                                                   Line 1003
          old_s = true;                                                         Line 1004
          if (!use_col_separator && optarg)                                     Line 1005
            separator_string (optarg);                                          Line 1006
          break;                                                                Line 1007
        case 'S':                                                               Line 1008
          old_s = false;                                                        Line 1009
          /* Reset an additional input of -s, -S dominates -s */                
          col_sep_string = "";                                                  Line 1011
          col_sep_length = 0;                                                   Line 1012
          use_col_separator = true;                                             Line 1013
          if (optarg)                                                           Line 1014
            separator_string (optarg);                                          Line 1015
          break;                                                                Line 1016
        case 't':                                                               Line 1017
          extremities = false;                                                  Line 1018
          keep_FF = true;                                                       Line 1019
          break;                                                                Line 1020
        case 'T':                                                               Line 1021
          extremities = false;                                                  Line 1022
          keep_FF = false;                                                      Line 1023
          break;                                                                Line 1024
        case 'v':                                                               Line 1025
          use_esc_sequence = true;                                              Line 1026
          break;                                                                Line 1027
        case 'w':                                                               Line 1028
          old_options = true;                                                   Line 1029
          old_w = true;                                                         Line 1030
          {                                                                     
            int tmp_cpl;                                                        Line 1032
            getoptnum (optarg, 1, &tmp_cpl,                                     Line 1033
                       _("'-w PAGE_WIDTH' invalid number of characters"));      Line 1034
            if (! truncate_lines)                                               Line 1035
              chars_per_line = tmp_cpl;                                         Line 1036
          }                                                                     
          break;                                                                Line 1038
        case 'W':                                                               Line 1039
          old_w = false;   /* dominates -w */                                   Line 1040
          truncate_lines = true;                                                Line 1041
          getoptnum (optarg, 1, &chars_per_line,                                Line 1042
                     _("'-W PAGE_WIDTH' invalid number of characters"));        Line 1043
          break;                                                                Line 1044
        case_GETOPT_HELP_CHAR;                                                  Line 1045
        case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);                       Line 1046
        default:                                                                Line 1047
          usage (EXIT_FAILURE);                                                 Line 1048
          break;                                                                Line 1049
        }                                                                       
    }                                                                           
                                                                                
  if (column_count_string)                                                      Line 1053
    {                                                                           
      parse_column_count (column_count_string);                                 Line 1055
      free (column_count_string);                                               Line 1056
    }                                                                           
                                                                                
  if (! date_format)                                                            Line 1059
    date_format = (getenv ("POSIXLY_CORRECT") && !hard_locale (LC_TIME)         Line 1060
                   ? "%b %e %H:%M %Y"                                           Line 1061
                   : "%Y-%m-%d %H:%M");                                         Line 1062
                                                                                
  localtz = tzalloc (getenv ("TZ"));                                            Line 1064
                                                                                
  /* Now we can set a reasonable initial value: */                              
  if (first_page_number == 0)                                                   Line 1067
    first_page_number = 1;                                                      Line 1068
                                                                                
  if (parallel_files && explicit_columns)                                       Line 1070
    die (EXIT_FAILURE, 0,                                                       Line 1071
         _("cannot specify number of columns when printing in parallel"));      Line 1072
                                                                                
  if (parallel_files && print_across_flag)                                      Line 1074
    die (EXIT_FAILURE, 0,                                                       Line 1075
       _("cannot specify both printing across and printing in parallel"));      Line 1076
                                                                                
/* Translate some old short options to new/long options.                        
   To meet downward compatibility with other UNIX pr utilities                  
   and some POSIX specifications. */                                            
                                                                                
  if (old_options)                                                              Line 1082
    {                                                                           
      if (old_w)                                                                Line 1084
        {                                                                       
          if (parallel_files || explicit_columns)                               Line 1086
            {                                                                   
              /* activate -W */                                                 
              truncate_lines = true;                                            Line 1089
              if (old_s)                                                        Line 1090
                /* adapt HP-UX and SunOS: -s = no separator;                    
                   activate -S */                                               
                use_col_separator = true;                                       Line 1093
            }                                                                   
          else                                                                  Line 1095
            /* old -w sets width with columns only                              
               activate -J */                                                   
            join_lines = true;                                                  Line 1098
        }                                                                       
      else if (!use_col_separator)                                              Line 1100
        {                                                                       
          /* No -S option read */                                               
          if (old_s && (parallel_files || explicit_columns))                    Line 1103
            {                                                                   
              if (!truncate_lines)                                              Line 1105
                {                                                               
                  /* old -s (without -w and -W) annuls column alignment,        
                  uses fields, activate -J */                                   
                  join_lines = true;                                            Line 1109
                  if (col_sep_length > 0)                                       Line 1110
                    /* activate -S */                                           
                    use_col_separator = true;                                   Line 1112
                }                                                               
              else                                                              Line 1114
                /* with -W */                                                   
                /* adapt HP-UX and SunOS: -s = no separator;                    
                   activate -S */                                               
                use_col_separator = true;                                       Line 1118
            }                                                                   
        }                                                                       
    }                                                                           
                                                                                
  for (; optind < argc; optind++)                                               Line 1123
    {                                                                           
      file_names[n_files++] = argv[optind];                                     Line 1125
    }                                                                           
                                                                                
  if (n_files == 0)                                                             Line 1128
    {                                                                           
      /* No file arguments specified;  read from standard input.  */            
      print_files (0, NULL);                                                    Line 1131
    }                                                                           
  else                                                                          Line 1133
    {                                                                           
      if (parallel_files)                                                       Line 1135
        print_files (n_files, file_names);                                      Line 1136
      else                                                                      Line 1137
        {                                                                       
          for (unsigned int i = 0; i < n_files; i++)                            Line 1139
            print_files (1, &file_names[i]);                                    Line 1140
        }                                                                       
    }                                                                           
                                                                                
  cleanup ();                                                                   Line 1144
  IF_LINT (free (file_names));                                                  Line 1145
                                                                                
  if (have_read_stdin && fclose (stdin) == EOF)                                 Line 1147...!syscalls auto-comment...
    die (EXIT_FAILURE, errno, _("standard input"));                             Line 1148
  return failed_opens ? EXIT_FAILURE : EXIT_SUCCESS;                            Line 1149
}                                                                               Block 11
                                                                                
/* Parse numeric arguments, ensuring MIN <= number <= INT_MAX.  */              
                                                                                
static void                                                                     Line 1154
getoptnum (const char *n_str, int min, int *num, const char *err)               Line 1155
{                                                                               
  intmax_t tnum = xdectoimax (n_str, min, INT_MAX, "", err, 0);                 Line 1157
  *num = tnum;                                                                  Line 1158
}                                                                               Block 12
                                                                                
/* Parse options of the form -scNNN.                                            
                                                                                
   Example: -nck, where 'n' is the option, c is the optional number             
   separator, and k is the optional width of the field used when printing       
   a number. */                                                                 
                                                                                
static void                                                                     Line 1167
getoptarg (char *arg, char switch_char, char *character, int *number)           Line 1168
{                                                                               
  if (!ISDIGIT (*arg))                                                          Line 1170
    *character = *arg++;                                                        Line 1171
  if (*arg)                                                                     Line 1172
    {                                                                           
      long int tmp_long;                                                        Line 1174
      if (xstrtol (arg, NULL, 10, &tmp_long, "") != LONGINT_OK                  Line 1175
          || tmp_long <= 0 || INT_MAX < tmp_long)                               Line 1176
        {                                                                       
          error (0, INT_MAX < tmp_long ?  EOVERFLOW : errno,                    Line 1178
             _("'-%c' extra characters or invalid number in the argument: %s"), Line 1179
                 switch_char, quote (arg));                                     Line 1180
          usage (EXIT_FAILURE);                                                 Line 1181
        }                                                                       
      *number = tmp_long;                                                       Line 1183
    }                                                                           
}                                                                               Block 13
                                                                                
/* Set parameters related to formatting. */                                     
                                                                                
static void                                                                     Line 1189
init_parameters (int number_of_files)                                           Line 1190
{                                                                               
  int chars_used_by_number = 0;                                                 Line 1192
                                                                                
  lines_per_body = lines_per_page - lines_per_header - lines_per_footer;        Line 1194
  if (lines_per_body <= 0)                                                      Line 1195
    {                                                                           
      extremities = false;                                                      Line 1197
      keep_FF = true;                                                           Line 1198
    }                                                                           
  if (extremities == false)                                                     Line 1200
    lines_per_body = lines_per_page;                                            Line 1201
                                                                                
  if (double_space)                                                             Line 1203
    lines_per_body = lines_per_body / 2;                                        Line 1204
                                                                                
  /* If input is stdin, cannot print parallel files.  BSD dumps core            
     on this. */                                                                
  if (number_of_files == 0)                                                     Line 1208
    parallel_files = false;                                                     Line 1209
                                                                                
  if (parallel_files)                                                           Line 1211
    columns = number_of_files;                                                  Line 1212
                                                                                
  /* One file, multi columns down: -b option is set to get a consistent         
     formulation with "FF set by hand" in input files. */                       
  if (storing_columns)                                                          Line 1216
    balance_columns = true;                                                     Line 1217
                                                                                
  /* Tabification is assumed for multiple columns. */                           
  if (columns > 1)                                                              Line 1220
    {                                                                           
      if (!use_col_separator)                                                   Line 1222
        {                                                                       
          /* Use default separator */                                           
          if (join_lines)                                                       Line 1225
            col_sep_string = line_separator;                                    Line 1226
          else                                                                  Line 1227
            col_sep_string = column_separator;                                  Line 1228
                                                                                
          col_sep_length = 1;                                                   Line 1230
          use_col_separator = true;                                             Line 1231
        }                                                                       
      /* It's rather pointless to define a TAB separator with column            
         alignment */                                                           
      else if (!join_lines && col_sep_length == 1 && *col_sep_string == '\t')   Line 1235
        col_sep_string = column_separator;                                      Line 1236
                                                                                
      truncate_lines = true;                                                    Line 1238
      tabify_output = true;                                                     Line 1239
    }                                                                           
  else                                                                          Line 1241
    storing_columns = false;                                                    Line 1242
                                                                                
  /* -J dominates -w in any case */                                             
  if (join_lines)                                                               Line 1245
    truncate_lines = false;                                                     Line 1246
                                                                                
  if (numbered_lines)                                                           Line 1248
    {                                                                           
      int chars_per_default_tab = 8;                                            Line 1250
                                                                                
      line_count = start_line_num;                                              Line 1252
                                                                                
      /* 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);   */          
                                                                                
      /* Estimate chars_per_text without any margin and keep it constant. */    
      if (number_separator == '\t')                                             Line 1260
        number_width = (chars_per_number                                        Line 1261
                        + TAB_WIDTH (chars_per_default_tab, chars_per_number)); Line 1262
      else                                                                      Line 1263
        number_width = chars_per_number + 1;                                    Line 1264
                                                                                
      /* The number is part of the column width unless we are                   
         printing files in parallel. */                                         
      if (parallel_files)                                                       Line 1268
        chars_used_by_number = number_width;                                    Line 1269
    }                                                                           
                                                                                
  int sep_chars, useful_chars;                                                  Line 1272
  if (INT_MULTIPLY_WRAPV (columns - 1, col_sep_length, &sep_chars))             Line 1273
    sep_chars = INT_MAX;                                                        Line 1274
  if (INT_SUBTRACT_WRAPV (chars_per_line - chars_used_by_number, sep_chars,     Line 1275
                          &useful_chars))                                       Line 1276
    useful_chars = 0;                                                           Line 1277
  chars_per_column = useful_chars / columns;                                    Line 1278
                                                                                
  if (chars_per_column < 1)                                                     Line 1280
    die (EXIT_FAILURE, 0, _("page width too narrow"));                          Line 1281
                                                                                
  if (numbered_lines)                                                           Line 1283
    {                                                                           
      free (number_buff);                                                       Line 1285
      number_buff = xmalloc (MAX (chars_per_number,                             Line 1286
                                  INT_STRLEN_BOUND (line_number)) + 1);         Line 1287
    }                                                                           
                                                                                
  /* Pick the maximum between the tab width and the width of an                 
     escape sequence.                                                           
     The width of an escape sequence (4) isn't the lower limit any longer.      
     We've to use 8 as the lower limit, if we use chars_per_default_tab = 8     
     to expand a tab which is not an input_tab-char. */                         
  free (clump_buff);                                                            Line 1295
  clump_buff = xmalloc (MAX (8, chars_per_input_tab));                          Line 1296
}                                                                               Block 14
                                                                                
/* Open the necessary files,                                                    
   maintaining a COLUMN structure for each column.                              
                                                                                
   With multiple files, each column p has a different p->fp.                    
   With single files, each column p has the same p->fp.                         
   Return false if (number_of_files > 0) and no files can be opened,            
   true otherwise.                                                              
                                                                                
   With each column/file p, p->full_page_printed is initialized,                
   see also open_file.  */                                                      
                                                                                
static bool                                                                     Line 1310
init_fps (int number_of_files, char **av)                                       Line 1311
{                                                                               
  COLUMN *p;                                                                    Line 1313
                                                                                
  total_files = 0;                                                              Line 1315
                                                                                
  free (column_vector);                                                         Line 1317
  column_vector = xnmalloc (columns, sizeof (COLUMN));                          Line 1318
                                                                                
  if (parallel_files)                                                           Line 1320
    {                                                                           
      int files_left = number_of_files;                                         Line 1322
      for (p = column_vector; files_left--; ++p, ++av)                          Line 1323
        {                                                                       
          if (! open_file (*av, p))                                             Line 1325
            {                                                                   
              --p;                                                              Line 1327
              --columns;                                                        Line 1328
            }                                                                   
        }                                                                       
      if (columns == 0)                                                         Line 1331
        return false;                                                           Line 1332
      init_header ("", -1);                                                     Line 1333
    }                                                                           
  else                                                                          Line 1335
    {                                                                           
      p = column_vector;                                                        Line 1337
      if (number_of_files > 0)                                                  Line 1338
        {                                                                       
          if (! open_file (*av, p))                                             Line 1340
            return false;                                                       Line 1341
          init_header (*av, fileno (p->fp));                                    Line 1342
          p->lines_stored = 0;                                                  Line 1343
        }                                                                       
      else                                                                      Line 1345
        {                                                                       
          p->name = _("standard input");                                        Line 1347
          p->fp = stdin;                                                        Line 1348
          have_read_stdin = true;                                               Line 1349
          p->status = OPEN;                                                     Line 1350
          p->full_page_printed = false;                                         Line 1351
          ++total_files;                                                        Line 1352
          init_header ("", -1);                                                 Line 1353
          p->lines_stored = 0;                                                  Line 1354
        }                                                                       
                                                                                
      char const *firstname = p->name;                                          Line 1357
      FILE *firstfp = p->fp;                                                    Line 1358
      int i;                                                                    Line 1359
      for (i = columns - 1, ++p; i; --i, ++p)                                   Line 1360
        {                                                                       
          p->name = firstname;                                                  Line 1362
          p->fp = firstfp;                                                      Line 1363
          p->status = OPEN;                                                     Line 1364
          p->full_page_printed = false;                                         Line 1365
          p->lines_stored = 0;                                                  Line 1366
        }                                                                       
    }                                                                           
  files_ready_to_read = total_files;                                            Line 1369
  return true;                                                                  Line 1370
}                                                                               Block 15
                                                                                
/* Determine print_func and char_func, the functions                            
   used by each column for printing and/or storing.                             
                                                                                
   Determine the horizontal position desired when we begin                      
   printing a column (p->start_position). */                                    
                                                                                
static void                                                                     Line 1379
init_funcs (void)                                                               Line 1380
{                                                                               
  int i, h, h_next;                                                             Line 1382
  COLUMN *p;                                                                    Line 1383
                                                                                
  h = chars_per_margin;                                                         Line 1385
                                                                                
  if (!truncate_lines)                                                          Line 1387
    h_next = ANYWHERE;                                                          Line 1388
  else                                                                          Line 1389
    {                                                                           
      /* When numbering lines of parallel files, we enlarge the                 
         first column to accommodate the number.  Looks better than             
         the Sys V approach. */                                                 
      if (parallel_files && numbered_lines)                                     Line 1394
        h_next = h + chars_per_column + number_width;                           Line 1395
      else                                                                      Line 1396
        h_next = h + chars_per_column;                                          Line 1397
    }                                                                           
                                                                                
  /* Enlarge p->start_position of first column to use the same form of          
     padding_not_printed with all columns. */                                   
  h = h + col_sep_length;                                                       Line 1402
                                                                                
  /* This loop takes care of all but the rightmost column. */                   
                                                                                
  for (p = column_vector, i = 1; i < columns; ++p, ++i)                         Line 1406
    {                                                                           
      if (storing_columns) /* One file, multi columns down. */                  Line 1408
        {                                                                       
          p->char_func = store_char;                                            Line 1410
          p->print_func = print_stored;                                         Line 1411
        }                                                                       
      else                                                                      Line 1413
        /* One file, multi columns across; or parallel files.  */               
        {                                                                       
          p->char_func = print_char;                                            Line 1416
          p->print_func = read_line;                                            Line 1417
        }                                                                       
                                                                                
      /* Number only the first column when printing files in                    
         parallel. */                                                           
      p->numbered = numbered_lines && (!parallel_files || i == 1);              Line 1422
      p->start_position = h;                                                    Line 1423
                                                                                
      /* If we don't truncate lines, all start_positions are                    
         ANYWHERE, except the first column's start_position when                
         using a margin. */                                                     
                                                                                
      if (!truncate_lines)                                                      Line 1429
        {                                                                       
          h = ANYWHERE;                                                         Line 1431
          h_next = ANYWHERE;                                                    Line 1432
        }                                                                       
      else                                                                      Line 1434
        {                                                                       
          h = h_next + col_sep_length;                                          Line 1436
          h_next = h + chars_per_column;                                        Line 1437
        }                                                                       
    }                                                                           
                                                                                
  /* The rightmost column.                                                      
                                                                                
     Doesn't need to be stored unless we intend to balance                      
     columns on the last page. */                                               
  if (storing_columns && balance_columns)                                       Line 1445
    {                                                                           
      p->char_func = store_char;                                                Line 1447
      p->print_func = print_stored;                                             Line 1448
    }                                                                           
  else                                                                          Line 1450
    {                                                                           
      p->char_func = print_char;                                                Line 1452
      p->print_func = read_line;                                                Line 1453
    }                                                                           
                                                                                
  p->numbered = numbered_lines && (!parallel_files || i == 1);                  Line 1456
  p->start_position = h;                                                        Line 1457
}                                                                               Block 16
                                                                                
/* Open a file.  Return true if successful.                                     
                                                                                
   With each file p, p->full_page_printed is initialized,                       
   see also init_fps. */                                                        
                                                                                
static bool                                                                     Line 1465
open_file (char *name, COLUMN *p)                                               Line 1466
{                                                                               
  if (STREQ (name, "-"))                                                        Line 1468
    {                                                                           
      p->name = _("standard input");                                            Line 1470
      p->fp = stdin;                                                            Line 1471
      have_read_stdin = true;                                                   Line 1472
    }                                                                           
  else                                                                          Line 1474
    {                                                                           
      p->name = name;                                                           Line 1476
      p->fp = fopen (name, "r");                                                Line 1477...!syscalls auto-comment...
    }                                                                           
  if (p->fp == NULL)                                                            Line 1479
    {                                                                           
      failed_opens = true;                                                      Line 1481
      if (!ignore_failed_opens)                                                 Line 1482
        error (0, errno, "%s", quotef (name));                                  Line 1483
      return false;                                                             Line 1484
    }                                                                           
  fadvise (p->fp, FADVISE_SEQUENTIAL);                                          Line 1486...!syscalls auto-comment...
  p->status = OPEN;                                                             Line 1487
  p->full_page_printed = false;                                                 Line 1488
  ++total_files;                                                                Line 1489
  return true;                                                                  Line 1490
}                                                                               Block 17
                                                                                
/* Close the file in P.                                                         
                                                                                
   If we aren't dealing with multiple files in parallel, we change              
   the status of all columns in the column list to reflect the close. */        
                                                                                
static void                                                                     Line 1498
close_file (COLUMN *p)                                                          Line 1499
{                                                                               
  COLUMN *q;                                                                    Line 1501
  int i;                                                                        Line 1502
                                                                                
  if (p->status == CLOSED)                                                      Line 1504
    return;                                                                     Line 1505
  if (ferror (p->fp))                                                           Line 1506
    die (EXIT_FAILURE, errno, "%s", quotef (p->name));                          Line 1507
  if (fileno (p->fp) != STDIN_FILENO && fclose (p->fp) != 0)                    Line 1508...!syscalls auto-comment...
    die (EXIT_FAILURE, errno, "%s", quotef (p->name));                          Line 1509
                                                                                
  if (!parallel_files)                                                          Line 1511
    {                                                                           
      for (q = column_vector, i = columns; i; ++q, --i)                         Line 1513
        {                                                                       
          q->status = CLOSED;                                                   Line 1515
          if (q->lines_stored == 0)                                             Line 1516
            {                                                                   
              q->lines_to_print = 0;                                            Line 1518
            }                                                                   
        }                                                                       
    }                                                                           
  else                                                                          Line 1522
    {                                                                           
      p->status = CLOSED;                                                       Line 1524
      p->lines_to_print = 0;                                                    Line 1525
    }                                                                           
                                                                                
  --files_ready_to_read;                                                        Line 1528
}                                                                               Block 18
                                                                                
/* Put a file on hold until we start a new page,                                
   since we've hit a form feed.                                                 
                                                                                
   If we aren't dealing with parallel files, we must change the                 
   status of all columns in the column list. */                                 
                                                                                
static void                                                                     Line 1537
hold_file (COLUMN *p)                                                           Line 1538
{                                                                               
  COLUMN *q;                                                                    Line 1540
  int i;                                                                        Line 1541
                                                                                
  if (!parallel_files)                                                          Line 1543
    for (q = column_vector, i = columns; i; ++q, --i)                           Line 1544
      {                                                                         
        if (storing_columns)                                                    Line 1546
          q->status = FF_FOUND;                                                 Line 1547
        else                                                                    Line 1548
          q->status = ON_HOLD;                                                  Line 1549
      }                                                                         
  else                                                                          Line 1551
    p->status = ON_HOLD;                                                        Line 1552
                                                                                
  p->lines_to_print = 0;                                                        Line 1554
  --files_ready_to_read;                                                        Line 1555
}                                                                               Block 19
                                                                                
/* Undo hold_file -- go through the column list and change any                  
   ON_HOLD columns to OPEN.  Used at the end of each page. */                   
                                                                                
static void                                                                     Line 1561
reset_status (void)                                                             Line 1562
{                                                                               
  int i = columns;                                                              Line 1564
  COLUMN *p;                                                                    Line 1565
                                                                                
  for (p = column_vector; i; --i, ++p)                                          Line 1567
    if (p->status == ON_HOLD)                                                   Line 1568
      {                                                                         
        p->status = OPEN;                                                       Line 1570
        files_ready_to_read++;                                                  Line 1571
      }                                                                         
                                                                                
  if (storing_columns)                                                          Line 1574
    {                                                                           
      if (column_vector->status == CLOSED)                                      Line 1576
        /* We use the info to output an error message in  skip_to_page. */      
        files_ready_to_read = 0;                                                Line 1578
      else                                                                      Line 1579
        files_ready_to_read = 1;                                                Line 1580
    }                                                                           
}                                                                               Block 20
                                                                                
/* Print a single file, or multiple files in parallel.                          
                                                                                
   Set up the list of columns, opening the necessary files.                     
   Allocate space for storing columns, if necessary.                            
   Skip to first_page_number, if user has asked to skip leading pages.          
   Determine which functions are appropriate to store/print lines               
   in each column.                                                              
   Print the file(s). */                                                        
                                                                                
static void                                                                     Line 1593
print_files (int number_of_files, char **av)                                    Line 1594
{                                                                               
  init_parameters (number_of_files);                                            Line 1596
  if (! init_fps (number_of_files, av))                                         Line 1597
    return;                                                                     Line 1598
  if (storing_columns)                                                          Line 1599
    init_store_cols ();                                                         Line 1600
                                                                                
  if (first_page_number > 1)                                                    Line 1602
    {                                                                           
      if (!skip_to_page (first_page_number))                                    Line 1604
        return;                                                                 Line 1605
      else                                                                      Line 1606
        page_number = first_page_number;                                        Line 1607
    }                                                                           
  else                                                                          Line 1609
    page_number = 1;                                                            Line 1610
                                                                                
  init_funcs ();                                                                Line 1612
                                                                                
  line_number = line_count;                                                     Line 1614
  while (print_page ())                                                         Line 1615
    ;                                                                           
}                                                                               Block 21
                                                                                
/* Initialize header information.                                               
   If DESC is non-negative, it is a file descriptor open to                     
   FILENAME for reading.  */                                                    
                                                                                
static void                                                                     Line 1623
init_header (char const *filename, int desc)                                    Line 1624
{                                                                               
  char *buf = NULL;                                                             Line 1626
  struct stat st;                                                               Line 1627
  struct timespec t;                                                            Line 1628
  int ns;                                                                       Line 1629
  struct tm tm;                                                                 Line 1630
                                                                                
  /* If parallel files or standard input, use current date. */                  
  if (STREQ (filename, "-"))                                                    Line 1633
    desc = -1;                                                                  Line 1634
  if (0 <= desc && fstat (desc, &st) == 0)                                      Line 1635...!syscalls auto-comment......!syscalls auto-comment...
    t = get_stat_mtime (&st);                                                   Line 1636
  else                                                                          Line 1637
    {                                                                           
      static struct timespec timespec;                                          Line 1639
      if (! timespec.tv_sec)                                                    Line 1640
        gettime (×pec);                                                    Line 1641
      t = timespec;                                                             Line 1642
    }                                                                           
                                                                                
  ns = t.tv_nsec;                                                               Line 1645
  if (localtime_rz (localtz, &t.tv_sec, &tm))                                   Line 1646
    {                                                                           
      size_t bufsize                                                            Line 1648
        = nstrftime (NULL, SIZE_MAX, date_format, &tm, localtz, ns) + 1;        Line 1649
      buf = xmalloc (bufsize);                                                  Line 1650
      nstrftime (buf, bufsize, date_format, &tm, localtz, ns);                  Line 1651
    }                                                                           
  else                                                                          Line 1653
    {                                                                           
      char secbuf[INT_BUFSIZE_BOUND (intmax_t)];                                Line 1655
      buf = xmalloc (sizeof secbuf + MAX (10, INT_BUFSIZE_BOUND (int)));        Line 1656
      sprintf (buf, "%s.%09d", timetostr (t.tv_sec, secbuf), ns);               Line 1657
    }                                                                           
                                                                                
  free (date_text);                                                             Line 1660
  date_text = buf;                                                              Line 1661
  file_text = custom_header ? custom_header : desc < 0 ? "" : filename;         Line 1662
  header_width_available = (chars_per_line                                      Line 1663
                            - mbswidth (date_text, 0)                           Line 1664
                            - mbswidth (file_text, 0));                         Line 1665
}                                                                               Block 22
                                                                                
/* Set things up for printing a page                                            
                                                                                
   Scan through the columns ...                                                 
   Determine which are ready to print                                           
   (i.e., which have lines stored or open files)                                
   Set p->lines_to_print appropriately                                          
   (to p->lines_stored if we're storing, or lines_per_body                      
   if we're reading straight from the file)                                     
   Keep track of this total so we know when to stop printing */                 
                                                                                
static void                                                                     Line 1678
init_page (void)                                                                Line 1679
{                                                                               
  int j;                                                                        Line 1681
  COLUMN *p;                                                                    Line 1682
                                                                                
  if (storing_columns)                                                          Line 1684
    {                                                                           
      store_columns ();                                                         Line 1686
      for (j = columns - 1, p = column_vector; j; --j, ++p)                     Line 1687
        {                                                                       
          p->lines_to_print = p->lines_stored;                                  Line 1689
        }                                                                       
                                                                                
      /* Last column. */                                                        
      if (balance_columns)                                                      Line 1693
        {                                                                       
          p->lines_to_print = p->lines_stored;                                  Line 1695
        }                                                                       
      /* Since we're not balancing columns, we don't need to store              
         the rightmost column.   Read it straight from the file. */             
      else                                                                      Line 1699
        {                                                                       
          if (p->status == OPEN)                                                Line 1701
            {                                                                   
              p->lines_to_print = lines_per_body;                               Line 1703
            }                                                                   
          else                                                                  Line 1705
            p->lines_to_print = 0;                                              Line 1706
        }                                                                       
    }                                                                           
  else                                                                          Line 1709
    for (j = columns, p = column_vector; j; --j, ++p)                           Line 1710
      if (p->status == OPEN)                                                    Line 1711
        {                                                                       
          p->lines_to_print = lines_per_body;                                   Line 1713
        }                                                                       
      else                                                                      Line 1715
        p->lines_to_print = 0;                                                  Line 1716
}                                                                               Block 23
                                                                                
/* Align empty columns and print separators.                                    
   Empty columns will be formed by files with status ON_HOLD or CLOSED          
   when printing multiple files in parallel. */                                 
                                                                                
static void                                                                     Line 1723
align_column (COLUMN *p)                                                        Line 1724
{                                                                               
  padding_not_printed = p->start_position;                                      Line 1726
  if (col_sep_length < padding_not_printed)                                     Line 1727
    {                                                                           
      pad_across_to (padding_not_printed - col_sep_length);                     Line 1729
      padding_not_printed = ANYWHERE;                                           Line 1730
    }                                                                           
                                                                                
  if (use_col_separator)                                                        Line 1733
    print_sep_string ();                                                        Line 1734
                                                                                
  if (p->numbered)                                                              Line 1736
    add_line_number (p);                                                        Line 1737
}                                                                               Block 24
                                                                                
/* Print one page.                                                              
                                                                                
   As long as there are lines left on the page and columns ready to print,      
   Scan across the column list                                                  
   if the column has stored lines or the file is open                           
   pad to the appropriate spot                                                  
   print the column                                                             
   pad the remainder of the page with \n or \f as requested                     
   reset the status of all files -- any files which where on hold because       
   of formfeeds are now put back into the lineup. */                            
                                                                                
static bool                                                                     Line 1751
print_page (void)                                                               Line 1752
{                                                                               
  int j;                                                                        Line 1754
  int lines_left_on_page;                                                       Line 1755
  COLUMN *p;                                                                    Line 1756
                                                                                
  /* Used as an accumulator (with | operator) of successive values of           
     pad_vertically.  The trick is to set pad_vertically                        
     to false before each run through the inner loop, then after that           
     loop, it tells us whether a line was actually printed (whether a           
     newline needs to be output -- or two for double spacing).  But those       
     values have to be accumulated (in pv) so we can invoke pad_down            
     properly after the outer loop completes. */                                
  bool pv;                                                                      Line 1765
                                                                                
  init_page ();                                                                 Line 1767
                                                                                
  if (cols_ready_to_print () == 0)                                              Line 1769
    return false;                                                               Line 1770
                                                                                
  if (extremities)                                                              Line 1772
    print_a_header = true;                                                      Line 1773
                                                                                
  /* Don't pad unless we know a page was printed. */                            
  pad_vertically = false;                                                       Line 1776
  pv = false;                                                                   Line 1777
                                                                                
  lines_left_on_page = lines_per_body;                                          Line 1779
  if (double_space)                                                             Line 1780
    lines_left_on_page *= 2;                                                    Line 1781
                                                                                
  while (lines_left_on_page > 0 && cols_ready_to_print () > 0)                  Line 1783
    {                                                                           
      output_position = 0;                                                      Line 1785
      spaces_not_printed = 0;                                                   Line 1786
      separators_not_printed = 0;                                               Line 1787
      pad_vertically = false;                                                   Line 1788
      align_empty_cols = false;                                                 Line 1789
      empty_line = true;                                                        Line 1790
                                                                                
      for (j = 1, p = column_vector; j <= columns; ++j, ++p)                    Line 1792
        {                                                                       
          input_position = 0;                                                   Line 1794
          if (p->lines_to_print > 0 || p->status == FF_FOUND)                   Line 1795
            {                                                                   
              FF_only = false;                                                  Line 1797
              padding_not_printed = p->start_position;                          Line 1798
              if (!(p->print_func) (p))                                         Line 1799
                read_rest_of_line (p);                                          Line 1800
              pv |= pad_vertically;                                             Line 1801
                                                                                
              --p->lines_to_print;                                              Line 1803
              if (p->lines_to_print <= 0)                                       Line 1804
                {                                                               
                  if (cols_ready_to_print () == 0)                              Line 1806
                    break;                                                      Line 1807
                }                                                               
                                                                                
              /* File p changed its status to ON_HOLD or CLOSED */              
              if (parallel_files && p->status != OPEN)                          Line 1811
                {                                                               
                  if (empty_line)                                               Line 1813
                    align_empty_cols = true;                                    Line 1814
                  else if (p->status == CLOSED                                  Line 1815
                           || (p->status == ON_HOLD && FF_only))                Line 1816
                    align_column (p);                                           Line 1817
                }                                                               
            }                                                                   
          else if (parallel_files)                                              Line 1820
            {                                                                   
              /* File status ON_HOLD or CLOSED */                               
              if (empty_line)                                                   Line 1823
                align_empty_cols = true;                                        Line 1824
              else                                                              Line 1825
                align_column (p);                                               Line 1826
            }                                                                   
                                                                                
          /* We need it also with an empty column */                            
          if (use_col_separator)                                                Line 1830
            ++separators_not_printed;                                           Line 1831
        }                                                                       
                                                                                
      if (pad_vertically)                                                       Line 1834
        {                                                                       
          putchar ('\n');                                                       Line 1836
          --lines_left_on_page;                                                 Line 1837
        }                                                                       
                                                                                
      if (cols_ready_to_print () == 0 && !extremities)                          Line 1840
        break;                                                                  Line 1841
                                                                                
      if (double_space && pv)                                                   Line 1843
        {                                                                       
          putchar ('\n');                                                       Line 1845
          --lines_left_on_page;                                                 Line 1846
        }                                                                       
    }                                                                           
                                                                                
  if (lines_left_on_page == 0)                                                  Line 1850
    for (j = 1, p = column_vector; j <= columns; ++j, ++p)                      Line 1851
      if (p->status == OPEN)                                                    Line 1852
        p->full_page_printed = true;                                            Line 1853
                                                                                
  pad_vertically = pv;                                                          Line 1855
                                                                                
  if (pad_vertically && extremities)                                            Line 1857
    pad_down (lines_left_on_page + lines_per_footer);                           Line 1858
  else if (keep_FF && print_a_FF)                                               Line 1859
    {                                                                           
      putchar ('\f');                                                           Line 1861
      print_a_FF = false;                                                       Line 1862
    }                                                                           
                                                                                
  if (last_page_number < ++page_number)                                         Line 1865
    return false;  /* Stop printing with LAST_PAGE */                           Line 1866
                                                                                
  reset_status ();  /* Change ON_HOLD to OPEN. */                               Line 1868
                                                                                
  return true;   /* More pages to go. */                                        Line 1870
}                                                                               Block 25
                                                                                
/* Allocate space for storing columns.                                          
                                                                                
   This is necessary when printing multiple columns from a single file.         
   Lines are stored consecutively in buff, separated by '\0'.                   
                                                                                
   The following doesn't apply any longer - any tuning possible?                
   (We can't use a fixed offset since with the '-s' flag lines aren't           
   truncated.)                                                                  
                                                                                
   We maintain a list (line_vector) of pointers to the beginnings               
   of lines in buff.  We allocate one more than the number of lines             
   because the last entry tells us the index of the last character,             
   which we need to know in order to print the last line in buff. */            
                                                                                
static void                                                                     Line 1887
init_store_cols (void)                                                          Line 1888
{                                                                               
  int total_lines, total_lines_1, chars_per_column_1, chars_if_truncate;        Line 1890
  if (INT_MULTIPLY_WRAPV (lines_per_body, columns, &total_lines)                Line 1891
      || INT_ADD_WRAPV (total_lines, 1, &total_lines_1)                         Line 1892
      || INT_ADD_WRAPV (chars_per_column, 1, &chars_per_column_1)               Line 1893
      || INT_MULTIPLY_WRAPV (total_lines, chars_per_column_1,                   Line 1894
                             &chars_if_truncate))                               Line 1895
    integer_overflow ();                                                        Line 1896
                                                                                
  free (line_vector);                                                           Line 1898
  /* FIXME: here's where it was allocated.  */                                  
  line_vector = xnmalloc (total_lines_1, sizeof *line_vector);                  Line 1900
                                                                                
  free (end_vector);                                                            Line 1902
  end_vector = xnmalloc (total_lines, sizeof *end_vector);                      Line 1903
                                                                                
  free (buff);                                                                  Line 1905
  buff = xnmalloc (chars_if_truncate, use_col_separator + 1);                   Line 1906
  buff_allocated = chars_if_truncate;  /* Tune this. */                         Line 1907
  buff_allocated *= use_col_separator + 1;                                      Line 1908
}                                                                               Block 26
                                                                                
/* Store all but the rightmost column.                                          
   (Used when printing a single file in multiple downward columns)              
                                                                                
   For each column                                                              
   set p->current_line to be the index in line_vector of the                    
   first line in the column                                                     
   For each line in the column                                                  
   store the line in buff                                                       
   add to line_vector the index of the line's first char                        
   buff_start is the index in buff of the first character in the                
   current line. */                                                             
                                                                                
static void                                                                     Line 1923
store_columns (void)                                                            Line 1924
{                                                                               
  int i, j;                                                                     Line 1926
  unsigned int line = 0;                                                        Line 1927
  unsigned int buff_start;                                                      Line 1928
  int last_col;  /* The rightmost column which will be saved in buff */         Line 1929
  COLUMN *p;                                                                    Line 1930
                                                                                
  buff_current = 0;                                                             Line 1932
  buff_start = 0;                                                               Line 1933
                                                                                
  if (balance_columns)                                                          Line 1935
    last_col = columns;                                                         Line 1936
  else                                                                          Line 1937
    last_col = columns - 1;                                                     Line 1938
                                                                                
  for (i = 1, p = column_vector; i <= last_col; ++i, ++p)                       Line 1940
    p->lines_stored = 0;                                                        Line 1941
                                                                                
  for (i = 1, p = column_vector; i <= last_col && files_ready_to_read;          Line 1943
       ++i, ++p)                                                                Line 1944
    {                                                                           
      p->current_line = line;                                                   Line 1946
      for (j = lines_per_body; j && files_ready_to_read; --j)                   Line 1947
                                                                                
        if (p->status == OPEN) /* Redundant.  Clean up. */                      Line 1949
          {                                                                     
            input_position = 0;                                                 Line 1951
                                                                                
            if (!read_line (p))                                                 Line 1953
              read_rest_of_line (p);                                            Line 1954
                                                                                
            if (p->status == OPEN                                               Line 1956
                || buff_start != buff_current)                                  Line 1957
              {                                                                 
                ++p->lines_stored;                                              Line 1959
                line_vector[line] = buff_start;                                 Line 1960
                end_vector[line++] = input_position;                            Line 1961
                buff_start = buff_current;                                      Line 1962
              }                                                                 
          }                                                                     
    }                                                                           
                                                                                
  /* Keep track of the location of the last char in buff. */                    
  line_vector[line] = buff_start;                                               Line 1968
                                                                                
  if (balance_columns)                                                          Line 1970
    balance (line);                                                             Line 1971
}                                                                               Block 27
                                                                                
static void                                                                     Line 1974
balance (int total_stored)                                                      Line 1975
{                                                                               
  COLUMN *p;                                                                    Line 1977
  int i, lines;                                                                 Line 1978
  int first_line = 0;                                                           Line 1979
                                                                                
  for (i = 1, p = column_vector; i <= columns; ++i, ++p)                        Line 1981
    {                                                                           
      lines = total_stored / columns;                                           Line 1983
      if (i <= total_stored % columns)                                          Line 1984
        ++lines;                                                                Line 1985
                                                                                
      p->lines_stored = lines;                                                  Line 1987
      p->current_line = first_line;                                             Line 1988
                                                                                
      first_line += lines;                                                      Line 1990
    }                                                                           
}                                                                               Block 28
                                                                                
/* Store a character in the buffer. */                                          
                                                                                
static void                                                                     Line 1996
store_char (char c)                                                             Line 1997
{                                                                               
  if (buff_current >= buff_allocated)                                           Line 1999
    {                                                                           
      /* May be too generous. */                                                
      buff = X2REALLOC (buff, &buff_allocated);                                 Line 2002
    }                                                                           
  buff[buff_current++] = c;                                                     Line 2004
}                                                                               Block 29
                                                                                
static void                                                                     Line 2007
add_line_number (COLUMN *p)                                                     Line 2008
{                                                                               
  int i;                                                                        Line 2010
  char *s;                                                                      Line 2011
  int num_width;                                                                Line 2012
                                                                                
  /* Cutting off the higher-order digits is more informative than               
     lower-order cut off. */                                                    
  num_width = sprintf (number_buff, "%*d", chars_per_number, line_number);      Line 2016
  line_number++;                                                                Line 2017
  s = number_buff + (num_width - chars_per_number);                             Line 2018
  for (i = chars_per_number; i > 0; i--)                                        Line 2019
    (p->char_func) (*s++);                                                      Line 2020
                                                                                
  if (columns > 1)                                                              Line 2022
    {                                                                           
      /* 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. */                         
      if (number_separator == '\t')                                             Line 2027
        {                                                                       
          i = number_width - chars_per_number;                                  Line 2029
          while (i-- > 0)                                                       Line 2030
            (p->char_func) (' ');                                               Line 2031
        }                                                                       
      else                                                                      Line 2033
        (p->char_func) (number_separator);                                      Line 2034
    }                                                                           
  else                                                                          Line 2036
    /* To comply with POSIX, we avoid any expansion of default TAB              
       separator with a single column output. No column_width requirement       
       has to be considered. */                                                 
    {                                                                           
      (p->char_func) (number_separator);                                        Line 2041
      if (number_separator == '\t')                                             Line 2042
        output_position = POS_AFTER_TAB (chars_per_output_tab,                  Line 2043
                          output_position);                                     Line 2044
    }                                                                           
                                                                                
  if (truncate_lines && !parallel_files)                                        Line 2047
    input_position += number_width;                                             Line 2048
}                                                                               Block 30
                                                                                
/* Print (or store) padding until the current horizontal position               
   is position. */                                                              
                                                                                
static void                                                                     Line 2054
pad_across_to (int position)                                                    Line 2055
{                                                                               
  int h = output_position;                                                      Line 2057
                                                                                
  if (tabify_output)                                                            Line 2059
    spaces_not_printed = position - output_position;                            Line 2060
  else                                                                          Line 2061
    {                                                                           
      while (++h <= position)                                                   Line 2063
        putchar (' ');                                                          Line 2064
      output_position = position;                                               Line 2065
    }                                                                           
}                                                                               Block 31
                                                                                
/* Pad to the bottom of the page.                                               
                                                                                
   If the user has requested a formfeed, use one.                               
   Otherwise, use newlines. */                                                  
                                                                                
static void                                                                     Line 2074
pad_down (unsigned int lines)                                                   Line 2075
{                                                                               
  if (use_form_feed)                                                            Line 2077
    putchar ('\f');                                                             Line 2078
  else                                                                          Line 2079
    for (unsigned int i = lines; i; --i)                                        Line 2080
      putchar ('\n');                                                           Line 2081
}                                                                               Block 32
                                                                                
/* Read the rest of the line.                                                   
                                                                                
   Read from the current column's file until an end of line is                  
   hit.  Used when we've truncated a line and we no longer need                 
   to print or store its characters. */                                         
                                                                                
static void                                                                     Line 2090
read_rest_of_line (COLUMN *p)                                                   Line 2091
{                                                                               
  int c;                                                                        Line 2093
  FILE *f = p->fp;                                                              Line 2094
                                                                                
  while ((c = getc (f)) != '\n')                                                Line 2096
    {                                                                           
      if (c == '\f')                                                            Line 2098
        {                                                                       
          if ((c = getc (f)) != '\n')                                           Line 2100
            ungetc (c, f);                                                      Line 2101
          if (keep_FF)                                                          Line 2102
            print_a_FF = true;                                                  Line 2103
          hold_file (p);                                                        Line 2104
          break;                                                                Line 2105
        }                                                                       
      else if (c == EOF)                                                        Line 2107
        {                                                                       
          close_file (p);                                                       Line 2109
          break;                                                                Line 2110
        }                                                                       
    }                                                                           
}                                                                               Block 33
                                                                                
/* Read a line with skip_to_page.                                               
                                                                                
   Read from the current column's file until an end of line is                  
   hit.  Used when we read full lines to skip pages.                            
   With skip_to_page we have to check for FF-coincidence which is done          
   in function read_line otherwise.                                             
   Count lines of skipped pages to find the line number of 1st page             
   printed relative to 1st line of input file (start_line_num). */              
                                                                                
static void                                                                     Line 2124
skip_read (COLUMN *p, int column_number)                                        Line 2125...!syscalls auto-comment...
{                                                                               
  int c;                                                                        Line 2127
  FILE *f = p->fp;                                                              Line 2128
  int i;                                                                        Line 2129
  bool single_ff = false;                                                       Line 2130
  COLUMN *q;                                                                    Line 2131
                                                                                
  /* Read 1st character in a line or any character succeeding a FF */           
  if ((c = getc (f)) == '\f' && p->full_page_printed)                           Line 2134
    /* A FF-coincidence with a previous full_page_printed.                      
       To avoid an additional empty page, eliminate the FF */                   
    if ((c = getc (f)) == '\n')                                                 Line 2137
      c = getc (f);                                                             Line 2138
                                                                                
  p->full_page_printed = false;                                                 Line 2140
                                                                                
  /* 1st character a FF means a single FF without any printable                 
     characters. Don't count it as a line with -n option. */                    
  if (c == '\f')                                                                Line 2144
    single_ff = true;                                                           Line 2145
                                                                                
  /* Preparing for a FF-coincidence: Maybe we finish that page                  
     without a FF found */                                                      
  if (last_line)                                                                Line 2149
    p->full_page_printed = true;                                                Line 2150
                                                                                
  while (c != '\n')                                                             Line 2152
    {                                                                           
      if (c == '\f')                                                            Line 2154
        {                                                                       
          /* No FF-coincidence possible,                                        
             no catching up of a FF-coincidence with next page */               
          if (last_line)                                                        Line 2158
            {                                                                   
              if (!parallel_files)                                              Line 2160
                for (q = column_vector, i = columns; i; ++q, --i)               Line 2161
                  q->full_page_printed = false;                                 Line 2162
              else                                                              Line 2163
                p->full_page_printed = false;                                   Line 2164
            }                                                                   
                                                                                
          if ((c = getc (f)) != '\n')                                           Line 2167
            ungetc (c, f);                                                      Line 2168
          hold_file (p);                                                        Line 2169
          break;                                                                Line 2170
        }                                                                       
      else if (c == EOF)                                                        Line 2172
        {                                                                       
          close_file (p);                                                       Line 2174
          break;                                                                Line 2175
        }                                                                       
      c = getc (f);                                                             Line 2177
    }                                                                           
                                                                                
  if (skip_count)                                                               Line 2180
    if ((!parallel_files || column_number == 1) && !single_ff)                  Line 2181
      ++line_count;                                                             Line 2182
}                                                                               Block 34
                                                                                
/* If we're tabifying output,                                                   
                                                                                
   When print_char encounters white space it keeps track                        
   of our desired horizontal position and delays printing                       
   until this function is called. */                                            
                                                                                
static void                                                                     Line 2191
print_white_space (void)                                                        Line 2192
{                                                                               
  int h_new;                                                                    Line 2194
  int h_old = output_position;                                                  Line 2195
  int goal = h_old + spaces_not_printed;                                        Line 2196
                                                                                
  while (goal - h_old > 1                                                       Line 2198
         && (h_new = POS_AFTER_TAB (chars_per_output_tab, h_old)) <= goal)      Line 2199
    {                                                                           
      putchar (output_tab_char);                                                Line 2201
      h_old = h_new;                                                            Line 2202
    }                                                                           
  while (++h_old <= goal)                                                       Line 2204
    putchar (' ');                                                              Line 2205
                                                                                
  output_position = goal;                                                       Line 2207
  spaces_not_printed = 0;                                                       Line 2208
}                                                                               Block 35
                                                                                
/* Print column separators.                                                     
                                                                                
   We keep a count until we know that we'll be printing a line,                 
   then print_sep_string() is called. */                                        
                                                                                
static void                                                                     Line 2216
print_sep_string (void)                                                         Line 2217
{                                                                               
  char const *s = col_sep_string;                                               Line 2219
  int l = col_sep_length;                                                       Line 2220
                                                                                
  if (separators_not_printed <= 0)                                              Line 2222
    {                                                                           
      /* We'll be starting a line with chars_per_margin, anything else? */      
      if (spaces_not_printed > 0)                                               Line 2225
        print_white_space ();                                                   Line 2226
    }                                                                           
  else                                                                          Line 2228
    {                                                                           
      for (; separators_not_printed > 0; --separators_not_printed)              Line 2230
        {                                                                       
          while (l-- > 0)                                                       Line 2232
            {                                                                   
              /* 3 types of sep_strings: spaces only, spaces and chars,         
              chars only */                                                     
              if (*s == ' ')                                                    Line 2236
                {                                                               
                  /* We're tabifying output; consecutive spaces in              
                  sep_string may have to be converted to tabs */                
                  s++;                                                          Line 2240
                  ++spaces_not_printed;                                         Line 2241
                }                                                               
              else                                                              Line 2243
                {                                                               
                  if (spaces_not_printed > 0)                                   Line 2245
                    print_white_space ();                                       Line 2246
                  putchar (*s++);                                               Line 2247
                  ++output_position;                                            Line 2248
                }                                                               
            }                                                                   
          /* sep_string ends with some spaces */                                
          if (spaces_not_printed > 0)                                           Line 2252
            print_white_space ();                                               Line 2253
        }                                                                       
    }                                                                           
}                                                                               Block 36
                                                                                
/* Print (or store, depending on p->char_func) a clump of N                     
   characters. */                                                               
                                                                                
static void                                                                     Line 2261
print_clump (COLUMN *p, int n, char *clump)                                     Line 2262
{                                                                               
  while (n--)                                                                   Line 2264
    (p->char_func) (*clump++);                                                  Line 2265
}                                                                               Block 37
                                                                                
/* Print a character.                                                           
                                                                                
   Update the following comment: process-char hasn't been used any              
   longer.                                                                      
   If we're tabifying, all tabs have been converted to spaces by                
   process_char().  Keep a count of consecutive spaces, and when                
   a nonspace is encountered, call print_white_space() to print the             
   required number of tabs and spaces. */                                       
                                                                                
static void                                                                     Line 2277
print_char (char c)                                                             Line 2278
{                                                                               
  if (tabify_output)                                                            Line 2280
    {                                                                           
      if (c == ' ')                                                             Line 2282
        {                                                                       
          ++spaces_not_printed;                                                 Line 2284
          return;                                                               Line 2285
        }                                                                       
      else if (spaces_not_printed > 0)                                          Line 2287
        print_white_space ();                                                   Line 2288
                                                                                
      /* Nonprintables are assumed to have width 0, except '\b'. */             
      if (! isprint (to_uchar (c)))                                             Line 2291
        {                                                                       
          if (c == '\b')                                                        Line 2293
            --output_position;                                                  Line 2294
        }                                                                       
      else                                                                      Line 2296
        ++output_position;                                                      Line 2297
    }                                                                           
  putchar (c);                                                                  Line 2299
}                                                                               Block 38
                                                                                
/* Skip to page PAGE before printing.                                           
   PAGE may be larger than total number of pages. */                            
                                                                                
static bool                                                                     Line 2305
skip_to_page (uintmax_t page)                                                   Line 2306
{                                                                               
  for (uintmax_t n = 1; n < page; ++n)                                          Line 2308
    {                                                                           
      COLUMN *p;                                                                Line 2310
      int j;                                                                    Line 2311
                                                                                
      for (int i = 1; i < lines_per_body; ++i)                                  Line 2313
        {                                                                       
          for (j = 1, p = column_vector; j <= columns; ++j, ++p)                Line 2315
            if (p->status == OPEN)                                              Line 2316
              skip_read (p, j);                                                 Line 2317...!syscalls auto-comment...
        }                                                                       
      last_line = true;                                                         Line 2319
      for (j = 1, p = column_vector; j <= columns; ++j, ++p)                    Line 2320
        if (p->status == OPEN)                                                  Line 2321
          skip_read (p, j);                                                     Line 2322...!syscalls auto-comment...
                                                                                
      if (storing_columns) /* change FF_FOUND to ON_HOLD */                     Line 2324
        for (j = 1, p = column_vector; j <= columns; ++j, ++p)                  Line 2325
          if (p->status != CLOSED)                                              Line 2326
            p->status = ON_HOLD;                                                Line 2327
                                                                                
      reset_status ();                                                          Line 2329
      last_line = false;                                                        Line 2330
                                                                                
      if (files_ready_to_read < 1)                                              Line 2332
        {                                                                       
          /* It's very helpful, normally the total number of pages is           
             not known in advance.  */                                          
          error (0, 0,                                                          Line 2336
                 _("starting page number %"PRIuMAX                              Line 2337
                   " exceeds page count %"PRIuMAX),                             Line 2338
                 page, n);                                                      Line 2339
          break;                                                                Line 2340
        }                                                                       
    }                                                                           
  return files_ready_to_read > 0;                                               Line 2343
}                                                                               Block 39
                                                                                
/* Print a header.                                                              
                                                                                
   Formfeeds are assumed to use up two lines at the beginning of                
   the page. */                                                                 
                                                                                
static void                                                                     Line 2351
print_header (void)                                                             Line 2352
{                                                                               
  char page_text[256 + INT_STRLEN_BOUND (page_number)];                         Line 2354
  int available_width;                                                          Line 2355
  int lhs_spaces;                                                               Line 2356
  int rhs_spaces;                                                               Line 2357
                                                                                
  output_position = 0;                                                          Line 2359
  pad_across_to (chars_per_margin);                                             Line 2360
  print_white_space ();                                                         Line 2361
                                                                                
  if (page_number == 0)                                                         Line 2363
    die (EXIT_FAILURE, 0, _("page number overflow"));                           Line 2364
                                                                                
  /* 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);                         Line 2369
  available_width = header_width_available - mbswidth (page_text, 0);           Line 2370
  available_width = MAX (0, available_width);                                   Line 2371
  lhs_spaces = available_width >> 1;                                            Line 2372
  rhs_spaces = available_width - lhs_spaces;                                    Line 2373
                                                                                
  printf ("\n\n%*s%s%*s%s%*s%s\n\n\n",                                          Line 2375
          chars_per_margin, "",                                                 Line 2376
          date_text, lhs_spaces, " ",                                           Line 2377
          file_text, rhs_spaces, " ", page_text);                               Line 2378
                                                                                
  print_a_header = false;                                                       Line 2380
  output_position = 0;                                                          Line 2381
}                                                                               Block 40
                                                                                
/* Print (or store, if p->char_func is store_char()) a line.                    
                                                                                
   Read a character to determine whether we have a line or not.                 
   (We may hit EOF, \n, or \f)                                                  
                                                                                
   Once we know we have a line,                                                 
   set pad_vertically = true, meaning it's safe                                 
   to pad down at the end of the page, since we do have a page.                 
   print a header if needed.                                                    
   pad across to padding_not_printed if needed.                                 
   print any separators which need to be printed.                               
   print a line number if it needs to be printed.                               
                                                                                
   Print the clump which corresponds to the first character.                    
                                                                                
   Enter a loop and keep printing until an end of line condition                
   exists, or until we exceed chars_per_column.                                 
                                                                                
   Return false if we exceed chars_per_column before reading                    
   an end of line character, true otherwise. */                                 
                                                                                
static bool                                                                     Line 2405
read_line (COLUMN *p)                                                           Line 2406
{                                                                               
  int c;                                                                        Line 2408
  int chars IF_LINT ( = 0);                                                     Line 2409
  int last_input_position;                                                      Line 2410
  int j, k;                                                                     Line 2411
  COLUMN *q;                                                                    Line 2412
                                                                                
  /* read 1st character in each line or any character succeeding a FF: */       
  c = getc (p->fp);                                                             Line 2415
                                                                                
  last_input_position = input_position;                                         Line 2417
                                                                                
  if (c == '\f' && p->full_page_printed)                                        Line 2419
    if ((c = getc (p->fp)) == '\n')                                             Line 2420
      c = getc (p->fp);                                                         Line 2421
  p->full_page_printed = false;                                                 Line 2422
                                                                                
  switch (c)                                                                    Line 2424
    {                                                                           
    case '\f':                                                                  Line 2426
      if ((c = getc (p->fp)) != '\n')                                           Line 2427
        ungetc (c, p->fp);                                                      Line 2428
      FF_only = true;                                                           Line 2429
      if (print_a_header && !storing_columns)                                   Line 2430
        {                                                                       
          pad_vertically = true;                                                Line 2432
          print_header ();                                                      Line 2433
        }                                                                       
      else if (keep_FF)                                                         Line 2435
        print_a_FF = true;                                                      Line 2436
      hold_file (p);                                                            Line 2437
      return true;                                                              Line 2438
    case EOF:                                                                   Line 2439
      close_file (p);                                                           Line 2440
      return true;                                                              Line 2441
    case '\n':                                                                  Line 2442
      break;                                                                    Line 2443
    default:                                                                    Line 2444
      chars = char_to_clump (c);                                                Line 2445
    }                                                                           
                                                                                
  if (truncate_lines && input_position > chars_per_column)                      Line 2448
    {                                                                           
      input_position = last_input_position;                                     Line 2450
      return false;                                                             Line 2451
    }                                                                           
                                                                                
  if (p->char_func != store_char)                                               Line 2454
    {                                                                           
      pad_vertically = true;                                                    Line 2456
                                                                                
      if (print_a_header && !storing_columns)                                   Line 2458
        print_header ();                                                        Line 2459
                                                                                
      if (parallel_files && align_empty_cols)                                   Line 2461
        {                                                                       
          /* We have to align empty columns at the beginning of a line. */      
          k = separators_not_printed;                                           Line 2464
          separators_not_printed = 0;                                           Line 2465
          for (j = 1, q = column_vector; j <= k; ++j, ++q)                      Line 2466
            {                                                                   
              align_column (q);                                                 Line 2468
              separators_not_printed += 1;                                      Line 2469
            }                                                                   
          padding_not_printed = p->start_position;                              Line 2471
          if (truncate_lines)                                                   Line 2472
            spaces_not_printed = chars_per_column;                              Line 2473
          else                                                                  Line 2474
            spaces_not_printed = 0;                                             Line 2475
          align_empty_cols = false;                                             Line 2476
        }                                                                       
                                                                                
      if (col_sep_length < padding_not_printed)                                 Line 2479
        {                                                                       
          pad_across_to (padding_not_printed - col_sep_length);                 Line 2481
          padding_not_printed = ANYWHERE;                                       Line 2482
        }                                                                       
                                                                                
      if (use_col_separator)                                                    Line 2485
        print_sep_string ();                                                    Line 2486
    }                                                                           
                                                                                
  if (p->numbered)                                                              Line 2489
    add_line_number (p);                                                        Line 2490
                                                                                
  empty_line = false;                                                           Line 2492
  if (c == '\n')                                                                Line 2493
    return true;                                                                Line 2494
                                                                                
  print_clump (p, chars, clump_buff);                                           Line 2496
                                                                                
  while (true)                                                                  Line 2498
    {                                                                           
      c = getc (p->fp);                                                         Line 2500
                                                                                
      switch (c)                                                                Line 2502
        {                                                                       
        case '\n':                                                              Line 2504
          return true;                                                          Line 2505
        case '\f':                                                              Line 2506
          if ((c = getc (p->fp)) != '\n')                                       Line 2507
            ungetc (c, p->fp);                                                  Line 2508
          if (keep_FF)                                                          Line 2509
            print_a_FF = true;                                                  Line 2510
          hold_file (p);                                                        Line 2511
          return true;                                                          Line 2512
        case EOF:                                                               Line 2513
          close_file (p);                                                       Line 2514
          return true;                                                          Line 2515
        }                                                                       
                                                                                
      last_input_position = input_position;                                     Line 2518
      chars = char_to_clump (c);                                                Line 2519
      if (truncate_lines && input_position > chars_per_column)                  Line 2520
        {                                                                       
          input_position = last_input_position;                                 Line 2522
          return false;                                                         Line 2523
        }                                                                       
                                                                                
      print_clump (p, chars, clump_buff);                                       Line 2526
    }                                                                           
}                                                                               Block 41
                                                                                
/* Print a line from buff.                                                      
                                                                                
   If this function has been called, we know we have "something to              
   print". But it remains to be seen whether we have a real text page           
   or an empty page (a single form feed) with/without a header only.            
   Therefore first we set pad_vertically to true and print a header             
   if necessary.                                                                
   If FF_FOUND and we are using -t|-T option we omit any newline by             
   setting pad_vertically to false (see print_page).                            
   Otherwise we pad across if necessary, print separators if necessary          
   and text of COLUMN *p.                                                       
                                                                                
   Return true, meaning there is no need to call read_rest_of_line. */          
                                                                                
static bool                                                                     Line 2544
print_stored (COLUMN *p)                                                        Line 2545
{                                                                               
  COLUMN *q;                                                                    Line 2547
                                                                                
  int line = p->current_line++;                                                 Line 2549
  char *first = &buff[line_vector[line]];                                       Line 2550
  /* FIXME                                                                      
     UMR: Uninitialized memory read:                                            
     * This is occurring while in:                                              
     print_stored   [pr.c:2239]                                                 
     * Reading 4 bytes from 0x5148c in the heap.                                
     * Address 0x5148c is 4 bytes into a malloc'd block at 0x51488 of 676 bytes 
     * This block was allocated from:                                           
     malloc         [rtlib.o]                                                   
     xmalloc        [xmalloc.c:94]                                              
     init_store_cols [pr.c:1648]                                                
     */                                                                         
  char *last = &buff[line_vector[line + 1]];                                    Line 2562
                                                                                
  pad_vertically = true;                                                        Line 2564
                                                                                
  if (print_a_header)                                                           Line 2566
    print_header ();                                                            Line 2567
                                                                                
  if (p->status == FF_FOUND)                                                    Line 2569
    {                                                                           
      int i;                                                                    Line 2571
      for (i = 1, q = column_vector; i <= columns; ++i, ++q)                    Line 2572
        q->status = ON_HOLD;                                                    Line 2573
      if (column_vector->lines_to_print <= 0)                                   Line 2574
        {                                                                       
          if (!extremities)                                                     Line 2576
            pad_vertically = false;                                             Line 2577
          return true;  /* print a header only */                               Line 2578
        }                                                                       
    }                                                                           
                                                                                
  if (col_sep_length < padding_not_printed)                                     Line 2582
    {                                                                           
      pad_across_to (padding_not_printed - col_sep_length);                     Line 2584
      padding_not_printed = ANYWHERE;                                           Line 2585
    }                                                                           
                                                                                
  if (use_col_separator)                                                        Line 2588
    print_sep_string ();                                                        Line 2589
                                                                                
  while (first != last)                                                         Line 2591
    print_char (*first++);                                                      Line 2592
                                                                                
  if (spaces_not_printed == 0)                                                  Line 2594
    {                                                                           
      output_position = p->start_position + end_vector[line];                   Line 2596
      if (p->start_position - col_sep_length == chars_per_margin)               Line 2597
        output_position -= col_sep_length;                                      Line 2598
    }                                                                           
                                                                                
  return true;                                                                  Line 2601
}                                                                               Block 42
                                                                                
/* Convert a character to the proper format and return the number of            
   characters in the resulting clump.  Increment input_position by              
   the width of the clump.                                                      
                                                                                
   Tabs are converted to clumps of spaces.                                      
   Nonprintable characters may be converted to clumps of escape                 
   sequences or control prefixes.                                               
                                                                                
   Note: the width of a clump is not necessarily equal to the number of         
   characters in clump_buff.  (e.g, the width of '\b' is -1, while the          
   number of characters is 1.) */                                               
                                                                                
static int                                                                      Line 2616
char_to_clump (char c)                                                          Line 2617
{                                                                               
  unsigned char uc = c;                                                         Line 2619
  char *s = clump_buff;                                                         Line 2620
  int i;                                                                        Line 2621
  char esc_buff[4];                                                             Line 2622
  int width;                                                                    Line 2623
  int chars;                                                                    Line 2624
  int chars_per_c = 8;                                                          Line 2625
                                                                                
  if (c == input_tab_char)                                                      Line 2627
    chars_per_c = chars_per_input_tab;                                          Line 2628
                                                                                
  if (c == input_tab_char || c == '\t')                                         Line 2630
    {                                                                           
      width = TAB_WIDTH (chars_per_c, input_position);                          Line 2632
                                                                                
      if (untabify_input)                                                       Line 2634
        {                                                                       
          for (i = width; i; --i)                                               Line 2636
            *s++ = ' ';                                                         Line 2637
          chars = width;                                                        Line 2638
        }                                                                       
      else                                                                      Line 2640
        {                                                                       
          *s = c;                                                               Line 2642
          chars = 1;                                                            Line 2643
        }                                                                       
                                                                                
    }                                                                           
  else if (! isprint (uc))                                                      Line 2647
    {                                                                           
      if (use_esc_sequence)                                                     Line 2649
        {                                                                       
          width = 4;                                                            Line 2651
          chars = 4;                                                            Line 2652
          *s++ = '\\';                                                          Line 2653
          sprintf (esc_buff, "%03o", uc);                                       Line 2654
          for (i = 0; i <= 2; ++i)                                              Line 2655
            *s++ = esc_buff[i];                                                 Line 2656
        }                                                                       
      else if (use_cntrl_prefix)                                                Line 2658
        {                                                                       
          if (uc < 0200)                                                        Line 2660
            {                                                                   
              width = 2;                                                        Line 2662
              chars = 2;                                                        Line 2663
              *s++ = '^';                                                       Line 2664
              *s = c ^ 0100;                                                    Line 2665
            }                                                                   
          else                                                                  Line 2667
            {                                                                   
              width = 4;                                                        Line 2669
              chars = 4;                                                        Line 2670
              *s++ = '\\';                                                      Line 2671
              sprintf (esc_buff, "%03o", uc);                                   Line 2672
              for (i = 0; i <= 2; ++i)                                          Line 2673
                *s++ = esc_buff[i];                                             Line 2674
            }                                                                   
        }                                                                       
      else if (c == '\b')                                                       Line 2677
        {                                                                       
          width = -1;                                                           Line 2679
          chars = 1;                                                            Line 2680
          *s = c;                                                               Line 2681
        }                                                                       
      else                                                                      Line 2683
        {                                                                       
          width = 0;                                                            Line 2685
          chars = 1;                                                            Line 2686
          *s = c;                                                               Line 2687
        }                                                                       
    }                                                                           
  else                                                                          Line 2690
    {                                                                           
      width = 1;                                                                Line 2692
      chars = 1;                                                                Line 2693
      *s = c;                                                                   Line 2694
    }                                                                           
                                                                                
  /* Too many backspaces must put us in position 0 -- never negative.  */       
  if (width < 0 && input_position == 0)                                         Line 2698
    {                                                                           
      chars = 0;                                                                Line 2700
      input_position = 0;                                                       Line 2701
    }                                                                           
  else if (width < 0 && input_position <= -width)                               Line 2703
    input_position = 0;                                                         Line 2704
  else                                                                          Line 2705
    input_position += width;                                                    Line 2706
                                                                                
  return chars;                                                                 Line 2708
}                                                                               Block 43
                                                                                
/* 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'. */                        
                                                                                
static void                                                                     Line 2716
cleanup (void)                                                                  Line 2717
{                                                                               
  free (number_buff);                                                           Line 2719
  free (clump_buff);                                                            Line 2720
  free (column_vector);                                                         Line 2721
  free (line_vector);                                                           Line 2722
  free (end_vector);                                                            Line 2723
  free (buff);                                                                  Line 2724
}                                                                               Block 44
                                                                                
/* Complain, print a usage message, and die. */                                 
                                                                                
void                                                                            Line 2729
usage (int status)                                                              Line 2730
{                                                                               
  if (status != EXIT_SUCCESS)                                                   Line 2732
    emit_try_help ();                                                           ...!common auto-comment...
  else                                                                          Line 2734
    {                                                                           
      printf (_("\                                                              Line 2736
Usage: %s [OPTION]... [FILE]...\n\                                              Line 2737
"),                                                                             Line 2738
              program_name);                                                    Line 2739
                                                                                
      fputs (_("\                                                               Line 2741
Paginate or columnate FILE(s) for printing.\n\                                  Line 2742
"), stdout);                                                                    Line 2743
                                                                                
      emit_stdin_note ();                                                       ...!common auto-comment...
      emit_mandatory_arg_note ();                                               ...!common auto-comment...
                                                                                
      fputs (_("\                                                               Line 2748
  +FIRST_PAGE[:LAST_PAGE], --pages=FIRST_PAGE[:LAST_PAGE]\n\                    Line 2749
                    begin [stop] printing with page FIRST_[LAST_]PAGE\n\        Line 2750
  -COLUMN, --columns=COLUMN\n\                                                  Line 2751
                    output COLUMN columns and print columns down,\n\            Line 2752
                    unless -a is used. Balance number of lines in the\n\        Line 2753
                    columns on each page\n\                                     Line 2754
"), stdout);                                                                    Line 2755
      fputs (_("\                                                               Line 2756
  -a, --across      print columns across rather than down, used together\n\     Line 2757
                    with -COLUMN\n\                                             Line 2758
  -c, --show-control-chars\n\                                                   Line 2759
                    use hat notation (^G) and octal backslash notation\n\       Line 2760
  -d, --double-space\n\                                                         Line 2761
                    double space the output\n\                                  Line 2762
"), stdout);                                                                    Line 2763
      fputs (_("\                                                               Line 2764
  -D, --date-format=FORMAT\n\                                                   Line 2765
                    use FORMAT for the header date\n\                           Line 2766
  -e[CHAR[WIDTH]], --expand-tabs[=CHAR[WIDTH]]\n\                               Line 2767
                    expand input CHARs (TABs) to tab WIDTH (8)\n\               Line 2768
  -F, -f, --form-feed\n\                                                        Line 2769
                    use form feeds instead of newlines to separate pages\n\     Line 2770
                    (by a 3-line page header with -F or a 5-line header\n\      Line 2771
                    and trailer without -F)\n\                                  Line 2772
"), stdout);                                                                    Line 2773
      fputs (_("\                                                               Line 2774
  -h, --header=HEADER\n\                                                        Line 2775
                    use a centered HEADER instead of filename in page header,\n\Line 2776
                    -h \"\" prints a blank line, don't use -h\"\"\n\            Line 2777
  -i[CHAR[WIDTH]], --output-tabs[=CHAR[WIDTH]]\n\                               Line 2778
                    replace spaces with CHARs (TABs) to tab WIDTH (8)\n\        Line 2779
  -J, --join-lines  merge full lines, turns off -W line truncation, no column\n\Line 2780
                    alignment, --sep-string[=STRING] sets separators\n\         Line 2781
"), stdout);                                                                    Line 2782
      fputs (_("\                                                               Line 2783
  -l, --length=PAGE_LENGTH\n\                                                   Line 2784
                    set the page length to PAGE_LENGTH (66) lines\n\            Line 2785
                    (default number of lines of text 56, and with -F 63).\n\    Line 2786
                    implies -t if PAGE_LENGTH <= 10\n\                          Line 2787
"), stdout);                                                                    Line 2788
      fputs (_("\                                                               Line 2789
  -m, --merge       print all files in parallel, one in each column,\n\         Line 2790
                    truncate lines, but join lines of full length with -J\n\    Line 2791
"), stdout);                                                                    Line 2792
      fputs (_("\                                                               Line 2793
  -n[SEP[DIGITS]], --number-lines[=SEP[DIGITS]]\n\                              Line 2794
                    number lines, use DIGITS (5) digits, then SEP (TAB),\n\     Line 2795
                    default counting starts with 1st line of input file\n\      Line 2796
  -N, --first-line-number=NUMBER\n\                                             Line 2797
                    start counting with NUMBER at 1st line of first\n\          Line 2798
                    page printed (see +FIRST_PAGE)\n\                           Line 2799
"), stdout);                                                                    Line 2800
      fputs (_("\                                                               Line 2801
  -o, --indent=MARGIN\n\                                                        Line 2802
                    offset each line with MARGIN (zero) spaces, do not\n\       Line 2803
                    affect -w or -W, MARGIN will be added to PAGE_WIDTH\n\      Line 2804
  -r, --no-file-warnings\n\                                                     Line 2805
                    omit warning when a file cannot be opened\n\                Line 2806
"), stdout);                                                                    Line 2807
      fputs (_("\                                                               Line 2808
  -s[CHAR], --separator[=CHAR]\n\                                               Line 2809
                    separate columns by a single character, default for CHAR\n\ Line 2810
                    is the <TAB> character without -w and \'no char\' with -w.\ Line 2811
\n\                                                                             
                    -s[CHAR] turns off line truncation of all 3 column\n\       Line 2813
                    options (-COLUMN|-a -COLUMN|-m) except -w is set\n\         Line 2814
"), stdout);                                                                    Line 2815
      fputs (_("\                                                               Line 2816
  -S[STRING], --sep-string[=STRING]\n\                                          Line 2817
                    separate columns by STRING,\n\                              Line 2818
                    without -S: Default separator <TAB> with -J and <space>\n\  Line 2819
                    otherwise (same as -S\" \"), no effect on column options\n\ Line 2820
"), stdout);                                                                    Line 2821
      fputs (_("\                                                               Line 2822
  -t, --omit-header  omit page headers and trailers;\n\                         Line 2823
                     implied if PAGE_LENGTH <= 10\n\                            Line 2824
"), stdout);                                                                    Line 2825
      fputs (_("\                                                               Line 2826
  -T, --omit-pagination\n\                                                      Line 2827
                    omit page headers and trailers, eliminate any pagination\n\ Line 2828
                    by form feeds set in input files\n\                         Line 2829
  -v, --show-nonprinting\n\                                                     Line 2830
                    use octal backslash notation\n\                             Line 2831
  -w, --width=PAGE_WIDTH\n\                                                     Line 2832
                    set page width to PAGE_WIDTH (72) characters for\n\         Line 2833
                    multiple text-column output only, -s[char] turns off (72)\n\Line 2834
"), stdout);                                                                    Line 2835
      fputs (_("\                                                               Line 2836
  -W, --page-width=PAGE_WIDTH\n\                                                Line 2837
                    set page width to PAGE_WIDTH (72) characters always,\n\     Line 2838
                    truncate lines, except -J option is set, no interference\n\ Line 2839
                    with -S or -s\n\                                            Line 2840
"), stdout);                                                                    Line 2841
      fputs (HELP_OPTION_DESCRIPTION, stdout);                                  Line 2842
      fputs (VERSION_OPTION_DESCRIPTION, stdout);                               Line 2843
      emit_ancillary_info (PROGRAM_NAME);                                       Line 2844
    }                                                                           
  exit (status);                                                                Line 2846
}                                                                               Block 45