LCOV - code coverage report
Current view: top level - src - csplit.c (source / functions) Hit Total Coverage
Test: coreutils.info Lines: 465 554 83.9 %
Date: 2018-01-30 Functions: 41 44 93.2 %

          Line data    Source code
       1             : /* csplit - split a file into sections determined by context lines
       2             :    Copyright (C) 91, 1995-2007 Free Software Foundation, Inc.
       3             : 
       4             :    This program is free software: you can redistribute it and/or modify
       5             :    it under the terms of the GNU General Public License as published by
       6             :    the Free Software Foundation, either version 3 of the License, or
       7             :    (at your option) any later version.
       8             : 
       9             :    This program is distributed in the hope that it will be useful,
      10             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             :    GNU General Public License for more details.
      13             : 
      14             :    You should have received a copy of the GNU General Public License
      15             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
      16             : 
      17             : /* Written by Stuart Kemp, cpsrk@groper.jcu.edu.au.
      18             :    Modified by David MacKenzie, djm@gnu.ai.mit.edu. */
      19             : 
      20             : #include <config.h>
      21             : 
      22             : #include <getopt.h>
      23             : #include <sys/types.h>
      24             : #include <signal.h>
      25             : 
      26             : #include "system.h"
      27             : 
      28             : #include <regex.h>
      29             : 
      30             : #include "error.h"
      31             : #include "fd-reopen.h"
      32             : #include "inttostr.h"
      33             : #include "quote.h"
      34             : #include "safe-read.h"
      35             : #include "stdio--.h"
      36             : #include "xstrtol.h"
      37             : 
      38             : /* Use SA_NOCLDSTOP as a proxy for whether the sigaction machinery is
      39             :    present.  */
      40             : #ifndef SA_NOCLDSTOP
      41             : # define SA_NOCLDSTOP 0
      42             : # define sigprocmask(How, Set, Oset) /* empty */
      43             : # define sigset_t int
      44             : # if ! HAVE_SIGINTERRUPT
      45             : #  define siginterrupt(sig, flag) /* empty */
      46             : # endif
      47             : #endif
      48             : 
      49             : /* The official name of this program (e.g., no `g' prefix).  */
      50             : #define PROGRAM_NAME "csplit"
      51             : 
      52             : #define AUTHORS "Stuart Kemp", "David MacKenzie"
      53             : 
      54             : /* Increment size of area for control records. */
      55             : #define ALLOC_SIZE 20
      56             : 
      57             : /* The default prefix for output file names. */
      58             : #define DEFAULT_PREFIX  "xx"
      59             : 
      60             : /* A compiled pattern arg. */
      61             : struct control
      62             : {
      63             :   intmax_t offset;              /* Offset from regexp to split at. */
      64             :   uintmax_t lines_required;     /* Number of lines required. */
      65             :   uintmax_t repeat;             /* Repeat count. */
      66             :   int argnum;                   /* ARGV index. */
      67             :   bool repeat_forever;          /* True if `*' used as a repeat count. */
      68             :   bool ignore;                  /* If true, produce no output (for regexp). */
      69             :   bool regexpr;                 /* True if regular expression was used. */
      70             :   struct re_pattern_buffer re_compiled; /* Compiled regular expression. */
      71             : };
      72             : 
      73             : /* Initial size of data area in buffers. */
      74             : #define START_SIZE      8191
      75             : 
      76             : /* Increment size for data area. */
      77             : #define INCR_SIZE       2048
      78             : 
      79             : /* Number of lines kept in each node in line list. */
      80             : #define CTRL_SIZE       80
      81             : 
      82             : #ifdef DEBUG
      83             : /* Some small values to test the algorithms. */
      84             : # define START_SIZE     200
      85             : # define INCR_SIZE      10
      86             : # define CTRL_SIZE      1
      87             : #endif
      88             : 
      89             : /* A string with a length count. */
      90             : struct cstring
      91             : {
      92             :   size_t len;
      93             :   char *str;
      94             : };
      95             : 
      96             : /* Pointers to the beginnings of lines in the buffer area.
      97             :    These structures are linked together if needed. */
      98             : struct line
      99             : {
     100             :   size_t used;                  /* Number of offsets used in this struct. */
     101             :   size_t insert_index;          /* Next offset to use when inserting line. */
     102             :   size_t retrieve_index;        /* Next index to use when retrieving line. */
     103             :   struct cstring starts[CTRL_SIZE]; /* Lines in the data area. */
     104             :   struct line *next;            /* Next in linked list. */
     105             : };
     106             : 
     107             : /* The structure to hold the input lines.
     108             :    Contains a pointer to the data area and a list containing
     109             :    pointers to the individual lines. */
     110             : struct buffer_record
     111             : {
     112             :   size_t bytes_alloc;           /* Size of the buffer area. */
     113             :   size_t bytes_used;            /* Bytes used in the buffer area. */
     114             :   uintmax_t start_line;         /* First line number in this buffer. */
     115             :   uintmax_t first_available;    /* First line that can be retrieved. */
     116             :   size_t num_lines;             /* Number of complete lines in this buffer. */
     117             :   char *buffer;                 /* Data area. */
     118             :   struct line *line_start;      /* Head of list of pointers to lines. */
     119             :   struct line *curr_line;       /* The line start record currently in use. */
     120             :   struct buffer_record *next;
     121             : };
     122             : 
     123             : static void close_output_file (void);
     124             : static void create_output_file (void);
     125             : static void delete_all_files (bool);
     126             : static void save_line_to_file (const struct cstring *line);
     127             : void usage (int status);
     128             : 
     129             : /* The name this program was run with. */
     130             : char *program_name;
     131             : 
     132             : /* Start of buffer list. */
     133             : static struct buffer_record *head = NULL;
     134             : 
     135             : /* Partially read line. */
     136             : static char *hold_area = NULL;
     137             : 
     138             : /* Number of bytes in `hold_area'. */
     139             : static size_t hold_count = 0;
     140             : 
     141             : /* Number of the last line in the buffers. */
     142             : static uintmax_t last_line_number = 0;
     143             : 
     144             : /* Number of the line currently being examined. */
     145             : static uintmax_t current_line = 0;
     146             : 
     147             : /* If true, we have read EOF. */
     148             : static bool have_read_eof = false;
     149             : 
     150             : /* Name of output files. */
     151             : static char *volatile filename_space = NULL;
     152             : 
     153             : /* Prefix part of output file names. */
     154             : static char const *volatile prefix = NULL;
     155             : 
     156             : /* Suffix part of output file names. */
     157             : static char *volatile suffix = NULL;
     158             : 
     159             : /* Number of digits to use in output file names. */
     160             : static int volatile digits = 2;
     161             : 
     162             : /* Number of files created so far. */
     163             : static unsigned int volatile files_created = 0;
     164             : 
     165             : /* Number of bytes written to current file. */
     166             : static uintmax_t bytes_written;
     167             : 
     168             : /* Output file pointer. */
     169             : static FILE *output_stream = NULL;
     170             : 
     171             : /* Output file name. */
     172             : static char *output_filename = NULL;
     173             : 
     174             : /* Perhaps it would be cleaner to pass arg values instead of indexes. */
     175             : static char **global_argv;
     176             : 
     177             : /* If true, do not print the count of bytes in each output file. */
     178             : static bool suppress_count;
     179             : 
     180             : /* If true, remove output files on error. */
     181             : static bool volatile remove_files;
     182             : 
     183             : /* If true, remove all output files which have a zero length. */
     184             : static bool elide_empty_files;
     185             : 
     186             : /* The compiled pattern arguments, which determine how to split
     187             :    the input file. */
     188             : static struct control *controls;
     189             : 
     190             : /* Number of elements in `controls'. */
     191             : static size_t control_used;
     192             : 
     193             : /* The set of signals that are caught.  */
     194             : static sigset_t caught_signals;
     195             : 
     196             : static struct option const longopts[] =
     197             : {
     198             :   {"digits", required_argument, NULL, 'n'},
     199             :   {"quiet", no_argument, NULL, 'q'},
     200             :   {"silent", no_argument, NULL, 's'},
     201             :   {"keep-files", no_argument, NULL, 'k'},
     202             :   {"elide-empty-files", no_argument, NULL, 'z'},
     203             :   {"prefix", required_argument, NULL, 'f'},
     204             :   {"suffix-format", required_argument, NULL, 'b'},
     205             :   {GETOPT_HELP_OPTION_DECL},
     206             :   {GETOPT_VERSION_OPTION_DECL},
     207             :   {NULL, 0, NULL, 0}
     208             : };
     209             : 
     210             : /* Optionally remove files created so far; then exit.
     211             :    Called when an error detected. */
     212             : 
     213             : static void
     214           6 : cleanup (void)
     215             : {
     216             :   sigset_t oldset;
     217             : 
     218           6 :   close_output_file ();
     219             : 
     220           6 :   sigprocmask (SIG_BLOCK, &caught_signals, &oldset);
     221           6 :   delete_all_files (false);
     222           6 :   sigprocmask (SIG_SETMASK, &oldset, NULL);
     223           6 : }
     224             : 
     225             : static void cleanup_fatal (void) ATTRIBUTE_NORETURN;
     226             : static void
     227           6 : cleanup_fatal (void)
     228             : {
     229           6 :   cleanup ();
     230           6 :   exit (EXIT_FAILURE);
     231             : }
     232             : 
     233             : extern void
     234           0 : xalloc_die (void)
     235             : {
     236           0 :   error (0, 0, "%s", _("memory exhausted"));
     237           0 :   cleanup_fatal ();
     238             : }
     239             : 
     240             : static void
     241           0 : interrupt_handler (int sig)
     242             : {
     243             :   if (! SA_NOCLDSTOP)
     244             :     signal (sig, SIG_IGN);
     245             : 
     246           0 :   delete_all_files (true);
     247             : 
     248           0 :   signal (sig, SIG_DFL);
     249           0 :   raise (sig);
     250           0 : }
     251             : 
     252             : /* Keep track of NUM bytes of a partial line in buffer START.
     253             :    These bytes will be retrieved later when another large buffer is read.  */
     254             : 
     255             : static void
     256           5 : save_to_hold_area (char *start, size_t num)
     257             : {
     258           5 :   free (hold_area);
     259           5 :   hold_area = start;
     260           5 :   hold_count = num;
     261           5 : }
     262             : 
     263             : /* Read up to MAX_N_BYTES bytes from the input stream into DEST.
     264             :    Return the number of bytes read. */
     265             : 
     266             : static size_t
     267          45 : read_input (char *dest, size_t max_n_bytes)
     268             : {
     269             :   size_t bytes_read;
     270             : 
     271          45 :   if (max_n_bytes == 0)
     272           0 :     return 0;
     273             : 
     274          45 :   bytes_read = safe_read (STDIN_FILENO, dest, max_n_bytes);
     275             : 
     276          45 :   if (bytes_read == 0)
     277          21 :     have_read_eof = true;
     278             : 
     279          45 :   if (bytes_read == SAFE_READ_ERROR)
     280             :     {
     281           3 :       error (0, errno, _("read error"));
     282           3 :       cleanup_fatal ();
     283             :     }
     284             : 
     285          42 :   return bytes_read;
     286             : }
     287             : 
     288             : /* Initialize existing line record P. */
     289             : 
     290             : static void
     291          24 : clear_line_control (struct line *p)
     292             : {
     293          24 :   p->used = 0;
     294          24 :   p->insert_index = 0;
     295          24 :   p->retrieve_index = 0;
     296          24 : }
     297             : 
     298             : /* Return a new, initialized line record. */
     299             : 
     300             : static struct line *
     301          24 : new_line_control (void)
     302             : {
     303          24 :   struct line *p = xmalloc (sizeof *p);
     304             : 
     305          24 :   p->next = NULL;
     306          24 :   clear_line_control (p);
     307             : 
     308          24 :   return p;
     309             : }
     310             : 
     311             : /* Record LINE_START, which is the address of the start of a line
     312             :    of length LINE_LEN in the large buffer, in the lines buffer of B. */
     313             : 
     314             : static void
     315         133 : keep_new_line (struct buffer_record *b, char *line_start, size_t line_len)
     316             : {
     317             :   struct line *l;
     318             : 
     319             :   /* If there is no existing area to keep line info, get some. */
     320         133 :   if (b->line_start == NULL)
     321          24 :     b->line_start = b->curr_line = new_line_control ();
     322             : 
     323             :   /* If existing area for lines is full, get more. */
     324         133 :   if (b->curr_line->used == CTRL_SIZE)
     325             :     {
     326           0 :       b->curr_line->next = new_line_control ();
     327           0 :       b->curr_line = b->curr_line->next;
     328             :     }
     329             : 
     330         133 :   l = b->curr_line;
     331             : 
     332             :   /* Record the start of the line, and update counters. */
     333         133 :   l->starts[l->insert_index].str = line_start;
     334         133 :   l->starts[l->insert_index].len = line_len;
     335         133 :   l->used++;
     336         133 :   l->insert_index++;
     337         133 : }
     338             : 
     339             : /* Scan the buffer in B for newline characters
     340             :    and record the line start locations and lengths in B.
     341             :    Return the number of lines found in this buffer.
     342             : 
     343             :    There may be an incomplete line at the end of the buffer;
     344             :    a pointer is kept to this area, which will be used when
     345             :    the next buffer is filled. */
     346             : 
     347             : static size_t
     348          42 : record_line_starts (struct buffer_record *b)
     349             : {
     350             :   char *line_start;             /* Start of current line. */
     351             :   char *line_end;               /* End of each line found. */
     352             :   size_t bytes_left;            /* Length of incomplete last line. */
     353             :   size_t lines;                 /* Number of lines found. */
     354             :   size_t line_length;           /* Length of each line found. */
     355             : 
     356          42 :   if (b->bytes_used == 0)
     357          16 :     return 0;
     358             : 
     359          26 :   lines = 0;
     360          26 :   line_start = b->buffer;
     361          26 :   bytes_left = b->bytes_used;
     362             : 
     363             :   for (;;)
     364             :     {
     365         282 :       line_end = memchr (line_start, '\n', bytes_left);
     366         154 :       if (line_end == NULL)
     367          26 :         break;
     368         128 :       line_length = line_end - line_start + 1;
     369         128 :       keep_new_line (b, line_start, line_length);
     370         128 :       bytes_left -= line_length;
     371         128 :       line_start = line_end + 1;
     372         128 :       lines++;
     373             :     }
     374             : 
     375             :   /* Check for an incomplete last line. */
     376          26 :   if (bytes_left)
     377             :     {
     378          10 :       if (have_read_eof)
     379             :         {
     380           5 :           keep_new_line (b, line_start, bytes_left);
     381           5 :           lines++;
     382             :         }
     383             :       else
     384           5 :         save_to_hold_area (xmemdup (line_start, bytes_left), bytes_left);
     385             :     }
     386             : 
     387          26 :   b->num_lines = lines;
     388          26 :   b->first_available = b->start_line = last_line_number + 1;
     389          26 :   last_line_number += lines;
     390             : 
     391          26 :   return lines;
     392             : }
     393             : 
     394             : /* Return a new buffer with room to store SIZE bytes, plus
     395             :    an extra byte for safety. */
     396             : 
     397             : static struct buffer_record *
     398          45 : create_new_buffer (size_t size)
     399             : {
     400          45 :   struct buffer_record *new_buffer = xmalloc (sizeof *new_buffer);
     401             : 
     402          45 :   new_buffer->buffer = xmalloc (size + 1);
     403             : 
     404          45 :   new_buffer->bytes_alloc = size;
     405          45 :   new_buffer->line_start = new_buffer->curr_line = NULL;
     406             : 
     407          45 :   return new_buffer;
     408             : }
     409             : 
     410             : /* Return a new buffer of at least MINSIZE bytes.  If a buffer of at
     411             :    least that size is currently free, use it, otherwise create a new one. */
     412             : 
     413             : static struct buffer_record *
     414          45 : get_new_buffer (size_t min_size)
     415             : {
     416             :   struct buffer_record *new_buffer; /* Buffer to return. */
     417             :   size_t alloc_size;    /* Actual size that will be requested. */
     418             : 
     419          45 :   alloc_size = START_SIZE;
     420          45 :   if (alloc_size < min_size)
     421             :     {
     422           2 :       size_t s = min_size - alloc_size + INCR_SIZE - 1;
     423           2 :       alloc_size += s - s % INCR_SIZE;
     424             :     }
     425             : 
     426          45 :   new_buffer = create_new_buffer (alloc_size);
     427             : 
     428          45 :   new_buffer->num_lines = 0;
     429          45 :   new_buffer->bytes_used = 0;
     430          45 :   new_buffer->start_line = new_buffer->first_available = last_line_number + 1;
     431          45 :   new_buffer->next = NULL;
     432             : 
     433          45 :   return new_buffer;
     434             : }
     435             : 
     436             : static void
     437          43 : free_buffer (struct buffer_record *buf)
     438             : {
     439          43 :   free (buf->buffer);
     440          43 :   buf->buffer = NULL;
     441          43 : }
     442             : 
     443             : /* Append buffer BUF to the linked list of buffers that contain
     444             :    some data yet to be processed. */
     445             : 
     446             : static void
     447          24 : save_buffer (struct buffer_record *buf)
     448             : {
     449             :   struct buffer_record *p;
     450             : 
     451          24 :   buf->next = NULL;
     452          24 :   buf->curr_line = buf->line_start;
     453             : 
     454          24 :   if (head == NULL)
     455          23 :     head = buf;
     456             :   else
     457             :     {
     458           1 :       for (p = head; p->next; p = p->next)
     459             :         /* Do nothing. */ ;
     460           1 :       p->next = buf;
     461             :     }
     462          24 : }
     463             : 
     464             : /* Fill a buffer of input.
     465             : 
     466             :    Set the initial size of the buffer to a default.
     467             :    Fill the buffer (from the hold area and input stream)
     468             :    and find the individual lines.
     469             :    If no lines are found (the buffer is too small to hold the next line),
     470             :    release the current buffer (whose contents would have been put in the
     471             :    hold area) and repeat the process with another large buffer until at least
     472             :    one entire line has been read.
     473             : 
     474             :    Return true if a new buffer was obtained, otherwise false
     475             :    (in which case end-of-file must have been encountered). */
     476             : 
     477             : static bool
     478          50 : load_buffer (void)
     479             : {
     480             :   struct buffer_record *b;
     481          50 :   size_t bytes_wanted = START_SIZE; /* Minimum buffer size. */
     482             :   size_t bytes_avail;           /* Size of new buffer created. */
     483             :   size_t lines_found;           /* Number of lines in this new buffer. */
     484             :   char *p;                      /* Place to load into buffer. */
     485             : 
     486          50 :   if (have_read_eof)
     487           7 :     return false;
     488             : 
     489             :   /* We must make the buffer at least as large as the amount of data
     490             :      in the partial line left over from the last call. */
     491          43 :   if (bytes_wanted < hold_count)
     492           0 :     bytes_wanted = hold_count;
     493             : 
     494             :   while (1)
     495             :     {
     496          47 :       b = get_new_buffer (bytes_wanted);
     497          45 :       bytes_avail = b->bytes_alloc; /* Size of buffer returned. */
     498          45 :       p = b->buffer;
     499             : 
     500             :       /* First check the `holding' area for a partial line. */
     501          45 :       if (hold_count)
     502             :         {
     503           5 :           memcpy (p, hold_area, hold_count);
     504           5 :           p += hold_count;
     505           5 :           b->bytes_used += hold_count;
     506           5 :           bytes_avail -= hold_count;
     507           5 :           hold_count = 0;
     508             :         }
     509             : 
     510          45 :       b->bytes_used += read_input (p, bytes_avail);
     511             : 
     512          42 :       lines_found = record_line_starts (b);
     513          42 :       if (!lines_found)
     514          18 :         free_buffer (b);
     515             : 
     516          42 :       if (lines_found || have_read_eof)
     517             :         break;
     518             : 
     519           2 :       if (xalloc_oversized (2, b->bytes_alloc))
     520           0 :         xalloc_die ();
     521           2 :       bytes_wanted = 2 * b->bytes_alloc;
     522           2 :       free_buffer (b);
     523           2 :       free (b);
     524             :     }
     525             : 
     526          40 :   if (lines_found)
     527          24 :     save_buffer (b);
     528             :   else
     529          16 :     free (b);
     530             : 
     531          40 :   return lines_found != 0;
     532             : }
     533             : 
     534             : /* Return the line number of the first line that has not yet been retrieved. */
     535             : 
     536             : static uintmax_t
     537          24 : get_first_line_in_buffer (void)
     538             : {
     539          24 :   if (head == NULL && !load_buffer ())
     540           0 :     error (EXIT_FAILURE, errno, _("input disappeared"));
     541             : 
     542          23 :   return head->first_available;
     543             : }
     544             : 
     545             : /* Return a pointer to the logical first line in the buffer and make the
     546             :    next line the logical first line.
     547             :    Return NULL if there is no more input. */
     548             : 
     549             : static struct cstring *
     550         153 : remove_line (void)
     551             : {
     552             :   /* If non-NULL, this is the buffer for which the previous call
     553             :      returned the final line.  So now, presuming that line has been
     554             :      processed, we can free the buffer and reset this pointer.  */
     555             :   static struct buffer_record *prev_buf = NULL;
     556             : 
     557             :   struct cstring *line;         /* Return value. */
     558             :   struct line *l;               /* For convenience. */
     559             : 
     560         153 :   if (prev_buf)
     561             :     {
     562          23 :       free_buffer (prev_buf);
     563          23 :       prev_buf = NULL;
     564             :     }
     565             : 
     566         153 :   if (head == NULL && !load_buffer ())
     567          20 :     return NULL;
     568             : 
     569         133 :   if (current_line < head->first_available)
     570         112 :     current_line = head->first_available;
     571             : 
     572         133 :   ++(head->first_available);
     573             : 
     574         133 :   l = head->curr_line;
     575             : 
     576         133 :   line = &l->starts[l->retrieve_index];
     577             : 
     578             :   /* Advance index to next line. */
     579         133 :   if (++l->retrieve_index == l->used)
     580             :     {
     581             :       /* Go on to the next line record. */
     582          24 :       head->curr_line = l->next;
     583          24 :       if (head->curr_line == NULL || head->curr_line->used == 0)
     584             :         {
     585             :           /* Go on to the next data block.
     586             :              but first record the current one so we can free it
     587             :              once the line we're returning has been processed.  */
     588          24 :           prev_buf = head;
     589          24 :           head = head->next;
     590             :         }
     591             :     }
     592             : 
     593         133 :   return line;
     594             : }
     595             : 
     596             : /* Search the buffers for line LINENUM, reading more input if necessary.
     597             :    Return a pointer to the line, or NULL if it is not found in the file. */
     598             : 
     599             : static struct cstring *
     600          27 : find_line (uintmax_t linenum)
     601             : {
     602             :   struct buffer_record *b;
     603             : 
     604          27 :   if (head == NULL && !load_buffer ())
     605           1 :     return NULL;
     606             : 
     607          24 :   if (linenum < head->start_line)
     608           0 :     return NULL;
     609             : 
     610          24 :   for (b = head;;)
     611             :     {
     612          26 :       if (linenum < b->start_line + b->num_lines)
     613             :         {
     614             :           /* The line is in this buffer. */
     615             :           struct line *l;
     616             :           size_t offset;        /* How far into the buffer the line is. */
     617             : 
     618          22 :           l = b->line_start;
     619          22 :           offset = linenum - b->start_line;
     620             :           /* Find the control record. */
     621          44 :           while (offset >= CTRL_SIZE)
     622             :             {
     623           0 :               l = l->next;
     624           0 :               offset -= CTRL_SIZE;
     625             :             }
     626          22 :           return &l->starts[offset];
     627             :         }
     628           3 :       if (b->next == NULL && !load_buffer ())
     629           2 :         return NULL;
     630           1 :       b = b->next;           /* Try the next data block. */
     631             :     }
     632             : }
     633             : 
     634             : /* Return true if at least one more line is available for input. */
     635             : 
     636             : static bool
     637           2 : no_more_lines (void)
     638             : {
     639           2 :   return find_line (current_line + 1) == NULL;
     640             : }
     641             : 
     642             : /* Open NAME as standard input.  */
     643             : 
     644             : static void
     645          59 : set_input_file (const char *name)
     646             : {
     647          59 :   if (! STREQ (name, "-") && fd_reopen (STDIN_FILENO, name, O_RDONLY, 0) < 0)
     648           5 :     error (EXIT_FAILURE, errno, _("cannot open %s for reading"), quote (name));
     649          54 : }
     650             : 
     651             : /* Write all lines from the beginning of the buffer up to, but
     652             :    not including, line LAST_LINE, to the current output file.
     653             :    If IGNORE is true, do not output lines selected here.
     654             :    ARGNUM is the index in ARGV of the current pattern. */
     655             : 
     656             : static void
     657          21 : write_to_file (uintmax_t last_line, bool ignore, int argnum)
     658             : {
     659             :   struct cstring *line;
     660             :   uintmax_t first_line;         /* First available input line. */
     661             :   uintmax_t lines;              /* Number of lines to output. */
     662             :   uintmax_t i;
     663             : 
     664          21 :   first_line = get_first_line_in_buffer ();
     665             : 
     666          21 :   if (first_line > last_line)
     667             :     {
     668           0 :       error (0, 0, _("%s: line number out of range"), global_argv[argnum]);
     669           0 :       cleanup_fatal ();
     670             :     }
     671             : 
     672          21 :   lines = last_line - first_line;
     673             : 
     674          23 :   for (i = 0; i < lines; i++)
     675             :     {
     676           2 :       line = remove_line ();
     677           2 :       if (line == NULL)
     678             :         {
     679           0 :           error (0, 0, _("%s: line number out of range"), global_argv[argnum]);
     680           0 :           cleanup_fatal ();
     681             :         }
     682           2 :       if (!ignore)
     683           2 :         save_line_to_file (line);
     684             :     }
     685          21 : }
     686             : 
     687             : /* Output any lines left after all regexps have been processed. */
     688             : 
     689             : static void
     690          20 : dump_rest_of_file (void)
     691             : {
     692             :   struct cstring *line;
     693             : 
     694         163 :   while ((line = remove_line ()) != NULL)
     695         123 :     save_line_to_file (line);
     696          20 : }
     697             : 
     698             : /* Handle an attempt to read beyond EOF under the control of record P,
     699             :    on iteration REPETITION if nonzero. */
     700             : 
     701             : static void handle_line_error (const struct control *, uintmax_t)
     702             :      ATTRIBUTE_NORETURN;
     703             : static void
     704           1 : handle_line_error (const struct control *p, uintmax_t repetition)
     705             : {
     706             :   char buf[INT_BUFSIZE_BOUND (uintmax_t)];
     707             : 
     708           1 :   fprintf (stderr, _("%s: %s: line number out of range"),
     709           1 :            program_name, quote (umaxtostr (p->lines_required, buf)));
     710           1 :   if (repetition)
     711           0 :     fprintf (stderr, _(" on repetition %s\n"), umaxtostr (repetition, buf));
     712             :   else
     713           1 :     fprintf (stderr, "\n");
     714             : 
     715           1 :   cleanup_fatal ();
     716             : }
     717             : 
     718             : /* Determine the line number that marks the end of this file,
     719             :    then get those lines and save them to the output file.
     720             :    P is the control record.
     721             :    REPETITION is the repetition number. */
     722             : 
     723             : static void
     724           3 : process_line_count (const struct control *p, uintmax_t repetition)
     725             : {
     726             :   uintmax_t linenum;
     727           3 :   uintmax_t last_line_to_save = p->lines_required * (repetition + 1);
     728             :   struct cstring *line;
     729             : 
     730           3 :   create_output_file ();
     731             : 
     732           3 :   linenum = get_first_line_in_buffer ();
     733             : 
     734          12 :   while (linenum++ < last_line_to_save)
     735             :     {
     736           8 :       line = remove_line ();
     737           8 :       if (line == NULL)
     738           0 :         handle_line_error (p, repetition);
     739           8 :       save_line_to_file (line);
     740             :     }
     741             : 
     742           2 :   close_output_file ();
     743             : 
     744             :   /* Ensure that the line number specified is not 1 greater than
     745             :      the number of lines in the file. */
     746           2 :   if (no_more_lines ())
     747           1 :     handle_line_error (p, repetition);
     748           1 : }
     749             : 
     750             : static void regexp_error (struct control *, uintmax_t, bool) ATTRIBUTE_NORETURN;
     751             : static void
     752           2 : regexp_error (struct control *p, uintmax_t repetition, bool ignore)
     753             : {
     754           2 :   fprintf (stderr, _("%s: %s: match not found"),
     755           2 :            program_name, quote (global_argv[p->argnum]));
     756             : 
     757           2 :   if (repetition)
     758             :     {
     759             :       char buf[INT_BUFSIZE_BOUND (uintmax_t)];
     760           0 :       fprintf (stderr, _(" on repetition %s\n"), umaxtostr (repetition, buf));
     761             :     }
     762             :   else
     763           2 :     fprintf (stderr, "\n");
     764             : 
     765           2 :   if (!ignore)
     766             :     {
     767           2 :       dump_rest_of_file ();
     768           2 :       close_output_file ();
     769             :     }
     770           2 :   cleanup_fatal ();
     771             : }
     772             : 
     773             : /* Read the input until a line matches the regexp in P, outputting
     774             :    it unless P->IGNORE is true.
     775             :    REPETITION is this repeat-count; 0 means the first time. */
     776             : 
     777             : static void
     778          25 : process_regexp (struct control *p, uintmax_t repetition)
     779             : {
     780             :   struct cstring *line;         /* From input file. */
     781             :   size_t line_len;              /* To make "$" in regexps work. */
     782             :   uintmax_t break_line;         /* First line number of next file. */
     783          25 :   bool ignore = p->ignore;   /* If true, skip this section. */
     784             :   regoff_t ret;
     785             : 
     786          25 :   if (!ignore)
     787          22 :     create_output_file ();
     788             : 
     789             :   /* If there is no offset for the regular expression, or
     790             :      it is positive, then it is not necessary to buffer the lines. */
     791             : 
     792          25 :   if (p->offset >= 0)
     793             :     {
     794             :       for (;;)
     795             :         {
     796          25 :           line = find_line (++current_line);
     797          23 :           if (line == NULL)
     798             :             {
     799           2 :               if (p->repeat_forever)
     800             :                 {
     801           0 :                   if (!ignore)
     802             :                     {
     803           0 :                       dump_rest_of_file ();
     804           0 :                       close_output_file ();
     805             :                     }
     806           0 :                   exit (EXIT_SUCCESS);
     807             :                 }
     808             :               else
     809           2 :                 regexp_error (p, repetition, ignore);
     810             :             }
     811          21 :           line_len = line->len;
     812          21 :           if (line->str[line_len - 1] == '\n')
     813          18 :             line_len--;
     814          21 :           ret = re_search (&p->re_compiled, line->str, line_len,
     815             :                            0, line_len, NULL);
     816          21 :           if (ret == -2)
     817             :             {
     818           0 :               error (0, 0, _("error in regular expression search"));
     819           0 :               cleanup_fatal ();
     820             :             }
     821          21 :           if (ret == -1)
     822             :             {
     823           0 :               line = remove_line ();
     824           0 :               if (!ignore)
     825           0 :                 save_line_to_file (line);
     826             :             }
     827             :           else
     828          21 :             break;
     829             :         }
     830             :     }
     831             :   else
     832             :     {
     833             :       /* Buffer the lines. */
     834             :       for (;;)
     835             :         {
     836           0 :           line = find_line (++current_line);
     837           0 :           if (line == NULL)
     838             :             {
     839           0 :               if (p->repeat_forever)
     840             :                 {
     841           0 :                   if (!ignore)
     842             :                     {
     843           0 :                       dump_rest_of_file ();
     844           0 :                       close_output_file ();
     845             :                     }
     846           0 :                   exit (EXIT_SUCCESS);
     847             :                 }
     848             :               else
     849           0 :                 regexp_error (p, repetition, ignore);
     850             :             }
     851           0 :           line_len = line->len;
     852           0 :           if (line->str[line_len - 1] == '\n')
     853           0 :             line_len--;
     854           0 :           ret = re_search (&p->re_compiled, line->str, line_len,
     855             :                            0, line_len, NULL);
     856           0 :           if (ret == -2)
     857             :             {
     858           0 :               error (0, 0, _("error in regular expression search"));
     859           0 :               cleanup_fatal ();
     860             :             }
     861           0 :           if (ret != -1)
     862           0 :             break;
     863             :         }
     864             :     }
     865             : 
     866             :   /* Account for any offset from this regexp. */
     867          21 :   break_line = current_line + p->offset;
     868             : 
     869          21 :   write_to_file (break_line, ignore, p->argnum);
     870             : 
     871          21 :   if (!ignore)
     872          19 :     close_output_file ();
     873             : 
     874          21 :   if (p->offset > 0)
     875           0 :     current_line = break_line;
     876          21 : }
     877             : 
     878             : /* Split the input file according to the control records we have built. */
     879             : 
     880             : static void
     881          24 : split_file (void)
     882             : {
     883             :   size_t i;
     884             : 
     885          46 :   for (i = 0; i < control_used; i++)
     886             :     {
     887             :       uintmax_t j;
     888          28 :       if (controls[i].regexpr)
     889             :         {
     890          71 :           for (j = 0; (controls[i].repeat_forever
     891          67 :                        || j <= controls[i].repeat); j++)
     892          25 :             process_regexp (&controls[i], j);
     893             :         }
     894             :       else
     895             :         {
     896           7 :           for (j = 0; (controls[i].repeat_forever
     897           5 :                        || j <= controls[i].repeat); j++)
     898           3 :             process_line_count (&controls[i], j);
     899             :         }
     900             :     }
     901             : 
     902          18 :   create_output_file ();
     903          18 :   dump_rest_of_file ();
     904          18 :   close_output_file ();
     905          18 : }
     906             : 
     907             : /* Return the name of output file number NUM.
     908             : 
     909             :    This function is called from a signal handler, so it should invoke
     910             :    only reentrant functions that are async-signal-safe.  POSIX does
     911             :    not guarantee this for the functions called below, but we don't
     912             :    know of any hosts where this implementation isn't safe.  */
     913             : 
     914             : static char *
     915          50 : make_filename (unsigned int num)
     916             : {
     917          50 :   strcpy (filename_space, prefix);
     918          50 :   if (suffix)
     919          12 :     sprintf (filename_space + strlen (prefix), suffix, num);
     920             :   else
     921          38 :     sprintf (filename_space + strlen (prefix), "%0*u", digits, num);
     922          50 :   return filename_space;
     923             : }
     924             : 
     925             : /* Create the next output file. */
     926             : 
     927             : static void
     928          43 : create_output_file (void)
     929             : {
     930             :   sigset_t oldset;
     931             :   bool fopen_ok;
     932             :   int fopen_errno;
     933             : 
     934          43 :   output_filename = make_filename (files_created);
     935             : 
     936             :   /* Create the output file in a critical section, to avoid races.  */
     937          43 :   sigprocmask (SIG_BLOCK, &caught_signals, &oldset);
     938          43 :   output_stream = fopen (output_filename, "w");
     939          43 :   fopen_ok = (output_stream != NULL);
     940          43 :   fopen_errno = errno;
     941          43 :   files_created += fopen_ok;
     942          43 :   sigprocmask (SIG_SETMASK, &oldset, NULL);
     943             : 
     944          43 :   if (! fopen_ok)
     945             :     {
     946           0 :       error (0, fopen_errno, "%s", output_filename);
     947           0 :       cleanup_fatal ();
     948             :     }
     949          43 :   bytes_written = 0;
     950          43 : }
     951             : 
     952             : /* If requested, delete all the files we have created.  This function
     953             :    must be called only from critical sections.  */
     954             : 
     955             : static void
     956           6 : delete_all_files (bool in_signal_handler)
     957             : {
     958             :   unsigned int i;
     959             : 
     960           6 :   if (! remove_files)
     961           0 :     return;
     962             : 
     963          13 :   for (i = 0; i < files_created; i++)
     964             :     {
     965           7 :       const char *name = make_filename (i);
     966           7 :       if (unlink (name) != 0 && !in_signal_handler)
     967           0 :         error (0, errno, "%s", name);
     968             :     }
     969             : 
     970           6 :   files_created = 0;
     971             : }
     972             : 
     973             : /* Close the current output file and print the count
     974             :    of characters in this file. */
     975             : 
     976             : static void
     977          47 : close_output_file (void)
     978             : {
     979          47 :   if (output_stream)
     980             :     {
     981          43 :       if (ferror (output_stream))
     982             :         {
     983           0 :           error (0, 0, _("write error for %s"), quote (output_filename));
     984           0 :           output_stream = NULL;
     985           0 :           cleanup_fatal ();
     986             :         }
     987          43 :       if (fclose (output_stream) != 0)
     988             :         {
     989           0 :           error (0, errno, "%s", output_filename);
     990           0 :           output_stream = NULL;
     991           0 :           cleanup_fatal ();
     992             :         }
     993          43 :       if (bytes_written == 0 && elide_empty_files)
     994           0 :         {
     995             :           sigset_t oldset;
     996             :           bool unlink_ok;
     997             :           int unlink_errno;
     998             : 
     999             :           /* Remove the output file in a critical section, to avoid races.  */
    1000           0 :           sigprocmask (SIG_BLOCK, &caught_signals, &oldset);
    1001           0 :           unlink_ok = (unlink (output_filename) == 0);
    1002           0 :           unlink_errno = errno;
    1003           0 :           files_created -= unlink_ok;
    1004           0 :           sigprocmask (SIG_SETMASK, &oldset, NULL);
    1005             : 
    1006           0 :           if (! unlink_ok)
    1007           0 :             error (0, unlink_errno, "%s", output_filename);
    1008             :         }
    1009             :       else
    1010             :         {
    1011          43 :           if (!suppress_count)
    1012             :             {
    1013             :               char buf[INT_BUFSIZE_BOUND (uintmax_t)];
    1014          43 :               fprintf (stdout, "%s\n", umaxtostr (bytes_written, buf));
    1015             :             }
    1016             :         }
    1017          43 :       output_stream = NULL;
    1018             :     }
    1019          47 : }
    1020             : 
    1021             : /* Save line LINE to the output file and
    1022             :    increment the character count for the current file. */
    1023             : 
    1024             : static void
    1025         133 : save_line_to_file (const struct cstring *line)
    1026             : {
    1027         133 :   fwrite (line->str, sizeof (char), line->len, output_stream);
    1028         133 :   bytes_written += line->len;
    1029         133 : }
    1030             : 
    1031             : /* Return a new, initialized control record. */
    1032             : 
    1033             : static struct control *
    1034          55 : new_control_record (void)
    1035             : {
    1036             :   static size_t control_allocated = 0; /* Total space allocated. */
    1037             :   struct control *p;
    1038             : 
    1039          55 :   if (control_used == control_allocated)
    1040          55 :     controls = X2NREALLOC (controls, &control_allocated);
    1041          55 :   p = &controls[control_used++];
    1042          55 :   p->regexpr = false;
    1043          55 :   p->repeat = 0;
    1044          55 :   p->repeat_forever = false;
    1045          55 :   p->lines_required = 0;
    1046          55 :   p->offset = 0;
    1047          55 :   return p;
    1048             : }
    1049             : 
    1050             : /* Check if there is a numeric offset after a regular expression.
    1051             :    STR is the entire command line argument.
    1052             :    P is the control record for this regular expression.
    1053             :    NUM is the numeric part of STR. */
    1054             : 
    1055             : static void
    1056           0 : check_for_offset (struct control *p, const char *str, const char *num)
    1057             : {
    1058           0 :   if (xstrtoimax (num, NULL, 10, &p->offset, "") != LONGINT_OK)
    1059           0 :     error (EXIT_FAILURE, 0, _("%s: integer expected after delimiter"), str);
    1060           0 : }
    1061             : 
    1062             : /* Given that the first character of command line arg STR is '{',
    1063             :    make sure that the rest of the string is a valid repeat count
    1064             :    and store its value in P.
    1065             :    ARGNUM is the ARGV index of STR. */
    1066             : 
    1067             : static void
    1068           2 : parse_repeat_count (int argnum, struct control *p, char *str)
    1069             : {
    1070             :   uintmax_t val;
    1071             :   char *end;
    1072             : 
    1073           2 :   end = str + strlen (str) - 1;
    1074           2 :   if (*end != '}')
    1075           1 :     error (EXIT_FAILURE, 0, _("%s: `}' is required in repeat count"), str);
    1076           1 :   *end = '\0';
    1077             : 
    1078           1 :   if (str+1 == end-1 && *(str+1) == '*')
    1079           0 :     p->repeat_forever = true;
    1080             :   else
    1081             :     {
    1082           1 :       if (xstrtoumax (str + 1, NULL, 10, &val, "") != LONGINT_OK)
    1083             :         {
    1084           1 :           error (EXIT_FAILURE, 0,
    1085             :                  _("%s}: integer required between `{' and `}'"),
    1086           1 :                  global_argv[argnum]);
    1087             :         }
    1088           0 :       p->repeat = val;
    1089             :     }
    1090             : 
    1091           0 :   *end = '}';
    1092           0 : }
    1093             : 
    1094             : /* Extract the regular expression from STR and check for a numeric offset.
    1095             :    STR should start with the regexp delimiter character.
    1096             :    Return a new control record for the regular expression.
    1097             :    ARGNUM is the ARGV index of STR.
    1098             :    Unless IGNORE is true, mark these lines for output. */
    1099             : 
    1100             : static struct control *
    1101          32 : extract_regexp (int argnum, bool ignore, char const *str)
    1102             : {
    1103             :   size_t len;                   /* Number of bytes in this regexp. */
    1104          32 :   char delim = *str;
    1105             :   char const *closing_delim;
    1106             :   struct control *p;
    1107             :   const char *err;
    1108             : 
    1109          32 :   closing_delim = strrchr (str + 1, delim);
    1110          32 :   if (closing_delim == NULL)
    1111           4 :     error (EXIT_FAILURE, 0,
    1112             :            _("%s: closing delimiter `%c' missing"), str, delim);
    1113             : 
    1114          28 :   len = closing_delim - str - 1;
    1115          28 :   p = new_control_record ();
    1116          28 :   p->argnum = argnum;
    1117          28 :   p->ignore = ignore;
    1118             : 
    1119          28 :   p->regexpr = true;
    1120          28 :   p->re_compiled.buffer = NULL;
    1121          28 :   p->re_compiled.allocated = 0;
    1122          28 :   p->re_compiled.fastmap = xmalloc (UCHAR_MAX + 1);
    1123          28 :   p->re_compiled.translate = NULL;
    1124          28 :   re_syntax_options =
    1125             :     RE_SYNTAX_POSIX_BASIC & ~RE_CONTEXT_INVALID_DUP & ~RE_NO_EMPTY_RANGES;
    1126          28 :   err = re_compile_pattern (str + 1, len, &p->re_compiled);
    1127          28 :   if (err)
    1128             :     {
    1129           0 :       error (0, 0, _("%s: invalid regular expression: %s"), str, err);
    1130           0 :       cleanup_fatal ();
    1131             :     }
    1132             : 
    1133          28 :   if (closing_delim[1])
    1134           0 :     check_for_offset (p, str, closing_delim + 1);
    1135             : 
    1136          28 :   return p;
    1137             : }
    1138             : 
    1139             : /* Extract the break patterns from args START through ARGC - 1 of ARGV.
    1140             :    After each pattern, check if the next argument is a repeat count. */
    1141             : 
    1142             : static void
    1143          54 : parse_patterns (int argc, int start, char **argv)
    1144             : {
    1145             :   int i;                        /* Index into ARGV. */
    1146             :   struct control *p;            /* New control record created. */
    1147             :   uintmax_t val;
    1148             :   static uintmax_t last_val = 0;
    1149             : 
    1150          83 :   for (i = start; i < argc; i++)
    1151             :     {
    1152          59 :       if (*argv[i] == '/' || *argv[i] == '%')
    1153             :         {
    1154          32 :           p = extract_regexp (i, *argv[i] == '%', argv[i]);
    1155             :         }
    1156             :       else
    1157             :         {
    1158          27 :           p = new_control_record ();
    1159          27 :           p->argnum = i;
    1160             : 
    1161          27 :           if (xstrtoumax (argv[i], NULL, 10, &val, "") != LONGINT_OK)
    1162          22 :             error (EXIT_FAILURE, 0, _("%s: invalid pattern"), argv[i]);
    1163           5 :           if (val == 0)
    1164           2 :             error (EXIT_FAILURE, 0,
    1165             :                    _("%s: line number must be greater than zero"),
    1166           2 :                    argv[i]);
    1167           3 :           if (val < last_val)
    1168             :             {
    1169             :               char buf[INT_BUFSIZE_BOUND (uintmax_t)];
    1170           0 :               error (EXIT_FAILURE, 0,
    1171             :                _("line number %s is smaller than preceding line number, %s"),
    1172           0 :                      quote (argv[i]), umaxtostr (last_val, buf));
    1173             :             }
    1174             : 
    1175           3 :           if (val == last_val)
    1176           0 :             error (0, 0,
    1177             :            _("warning: line number %s is the same as preceding line number"),
    1178           0 :                    quote (argv[i]));
    1179             : 
    1180           3 :           last_val = val;
    1181             : 
    1182           3 :           p->lines_required = val;
    1183             :         }
    1184             : 
    1185          31 :       if (i + 1 < argc && *argv[i + 1] == '{')
    1186             :         {
    1187             :           /* We have a repeat count. */
    1188           2 :           i++;
    1189           2 :           parse_repeat_count (i, p, argv[i]);
    1190             :         }
    1191             :     }
    1192          24 : }
    1193             : 
    1194             : static unsigned int
    1195          21 : get_format_flags (char **format_ptr)
    1196             : {
    1197          21 :   unsigned int count = 0;
    1198             : 
    1199          43 :   for (; **format_ptr; (*format_ptr)++)
    1200             :     {
    1201          38 :       switch (**format_ptr)
    1202             :         {
    1203          10 :         case '-':
    1204          10 :           break;
    1205             : 
    1206           8 :         case '+':
    1207             :         case ' ':
    1208           8 :           count |= 1;
    1209           8 :           break;
    1210             : 
    1211           4 :         case '#':
    1212           4 :           count |= 2;   /* Allow for 0x prefix preceding an `x' conversion.  */
    1213           4 :           break;
    1214             : 
    1215          16 :         default:
    1216          16 :           return count;
    1217             :         }
    1218             :     }
    1219           5 :   return count;
    1220             : }
    1221             : 
    1222             : static size_t
    1223          21 : get_format_width (char **format_ptr)
    1224             : {
    1225          21 :   unsigned long int val = 0;
    1226             : 
    1227          21 :   if (ISDIGIT (**format_ptr)
    1228          11 :       && (xstrtoul (*format_ptr, format_ptr, 10, &val, NULL) != LONGINT_OK
    1229             :           || SIZE_MAX < val))
    1230           0 :     error (EXIT_FAILURE, 0, _("invalid format width"));
    1231             : 
    1232             :   /* Allow for enough octal digits to represent the value of UINT_MAX,
    1233             :      even if the field width is less than that.  */
    1234          21 :   return MAX (val, (sizeof (unsigned int) * CHAR_BIT + 2) / 3);
    1235             : }
    1236             : 
    1237             : static size_t
    1238          21 : get_format_prec (char **format_ptr)
    1239             : {
    1240          21 :   if (**format_ptr != '.')
    1241          12 :     return 0;
    1242           9 :   (*format_ptr)++;
    1243             : 
    1244           9 :   if (! ISDIGIT (**format_ptr))
    1245           6 :     return 0;
    1246             :   else
    1247             :     {
    1248             :       unsigned long int val;
    1249           3 :       if (xstrtoul (*format_ptr, format_ptr, 10, &val, NULL) != LONGINT_OK
    1250             :           || SIZE_MAX < val)
    1251           0 :         error (EXIT_FAILURE, 0, _("invalid format precision"));
    1252           3 :       return val;
    1253             :     }
    1254             : }
    1255             : 
    1256             : static void
    1257          21 : get_format_conv_type (char **format_ptr)
    1258             : {
    1259          21 :   unsigned char ch = *(*format_ptr)++;
    1260             : 
    1261          21 :   switch (ch)
    1262             :     {
    1263           9 :     case 'd':
    1264             :     case 'i':
    1265             :     case 'o':
    1266             :     case 'u':
    1267             :     case 'x':
    1268             :     case 'X':
    1269           9 :       break;
    1270             : 
    1271           8 :     case 0:
    1272           8 :       error (EXIT_FAILURE, 0, _("missing conversion specifier in suffix"));
    1273           0 :       break;
    1274             : 
    1275           4 :     default:
    1276           4 :       if (isprint (ch))
    1277           2 :         error (EXIT_FAILURE, 0,
    1278             :                _("invalid conversion specifier in suffix: %c"), ch);
    1279             :       else
    1280           2 :         error (EXIT_FAILURE, 0,
    1281             :                _("invalid conversion specifier in suffix: \\%.3o"), ch);
    1282             :     }
    1283           9 : }
    1284             : 
    1285             : static size_t
    1286          24 : max_out (char *format)
    1287             : {
    1288          24 :   size_t out_count = 0;
    1289          24 :   bool percent = false;
    1290             : 
    1291          65 :   while (*format)
    1292             :     {
    1293          30 :       if (*format++ != '%')
    1294           1 :         out_count++;
    1295          29 :       else if (*format == '%')
    1296             :         {
    1297           7 :           format++;
    1298           7 :           out_count++;
    1299             :         }
    1300             :       else
    1301             :         {
    1302          22 :           if (percent)
    1303           1 :             error (EXIT_FAILURE, 0,
    1304             :                    _("too many %% conversion specifications in suffix"));
    1305          21 :           percent = true;
    1306          21 :           out_count += get_format_flags (&format);
    1307             :           {
    1308          21 :             size_t width = get_format_width (&format);
    1309          21 :             size_t prec = get_format_prec (&format);
    1310             : 
    1311          21 :             out_count += MAX (width, prec);
    1312             :           }
    1313          21 :           get_format_conv_type (&format);
    1314             :         }
    1315             :     }
    1316             : 
    1317          11 :   if (! percent)
    1318           3 :     error (EXIT_FAILURE, 0,
    1319             :            _("missing %% conversion specification in suffix"));
    1320             : 
    1321           8 :   return out_count;
    1322             : }
    1323             : 
    1324             : int
    1325         119 : main (int argc, char **argv)
    1326             : {
    1327             :   int optc;
    1328             :   unsigned long int val;
    1329             : 
    1330             :   initialize_main (&argc, &argv);
    1331         119 :   program_name = argv[0];
    1332         119 :   setlocale (LC_ALL, "");
    1333             :   bindtextdomain (PACKAGE, LOCALEDIR);
    1334             :   textdomain (PACKAGE);
    1335             : 
    1336         119 :   atexit (close_stdout);
    1337             : 
    1338         119 :   global_argv = argv;
    1339         119 :   controls = NULL;
    1340         119 :   control_used = 0;
    1341         119 :   suppress_count = false;
    1342         119 :   remove_files = true;
    1343         119 :   prefix = DEFAULT_PREFIX;
    1344             : 
    1345         278 :   while ((optc = getopt_long (argc, argv, "f:b:kn:sqz", longopts, NULL)) != -1)
    1346          58 :     switch (optc)
    1347             :       {
    1348           4 :       case 'f':
    1349           4 :         prefix = optarg;
    1350           4 :         break;
    1351             : 
    1352          25 :       case 'b':
    1353          25 :         suffix = optarg;
    1354          25 :         break;
    1355             : 
    1356           4 :       case 'k':
    1357           4 :         remove_files = false;
    1358           4 :         break;
    1359             : 
    1360           9 :       case 'n':
    1361           9 :         if (xstrtoul (optarg, NULL, 10, &val, "") != LONGINT_OK
    1362           2 :             || val > INT_MAX)
    1363           7 :           error (EXIT_FAILURE, 0, _("%s: invalid number"), optarg);
    1364           2 :         digits = val;
    1365           2 :         break;
    1366             : 
    1367           4 :       case 's':
    1368             :       case 'q':
    1369           4 :         suppress_count = true;
    1370           4 :         break;
    1371             : 
    1372           1 :       case 'z':
    1373           1 :         elide_empty_files = true;
    1374           1 :         break;
    1375             : 
    1376           1 :       case_GETOPT_HELP_CHAR;
    1377             : 
    1378           1 :       case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
    1379             : 
    1380           9 :       default:
    1381           9 :         usage (EXIT_FAILURE);
    1382             :       }
    1383             : 
    1384         101 :   if (argc - optind < 2)
    1385             :     {
    1386          26 :       if (argc <= optind)
    1387          11 :         error (0, 0, _("missing operand"));
    1388             :       else
    1389          15 :         error (0, 0, _("missing operand after %s"), quote (argv[argc - 1]));
    1390          26 :       usage (EXIT_FAILURE);
    1391             :     }
    1392             : 
    1393          75 :   if (suffix)
    1394          24 :     filename_space = xmalloc (strlen (prefix) + max_out (suffix) + 2);
    1395             :   else
    1396          51 :     filename_space = xmalloc (strlen (prefix) + digits + 2);
    1397             : 
    1398          59 :   set_input_file (argv[optind++]);
    1399             : 
    1400          54 :   parse_patterns (argc, optind, argv);
    1401             : 
    1402             :   {
    1403             :     int i;
    1404             :     static int const sig[] =
    1405             :       {
    1406             :         /* The usual suspects.  */
    1407             :         SIGALRM, SIGHUP, SIGINT, SIGPIPE, SIGQUIT, SIGTERM,
    1408             : #ifdef SIGPOLL
    1409             :         SIGPOLL,
    1410             : #endif
    1411             : #ifdef SIGPROF
    1412             :         SIGPROF,
    1413             : #endif
    1414             : #ifdef SIGVTALRM
    1415             :         SIGVTALRM,
    1416             : #endif
    1417             : #ifdef SIGXCPU
    1418             :         SIGXCPU,
    1419             : #endif
    1420             : #ifdef SIGXFSZ
    1421             :         SIGXFSZ,
    1422             : #endif
    1423             :       };
    1424             :     enum { nsigs = sizeof sig / sizeof sig[0] };
    1425             : 
    1426             : #if SA_NOCLDSTOP
    1427             :     struct sigaction act;
    1428             : 
    1429          24 :     sigemptyset (&caught_signals);
    1430         288 :     for (i = 0; i < nsigs; i++)
    1431             :       {
    1432         264 :         sigaction (sig[i], NULL, &act);
    1433         264 :         if (act.sa_handler != SIG_IGN)
    1434         264 :           sigaddset (&caught_signals, sig[i]);
    1435             :       }
    1436             : 
    1437          24 :     act.sa_handler = interrupt_handler;
    1438          24 :     act.sa_mask = caught_signals;
    1439          24 :     act.sa_flags = 0;
    1440             : 
    1441         288 :     for (i = 0; i < nsigs; i++)
    1442         264 :       if (sigismember (&caught_signals, sig[i]))
    1443         264 :         sigaction (sig[i], &act, NULL);
    1444             : #else
    1445             :     for (i = 0; i < nsigs; i++)
    1446             :       if (signal (sig[i], SIG_IGN) != SIG_IGN)
    1447             :         {
    1448             :           signal (sig[i], interrupt_handler);
    1449             :           siginterrupt (sig[i], 1);
    1450             :         }
    1451             : #endif
    1452             :   }
    1453             : 
    1454          24 :   split_file ();
    1455             : 
    1456          18 :   if (close (STDIN_FILENO) != 0)
    1457             :     {
    1458           0 :       error (0, errno, _("read error"));
    1459           0 :       cleanup_fatal ();
    1460             :     }
    1461             : 
    1462          18 :   exit (EXIT_SUCCESS);
    1463             : }
    1464             : 
    1465             : void
    1466          36 : usage (int status)
    1467             : {
    1468          36 :   if (status != EXIT_SUCCESS)
    1469          35 :     fprintf (stderr, _("Try `%s --help' for more information.\n"),
    1470             :              program_name);
    1471             :   else
    1472             :     {
    1473           1 :       printf (_("\
    1474             : Usage: %s [OPTION]... FILE PATTERN...\n\
    1475             : "),
    1476             :               program_name);
    1477           1 :       fputs (_("\
    1478             : Output pieces of FILE separated by PATTERN(s) to files `xx00', `xx01', ...,\n\
    1479             : and output byte counts of each piece to standard output.\n\
    1480             : \n\
    1481             : "), stdout);
    1482           1 :       fputs (_("\
    1483             : Mandatory arguments to long options are mandatory for short options too.\n\
    1484             : "), stdout);
    1485           1 :       fputs (_("\
    1486             :   -b, --suffix-format=FORMAT  use sprintf FORMAT instead of %02d\n\
    1487             :   -f, --prefix=PREFIX        use PREFIX instead of `xx'\n\
    1488             :   -k, --keep-files           do not remove output files on errors\n\
    1489             : "), stdout);
    1490           1 :       fputs (_("\
    1491             :   -n, --digits=DIGITS        use specified number of digits instead of 2\n\
    1492             :   -s, --quiet, --silent      do not print counts of output file sizes\n\
    1493             :   -z, --elide-empty-files    remove empty output files\n\
    1494             : "), stdout);
    1495           1 :       fputs (HELP_OPTION_DESCRIPTION, stdout);
    1496           1 :       fputs (VERSION_OPTION_DESCRIPTION, stdout);
    1497           1 :       fputs (_("\
    1498             : \n\
    1499             : Read standard input if FILE is -.  Each PATTERN may be:\n\
    1500             : "), stdout);
    1501           1 :       fputs (_("\
    1502             : \n\
    1503             :   INTEGER            copy up to but not including specified line number\n\
    1504             :   /REGEXP/[OFFSET]   copy up to but not including a matching line\n\
    1505             :   %REGEXP%[OFFSET]   skip to, but not including a matching line\n\
    1506             :   {INTEGER}          repeat the previous pattern specified number of times\n\
    1507             :   {*}                repeat the previous pattern as many times as possible\n\
    1508             : \n\
    1509             : A line OFFSET is a required `+' or `-' followed by a positive integer.\n\
    1510             : "), stdout);
    1511           1 :       emit_bug_reporting_address ();
    1512             :     }
    1513          36 :   exit (status);
    1514             : }

Generated by: LCOV version 1.10