/* head -- output first part of file(s)                                         This is the head utility
   Copyright (C) 1989-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
                                                                                
/* Options: (see usage)                                                         
   Reads from standard input if no files are given or when a filename of        
   ''-'' is encountered.                                                        
   By default, filename headers are printed only if more than one file          
   is given.                                                                    
   By default, prints the first 10 lines (head -n 10).                          
                                                                                
   David MacKenzie <djm@gnu.ai.mit.edu> */                                      
                                                                                
#include <config.h>                                                             Provides system specific information
                                                                                
#include <stdio.h>                                                              Provides standard I/O capability
#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 "full-read.h"                                                          ...!includes auto-comment...
#include "quote.h"                                                              ...!includes auto-comment...
#include "safe-read.h"                                                          ...!includes auto-comment...
#include "stat-size.h"                                                          ...!includes auto-comment...
#include "xbinary-io.h"                                                         ...!includes auto-comment...
#include "xdectoint.h"                                                          ...!includes auto-comment...
                                                                                
/* The official name of this program (e.g., no 'g' prefix).  */                 
#define PROGRAM_NAME "head"                                                     Line 44
                                                                                
#define AUTHORS \                                                               Line 46
  proper_name ("David MacKenzie"), \                                            Line 47
  proper_name ("Jim Meyering")                                                  Line 48
                                                                                
/* Number of lines/chars/blocks to head. */                                     
#define DEFAULT_NUMBER 10                                                       Line 51
                                                                                
/* Useful only when eliding tail bytes or lines.                                
   If true, skip the is-regular-file test used to determine whether             
   to use the lseek optimization.  Instead, use the more general (and           
   more expensive) code unconditionally. Intended solely for testing.  */       
static bool presume_input_pipe;                                                 Line 57
                                                                                
/* If true, print filename headers. */                                          
static bool print_headers;                                                      Line 60
                                                                                
/* Character to split lines by. */                                              
static char line_end;                                                           Line 63
                                                                                
/* When to print the filename banners. */                                       
enum header_mode                                                                Line 66
{                                                                               
  multiple_files, always, never                                                 Line 68
};                                                                              Block 1
                                                                                
/* Have we ever read standard input?  */                                        
static bool have_read_stdin;                                                    Line 72
                                                                                
enum Copy_fd_status                                                             Line 74
  {                                                                             
    COPY_FD_OK = 0,                                                             Line 76
    COPY_FD_READ_ERROR,                                                         Line 77
    COPY_FD_UNEXPECTED_EOF                                                      Line 78
  };                                                                            Block 2
                                                                                
/* 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 83
{                                                                               
  PRESUME_INPUT_PIPE_OPTION = CHAR_MAX + 1                                      Line 85
};                                                                              Block 3
                                                                                
static struct option const long_options[] =                                     Line 88
{                                                                               
  {"bytes", required_argument, NULL, 'c'},                                      Line 90
  {"lines", required_argument, NULL, 'n'},                                      Line 91
  {"-presume-input-pipe", no_argument, NULL,                                    Line 92
   PRESUME_INPUT_PIPE_OPTION}, /* do not document */                            Line 93
  {"quiet", no_argument, NULL, 'q'},                                            Line 94
  {"silent", no_argument, NULL, 'q'},                                           Line 95
  {"verbose", no_argument, NULL, 'v'},                                          Line 96
  {"zero-terminated", no_argument, NULL, 'z'},                                  Line 97
  {GETOPT_HELP_OPTION_DECL},                                                    Line 98
  {GETOPT_VERSION_OPTION_DECL},                                                 Line 99
  {NULL, 0, NULL, 0}                                                            Line 100
};                                                                              Block 4
                                                                                
void                                                                            Line 103
usage (int status)                                                              Line 104
{                                                                               
  if (status != EXIT_SUCCESS)                                                   Line 106
    emit_try_help ();                                                           ...!common auto-comment...
  else                                                                          Line 108
    {                                                                           
      printf (_("\                                                              Line 110
Usage: %s [OPTION]... [FILE]...\n\                                              Line 111
"),                                                                             Line 112
              program_name);                                                    Line 113
      printf (_("\                                                              Line 114
Print the first %d lines of each FILE to standard output.\n\                    Line 115
With more than one FILE, precede each with a header giving the file name.\n\    Line 116
"), DEFAULT_NUMBER);                                                            Line 117
                                                                                
      emit_stdin_note ();                                                       ...!common auto-comment...
      emit_mandatory_arg_note ();                                               ...!common auto-comment...
                                                                                
      printf (_("\                                                              Line 122
  -c, --bytes=[-]NUM       print the first NUM bytes of each file;\n\           Line 123
                             with the leading '-', print all but the last\n\    Line 124
                             NUM bytes of each file\n\                          Line 125
  -n, --lines=[-]NUM       print the first NUM lines instead of the first %d;\n\Line 126
                             with the leading '-', print all but the last\n\    Line 127
                             NUM lines of each file\n\                          Line 128
"), DEFAULT_NUMBER);                                                            Line 129
      fputs (_("\                                                               Line 130
  -q, --quiet, --silent    never print headers giving file names\n\             Line 131
  -v, --verbose            always print headers giving file names\n\            Line 132
"), stdout);                                                                    Line 133
      fputs (_("\                                                               Line 134
  -z, --zero-terminated    line delimiter is NUL, not newline\n\                Line 135
"), stdout);                                                                    Line 136
      fputs (HELP_OPTION_DESCRIPTION, stdout);                                  Line 137
      fputs (VERSION_OPTION_DESCRIPTION, stdout);                               Line 138
      fputs (_("\                                                               Line 139
\n\                                                                             
NUM may have a multiplier suffix:\n\                                            Line 141
b 512, kB 1000, K 1024, MB 1000*1000, M 1024*1024,\n\                           Line 142
GB 1000*1000*1000, G 1024*1024*1024, and so on for T, P, E, Z, Y.\n\            Line 143
Binary prefixes can be used, too: KiB=K, MiB=M, and so on.\n\                   Line 144
"), stdout);                                                                    Line 145
      emit_ancillary_info (PROGRAM_NAME);                                       Line 146
    }                                                                           
  exit (status);                                                                Line 148
}                                                                               Block 5
                                                                                
static void                                                                     Line 151
diagnose_copy_fd_failure (enum Copy_fd_status err, char const *filename)        Line 152
{                                                                               
  switch (err)                                                                  Line 154
    {                                                                           
    case COPY_FD_READ_ERROR:                                                    Line 156
      error (0, errno, _("error reading %s"), quoteaf (filename));              Line 157
      break;                                                                    Line 158
    case COPY_FD_UNEXPECTED_EOF:                                                Line 159
      error (0, errno, _("%s: file has shrunk too much"), quotef (filename));   Line 160
      break;                                                                    Line 161
    default:                                                                    Line 162
      abort ();                                                                 ...!common auto-comment...
    }                                                                           
}                                                                               Block 6
                                                                                
static void                                                                     Line 167
write_header (const char *filename)                                             Line 168
{                                                                               
  static bool first_file = true;                                                Line 170
                                                                                
  printf ("%s==> %s <==\n", (first_file ? "" : "\n"), filename);                Line 172
  first_file = false;                                                           Line 173
}                                                                               Block 7
                                                                                
/* Write N_BYTES from BUFFER to stdout.                                         
   Exit immediately on error with a single diagnostic.  */                      
                                                                                
static void                                                                     Line 179
xwrite_stdout (char const *buffer, size_t n_bytes)                              Line 180
{                                                                               
  if (n_bytes > 0 && fwrite (buffer, 1, n_bytes, stdout) < n_bytes)             Line 182...!syscalls auto-comment...
    {                                                                           
      clearerr (stdout); /* To avoid redundant close_stdout diagnostic.  */     Line 184
      die (EXIT_FAILURE, errno, _("error writing %s"),                          Line 185
           quoteaf ("standard output"));                                        Line 186
    }                                                                           
}                                                                               Block 8
                                                                                
/* Copy no more than N_BYTES from file descriptor SRC_FD to stdout.             
   Return an appropriate indication of success or read failure.  */             
                                                                                
static enum Copy_fd_status                                                      Line 193
copy_fd (int src_fd, uintmax_t n_bytes)                                         Line 194
{                                                                               
  char buf[BUFSIZ];                                                             Line 196
  const size_t buf_size = sizeof (buf);                                         Line 197
                                                                                
  /* Copy the file contents.  */                                                
  while (0 < n_bytes)                                                           Line 200
    {                                                                           
      size_t n_to_read = MIN (buf_size, n_bytes);                               Line 202
      size_t n_read = safe_read (src_fd, buf, n_to_read);                       Line 203...!syscalls auto-comment...
      if (n_read == SAFE_READ_ERROR)                                            Line 204
        return COPY_FD_READ_ERROR;                                              Line 205
                                                                                
      n_bytes -= n_read;                                                        Line 207
                                                                                
      if (n_read == 0 && n_bytes != 0)                                          Line 209
        return COPY_FD_UNEXPECTED_EOF;                                          Line 210
                                                                                
      xwrite_stdout (buf, n_read);                                              Line 212
    }                                                                           
                                                                                
  return COPY_FD_OK;                                                            Line 215
}                                                                               Block 9
                                                                                
/* Call lseek (FD, OFFSET, WHENCE), where file descriptor FD                    
   corresponds to the file FILENAME.  WHENCE must be SEEK_SET or                
   SEEK_CUR.  Return the resulting offset.  Give a diagnostic and               
   return -1 if lseek fails.  */                                                
                                                                                
static off_t                                                                    Line 223
elseek (int fd, off_t offset, int whence, char const *filename)                 Line 224
{                                                                               
  off_t new_offset = lseek (fd, offset, whence);                                Line 226
  char buf[INT_BUFSIZE_BOUND (offset)];                                         Line 227
                                                                                
  if (new_offset < 0)                                                           Line 229
    error (0, errno,                                                            Line 230
           _(whence == SEEK_SET                                                 Line 231
             ? N_("%s: cannot seek to offset %s")                               Line 232
             : N_("%s: cannot seek to relative offset %s")),                    Line 233
           quotef (filename),                                                   Line 234
           offtostr (offset, buf));                                             Line 235
                                                                                
  return new_offset;                                                            Line 237
}                                                                               Block 10
                                                                                
/* For an input file with name FILENAME and descriptor FD,                      
   output all but the last N_ELIDE_0 bytes.                                     
   If CURRENT_POS is nonnegative, assume that the input file is                 
   positioned at CURRENT_POS and that it should be repositioned to              
   just before the elided bytes before returning.                               
   Return true upon success.                                                    
   Give a diagnostic and return false upon error.  */                           
static bool                                                                     Line 247
elide_tail_bytes_pipe (const char *filename, int fd, uintmax_t n_elide_0,       Line 248
                       off_t current_pos)                                       Line 249
{                                                                               
  size_t n_elide = n_elide_0;                                                   Line 251
  uintmax_t desired_pos = current_pos;                                          Line 252
  bool ok = true;                                                               Line 253
                                                                                
#ifndef HEAD_TAIL_PIPE_READ_BUFSIZE                                             Line 255
# define HEAD_TAIL_PIPE_READ_BUFSIZE BUFSIZ                                     Line 256
#endif                                                                          Line 257
#define READ_BUFSIZE HEAD_TAIL_PIPE_READ_BUFSIZE                                Line 258
                                                                                
  /* If we're eliding no more than this many bytes, then it's ok to allocate    
     more memory in order to use a more time-efficient algorithm.               
     FIXME: use a fraction of available memory instead, as in sort.             
     FIXME: is this even worthwhile?  */                                        
#ifndef HEAD_TAIL_PIPE_BYTECOUNT_THRESHOLD                                      Line 264
# define HEAD_TAIL_PIPE_BYTECOUNT_THRESHOLD 1024 * 1024                         Line 265
#endif                                                                          Line 266
                                                                                
#if HEAD_TAIL_PIPE_BYTECOUNT_THRESHOLD < 2 * READ_BUFSIZE                       Line 268
  "HEAD_TAIL_PIPE_BYTECOUNT_THRESHOLD must be at least 2 * READ_BUFSIZE"        Line 269
#endif                                                                          Line 270
                                                                                
  if (SIZE_MAX < n_elide_0 + READ_BUFSIZE)                                      Line 272
    {                                                                           
      char umax_buf[INT_BUFSIZE_BOUND (n_elide_0)];                             Line 274
      die (EXIT_FAILURE, 0, _("%s: number of bytes is too large"),              Line 275
           umaxtostr (n_elide_0, umax_buf));                                    Line 276
    }                                                                           
                                                                                
  /* Two cases to consider...                                                   
     1) n_elide is small enough that we can afford to double-buffer:            
        allocate 2 * (READ_BUFSIZE + n_elide) bytes                             
     2) n_elide is too big for that, so we allocate only                        
        (READ_BUFSIZE + n_elide) bytes                                          
                                                                                
     FIXME: profile, to see if double-buffering is worthwhile                   
                                                                                
     CAUTION: do not fail (out of memory) when asked to elide                   
     a ridiculous amount, but when given only a small input.  */                
                                                                                
  if (n_elide <= HEAD_TAIL_PIPE_BYTECOUNT_THRESHOLD)                            Line 290
    {                                                                           
      bool first = true;                                                        Line 292
      bool eof = false;                                                         Line 293
      size_t n_to_read = READ_BUFSIZE + n_elide;                                Line 294
      bool i;                                                                   Line 295
      char *b[2];                                                               Line 296
      b[0] = xnmalloc (2, n_to_read);                                           Line 297
      b[1] = b[0] + n_to_read;                                                  Line 298
                                                                                
      for (i = false; ! eof ; i = !i)                                           Line 300
        {                                                                       
          size_t n_read = full_read (fd, b[i], n_to_read);                      Line 302...!syscalls auto-comment...
          size_t delta = 0;                                                     Line 303
          if (n_read < n_to_read)                                               Line 304
            {                                                                   
              if (errno != 0)                                                   Line 306
                {                                                               
                  error (0, errno, _("error reading %s"), quoteaf (filename));  Line 308
                  ok = false;                                                   Line 309
                  break;                                                        Line 310
                }                                                               
                                                                                
              /* reached EOF */                                                 
              if (n_read <= n_elide)                                            Line 314
                {                                                               
                  if (first)                                                    Line 316
                    {                                                           
                      /* The input is no larger than the number of bytes        
                         to elide.  So there's nothing to output, and           
                         we're done.  */                                        
                    }                                                           
                  else                                                          Line 322
                    {                                                           
                      delta = n_elide - n_read;                                 Line 324
                    }                                                           
                }                                                               
              eof = true;                                                       Line 327
            }                                                                   
                                                                                
          /* Output any (but maybe just part of the) elided data from           
             the previous round.  */                                            
          if (! first)                                                          Line 332
            {                                                                   
              desired_pos += n_elide - delta;                                   Line 334
              xwrite_stdout (b[!i] + READ_BUFSIZE, n_elide - delta);            Line 335
            }                                                                   
          first = false;                                                        Line 337
                                                                                
          if (n_elide < n_read)                                                 Line 339
            {                                                                   
              desired_pos += n_read - n_elide;                                  Line 341
              xwrite_stdout (b[i], n_read - n_elide);                           Line 342
            }                                                                   
        }                                                                       
                                                                                
      free (b[0]);                                                              Line 346
    }                                                                           
  else                                                                          Line 348
    {                                                                           
      /* Read blocks of size READ_BUFSIZE, until we've read at least n_elide    
         bytes.  Then, for each new buffer we read, also write an old one.  */  
                                                                                
      bool eof = false;                                                         Line 353
      size_t n_read;                                                            Line 354
      bool buffered_enough;                                                     Line 355
      size_t i, i_next;                                                         Line 356
      char **b = NULL;                                                          Line 357
      /* Round n_elide up to a multiple of READ_BUFSIZE.  */                    
      size_t rem = READ_BUFSIZE - (n_elide % READ_BUFSIZE);                     Line 359
      size_t n_elide_round = n_elide + rem;                                     Line 360
      size_t n_bufs = n_elide_round / READ_BUFSIZE + 1;                         Line 361
      size_t n_alloc = 0;                                                       Line 362
      size_t n_array_alloc = 0;                                                 Line 363
                                                                                
      buffered_enough = false;                                                  Line 365
      for (i = 0, i_next = 1; !eof; i = i_next, i_next = (i_next + 1) % n_bufs) Line 366
        {                                                                       
          if (n_array_alloc == i)                                               Line 368
            {                                                                   
              /* reallocate between 16 and n_bufs entries.  */                  
              if (n_array_alloc == 0)                                           Line 371
                n_array_alloc = MIN (n_bufs, 16);                               Line 372
              else if (n_array_alloc <= n_bufs / 2)                             Line 373
                n_array_alloc *= 2;                                             Line 374
              else                                                              Line 375
                n_array_alloc = n_bufs;                                         Line 376
              b = xnrealloc (b, n_array_alloc, sizeof *b);                      Line 377
            }                                                                   
                                                                                
          if (! buffered_enough)                                                Line 380
            {                                                                   
              b[i] = xmalloc (READ_BUFSIZE);                                    Line 382
              n_alloc = i + 1;                                                  Line 383
            }                                                                   
          n_read = full_read (fd, b[i], READ_BUFSIZE);                          Line 385...!syscalls auto-comment...
          if (n_read < READ_BUFSIZE)                                            Line 386
            {                                                                   
              if (errno != 0)                                                   Line 388
                {                                                               
                  error (0, errno, _("error reading %s"), quoteaf (filename));  Line 390
                  ok = false;                                                   Line 391
                  goto free_mem;                                                Line 392
                }                                                               
              eof = true;                                                       Line 394
            }                                                                   
                                                                                
          if (i + 1 == n_bufs)                                                  Line 397
            buffered_enough = true;                                             Line 398
                                                                                
          if (buffered_enough)                                                  Line 400
            {                                                                   
              desired_pos += n_read;                                            Line 402
              xwrite_stdout (b[i_next], n_read);                                Line 403
            }                                                                   
        }                                                                       
                                                                                
      /* Output any remainder: rem bytes from b[i] + n_read.  */                
      if (rem)                                                                  Line 408
        {                                                                       
          if (buffered_enough)                                                  Line 410
            {                                                                   
              size_t n_bytes_left_in_b_i = READ_BUFSIZE - n_read;               Line 412
              desired_pos += rem;                                               Line 413
              if (rem < n_bytes_left_in_b_i)                                    Line 414
                {                                                               
                  xwrite_stdout (b[i] + n_read, rem);                           Line 416
                }                                                               
              else                                                              Line 418
                {                                                               
                  xwrite_stdout (b[i] + n_read, n_bytes_left_in_b_i);           Line 420
                  xwrite_stdout (b[i_next], rem - n_bytes_left_in_b_i);         Line 421
                }                                                               
            }                                                                   
          else if (i + 1 == n_bufs)                                             Line 424
            {                                                                   
              /* This happens when n_elide < file_size < n_elide_round.         
                                                                                
                 |READ_BUF.|                                                    
                 |                      |  rem |                                
                 |---------!---------!---------!---------|                      
                 |---- n_elide ---------|                                       
                 |                      | x |                                   
                 |                   |y |                                       
                 |---- file size -----------|                                   
                 |                   |n_read|                                   
                 |---- n_elide_round ----------|                                
               */                                                               
              size_t y = READ_BUFSIZE - rem;                                    Line 438
              size_t x = n_read - y;                                            Line 439
              desired_pos += x;                                                 Line 440
              xwrite_stdout (b[i_next], x);                                     Line 441
            }                                                                   
        }                                                                       
                                                                                
    free_mem:                                                                   Line 445
      for (i = 0; i < n_alloc; i++)                                             Line 446
        free (b[i]);                                                            Line 447
      free (b);                                                                 Line 448
    }                                                                           
                                                                                
  if (0 <= current_pos && elseek (fd, desired_pos, SEEK_SET, filename) < 0)     Line 451
    ok = false;                                                                 Line 452
  return ok;                                                                    Line 453
}                                                                               Block 11
                                                                                
/* For the file FILENAME with descriptor FD, output all but the last N_ELIDE    
   bytes.  If SIZE is nonnegative, this is a regular file positioned            
   at CURRENT_POS with SIZE bytes.  Return true on success.                     
   Give a diagnostic and return false upon error.  */                           
                                                                                
/* NOTE: if the input file shrinks by more than N_ELIDE bytes between           
   the length determination and the actual reading, then head fails.  */        
                                                                                
static bool                                                                     Line 464
elide_tail_bytes_file (const char *filename, int fd, uintmax_t n_elide,         Line 465
                       struct stat const *st, off_t current_pos)                Line 466
{                                                                               
  off_t size = st->st_size;                                                     Line 468
  if (presume_input_pipe || current_pos < 0 || size <= ST_BLKSIZE (*st))        Line 469
    return elide_tail_bytes_pipe (filename, fd, n_elide, current_pos);          Line 470
  else                                                                          Line 471
    {                                                                           
      /* Be careful here.  The current position may actually be                 
         beyond the end of the file.  */                                        
      off_t diff = size - current_pos;                                          Line 475
      off_t bytes_remaining = diff < 0 ? 0 : diff;                              Line 476
                                                                                
      if (bytes_remaining <= n_elide)                                           Line 478
        return true;                                                            Line 479
                                                                                
      enum Copy_fd_status err = copy_fd (fd, bytes_remaining - n_elide);        Line 481
      if (err == COPY_FD_OK)                                                    Line 482
        return true;                                                            Line 483
                                                                                
      diagnose_copy_fd_failure (err, filename);                                 Line 485
      return false;                                                             Line 486
    }                                                                           
}                                                                               Block 12
                                                                                
/* For an input file with name FILENAME and descriptor FD,                      
   output all but the last N_ELIDE_0 bytes.                                     
   If CURRENT_POS is nonnegative, the input file is positioned there            
   and should be repositioned to just before the elided bytes.                  
   Buffer the specified number of lines as a linked list of LBUFFERs,           
   adding them as needed.  Return true if successful.  */                       
                                                                                
static bool                                                                     Line 497
elide_tail_lines_pipe (const char *filename, int fd, uintmax_t n_elide,         Line 498
                       off_t current_pos)                                       Line 499
{                                                                               
  struct linebuffer                                                             Line 501
  {                                                                             
    char buffer[BUFSIZ];                                                        Line 503
    size_t nbytes;                                                              Line 504
    size_t nlines;                                                              Line 505
    struct linebuffer *next;                                                    Line 506
  };                                                                            
  uintmax_t desired_pos = current_pos;                                          Line 508
  typedef struct linebuffer LBUFFER;                                            Line 509
  LBUFFER *first, *last, *tmp;                                                  Line 510
  size_t total_lines = 0; /* Total number of newlines in all buffers.  */       Line 511
  bool ok = true;                                                               Line 512
  size_t n_read;  /* Size in bytes of most recent read */                       Line 513
                                                                                
  first = last = xmalloc (sizeof (LBUFFER));                                    Line 515
  first->nbytes = first->nlines = 0;                                            Line 516
  first->next = NULL;                                                           Line 517
  tmp = xmalloc (sizeof (LBUFFER));                                             Line 518
                                                                                
  /* Always read into a fresh buffer.                                           
     Read, (producing no output) until we've accumulated at least               
     n_elide newlines, or until EOF, whichever comes first.  */                 
  while (1)                                                                     Line 523
    {                                                                           
      n_read = safe_read (fd, tmp->buffer, BUFSIZ);                             Line 525...!syscalls auto-comment...
      if (n_read == 0 || n_read == SAFE_READ_ERROR)                             Line 526
        break;                                                                  Line 527
                                                                                
      if (! n_elide)                                                            Line 529
        {                                                                       
          desired_pos += n_read;                                                Line 531
          xwrite_stdout (tmp->buffer, n_read);                                  Line 532
          continue;                                                             Line 533
        }                                                                       
                                                                                
      tmp->nbytes = n_read;                                                     Line 536
      tmp->nlines = 0;                                                          Line 537
      tmp->next = NULL;                                                         Line 538
                                                                                
      /* Count the number of newlines just read.  */                            
      {                                                                         
        char const *buffer_end = tmp->buffer + n_read;                          Line 542
        char const *p = tmp->buffer;                                            Line 543
        while ((p = memchr (p, line_end, buffer_end - p)))                      Line 544
          {                                                                     
            ++p;                                                                Line 546
            ++tmp->nlines;                                                      Line 547
          }                                                                     
      }                                                                         
      total_lines += tmp->nlines;                                               Line 550
                                                                                
      /* If there is enough room in the last buffer read, just append the new   
         one to it.  This is because when reading from a pipe, 'n_read' can     
         often be very small.  */                                               
      if (tmp->nbytes + last->nbytes < BUFSIZ)                                  Line 555
        {                                                                       
          memcpy (&last->buffer[last->nbytes], tmp->buffer, tmp->nbytes);       Line 557
          last->nbytes += tmp->nbytes;                                          Line 558
          last->nlines += tmp->nlines;                                          Line 559
        }                                                                       
      else                                                                      Line 561
        {                                                                       
          /* If there's not enough room, link the new buffer onto the end of    
             the list, then either free up the oldest buffer for the next       
             read if that would leave enough lines, or else malloc a new one.   
             Some compaction mechanism is possible but probably not             
             worthwhile.  */                                                    
          last = last->next = tmp;                                              Line 568
          if (n_elide < total_lines - first->nlines)                            Line 569
            {                                                                   
              desired_pos += first->nbytes;                                     Line 571
              xwrite_stdout (first->buffer, first->nbytes);                     Line 572
              tmp = first;                                                      Line 573
              total_lines -= first->nlines;                                     Line 574
              first = first->next;                                              Line 575
            }                                                                   
          else                                                                  Line 577
            tmp = xmalloc (sizeof (LBUFFER));                                   Line 578
        }                                                                       
    }                                                                           
                                                                                
  free (tmp);                                                                   Line 582
                                                                                
  if (n_read == SAFE_READ_ERROR)                                                Line 584
    {                                                                           
      error (0, errno, _("error reading %s"), quoteaf (filename));              Line 586
      ok = false;                                                               Line 587
      goto free_lbuffers;                                                       Line 588
    }                                                                           
                                                                                
  /* If we read any bytes at all, count the incomplete line                     
     on files that don't end with a newline.  */                                
  if (last->nbytes && last->buffer[last->nbytes - 1] != line_end)               Line 593
    {                                                                           
      ++last->nlines;                                                           Line 595
      ++total_lines;                                                            Line 596
    }                                                                           
                                                                                
  for (tmp = first; n_elide < total_lines - tmp->nlines; tmp = tmp->next)       Line 599
    {                                                                           
      desired_pos += tmp->nbytes;                                               Line 601
      xwrite_stdout (tmp->buffer, tmp->nbytes);                                 Line 602
      total_lines -= tmp->nlines;                                               Line 603
    }                                                                           
                                                                                
  /* Print the first 'total_lines - n_elide' lines of tmp->buffer.  */          
  if (n_elide < total_lines)                                                    Line 607
    {                                                                           
      size_t n = total_lines - n_elide;                                         Line 609
      char const *buffer_end = tmp->buffer + tmp->nbytes;                       Line 610
      char const *p = tmp->buffer;                                              Line 611
      while (n && (p = memchr (p, line_end, buffer_end - p)))                   Line 612
        {                                                                       
          ++p;                                                                  Line 614
          ++tmp->nlines;                                                        Line 615
          --n;                                                                  Line 616
        }                                                                       
      desired_pos += p - tmp->buffer;                                           Line 618
      xwrite_stdout (tmp->buffer, p - tmp->buffer);                             Line 619
    }                                                                           
                                                                                
free_lbuffers:                                                                  Line 622
  while (first)                                                                 Line 623
    {                                                                           
      tmp = first->next;                                                        Line 625
      free (first);                                                             Line 626
      first = tmp;                                                              Line 627
    }                                                                           
                                                                                
  if (0 <= current_pos && elseek (fd, desired_pos, SEEK_SET, filename) < 0)     Line 630
    ok = false;                                                                 Line 631
  return ok;                                                                    Line 632
}                                                                               Block 13
                                                                                
/* Output all but the last N_LINES lines of the input stream defined by         
   FD, START_POS, and SIZE.                                                     
   START_POS is the starting position of the read pointer for the file          
   associated with FD (may be nonzero).                                         
   SIZE is the file size in bytes.                                              
   Return true upon success.                                                    
   Give a diagnostic and return false upon error.                               
                                                                                
   NOTE: this code is very similar to that of tail.c's file_lines function.     
   Unfortunately, factoring out some common core looks like it'd result         
   in a less efficient implementation or a messy interface.  */                 
static bool                                                                     Line 646
elide_tail_lines_seekable (const char *pretty_filename, int fd,                 Line 647
                           uintmax_t n_lines,                                   Line 648
                           off_t start_pos, off_t size)                         Line 649
{                                                                               
  char buffer[BUFSIZ];                                                          Line 651
  size_t bytes_read;                                                            Line 652
  off_t pos = size;                                                             Line 653
                                                                                
  /* Set 'bytes_read' to the size of the last, probably partial, buffer;        
     0 < 'bytes_read' <= 'BUFSIZ'.  */                                          
  bytes_read = (pos - start_pos) % BUFSIZ;                                      Line 657
  if (bytes_read == 0)                                                          Line 658
    bytes_read = BUFSIZ;                                                        Line 659
  /* Make 'pos' a multiple of 'BUFSIZ' (0 if the file is short), so that all    
     reads will be on block boundaries, which might increase efficiency.  */    
  pos -= bytes_read;                                                            Line 662
  if (elseek (fd, pos, SEEK_SET, pretty_filename) < 0)                          Line 663
    return false;                                                               Line 664
  bytes_read = safe_read (fd, buffer, bytes_read);                              Line 665...!syscalls auto-comment...
  if (bytes_read == SAFE_READ_ERROR)                                            Line 666
    {                                                                           
      error (0, errno, _("error reading %s"), quoteaf (pretty_filename));       Line 668
      return false;                                                             Line 669
    }                                                                           
                                                                                
  /* n_lines == 0 case needs special treatment. */                              
  const bool all_lines = !n_lines;                                              Line 673
                                                                                
  /* Count the incomplete line on files that don't end with a newline.  */      
  if (n_lines && bytes_read && buffer[bytes_read - 1] != line_end)              Line 676
    --n_lines;                                                                  Line 677
                                                                                
  while (1)                                                                     Line 679
    {                                                                           
      /* Scan backward, counting the newlines in this bufferfull.  */           
                                                                                
      size_t n = bytes_read;                                                    Line 683
      while (n)                                                                 Line 684
        {                                                                       
          if (all_lines)                                                        Line 686
            n -= 1;                                                             Line 687
          else                                                                  Line 688
            {                                                                   
              char const *nl;                                                   Line 690
              nl = memrchr (buffer, line_end, n);                               Line 691
              if (nl == NULL)                                                   Line 692
                break;                                                          Line 693
              n = nl - buffer;                                                  Line 694
            }                                                                   
          if (n_lines-- == 0)                                                   Line 696
            {                                                                   
              /* Found it.  */                                                  
              /* If necessary, restore the file pointer and copy                
                 input to output up to position, POS.  */                       
              if (start_pos < pos)                                              Line 701
                {                                                               
                  enum Copy_fd_status err;                                      Line 703
                  if (elseek (fd, start_pos, SEEK_SET, pretty_filename) < 0)    Line 704
                    return false;                                               Line 705
                                                                                
                  err = copy_fd (fd, pos - start_pos);                          Line 707
                  if (err != COPY_FD_OK)                                        Line 708
                    {                                                           
                      diagnose_copy_fd_failure (err, pretty_filename);          Line 710
                      return false;                                             Line 711
                    }                                                           
                }                                                               
                                                                                
              /* Output the initial portion of the buffer                       
                 in which we found the desired newline byte.  */                
              xwrite_stdout (buffer, n + 1);                                    Line 717
                                                                                
              /* Set file pointer to the byte after what we've output.  */      
              return 0 <= elseek (fd, pos + n + 1, SEEK_SET, pretty_filename);  Line 720
            }                                                                   
        }                                                                       
                                                                                
      /* Not enough newlines in that bufferfull.  */                            
      if (pos == start_pos)                                                     Line 725
        {                                                                       
          /* Not enough lines in the file.  */                                  
          return true;                                                          Line 728
        }                                                                       
      pos -= BUFSIZ;                                                            Line 730
      if (elseek (fd, pos, SEEK_SET, pretty_filename) < 0)                      Line 731
        return false;                                                           Line 732
                                                                                
      bytes_read = safe_read (fd, buffer, BUFSIZ);                              Line 734...!syscalls auto-comment...
      if (bytes_read == SAFE_READ_ERROR)                                        Line 735
        {                                                                       
          error (0, errno, _("error reading %s"), quoteaf (pretty_filename));   Line 737
          return false;                                                         Line 738
        }                                                                       
                                                                                
      /* FIXME: is this dead code?                                              
         Consider the test, pos == start_pos, above. */                         
      if (bytes_read == 0)                                                      Line 743
        return true;                                                            Line 744
    }                                                                           
}                                                                               Block 14
                                                                                
/* For the file FILENAME with descriptor FD, output all but the last N_ELIDE    
   lines.  If SIZE is nonnegative, this is a regular file positioned            
   at START_POS with SIZE bytes.  Return true on success.                       
   Give a diagnostic and return nonzero upon error.  */                         
                                                                                
static bool                                                                     Line 753
elide_tail_lines_file (const char *filename, int fd, uintmax_t n_elide,         Line 754
                       struct stat const *st, off_t current_pos)                Line 755
{                                                                               
  off_t size = st->st_size;                                                     Line 757
  if (presume_input_pipe || current_pos < 0 || size <= ST_BLKSIZE (*st))        Line 758
    return elide_tail_lines_pipe (filename, fd, n_elide, current_pos);          Line 759
  else                                                                          Line 760
    {                                                                           
      /* Find the offset, OFF, of the Nth newline from the end,                 
         but not counting the last byte of the file.                            
         If found, write from current position to OFF, inclusive.               
         Otherwise, just return true.  */                                       
                                                                                
      return (size <= current_pos                                               Line 767
              || elide_tail_lines_seekable (filename, fd, n_elide,              Line 768
                                            current_pos, size));                Line 769
    }                                                                           
}                                                                               Block 15
                                                                                
static bool                                                                     Line 773
head_bytes (const char *filename, int fd, uintmax_t bytes_to_write)             Line 774
{                                                                               
  char buffer[BUFSIZ];                                                          Line 776
  size_t bytes_to_read = BUFSIZ;                                                Line 777
                                                                                
  while (bytes_to_write)                                                        Line 779
    {                                                                           
      size_t bytes_read;                                                        Line 781
      if (bytes_to_write < bytes_to_read)                                       Line 782
        bytes_to_read = bytes_to_write;                                         Line 783
      bytes_read = safe_read (fd, buffer, bytes_to_read);                       Line 784...!syscalls auto-comment...
      if (bytes_read == SAFE_READ_ERROR)                                        Line 785
        {                                                                       
          error (0, errno, _("error reading %s"), quoteaf (filename));          Line 787
          return false;                                                         Line 788
        }                                                                       
      if (bytes_read == 0)                                                      Line 790
        break;                                                                  Line 791
      xwrite_stdout (buffer, bytes_read);                                       Line 792
      bytes_to_write -= bytes_read;                                             Line 793
    }                                                                           
  return true;                                                                  Line 795
}                                                                               Block 16
                                                                                
static bool                                                                     Line 798
head_lines (const char *filename, int fd, uintmax_t lines_to_write)             Line 799
{                                                                               
  char buffer[BUFSIZ];                                                          Line 801
                                                                                
  while (lines_to_write)                                                        Line 803
    {                                                                           
      size_t bytes_read = safe_read (fd, buffer, BUFSIZ);                       Line 805...!syscalls auto-comment...
      size_t bytes_to_write = 0;                                                Line 806
                                                                                
      if (bytes_read == SAFE_READ_ERROR)                                        Line 808
        {                                                                       
          error (0, errno, _("error reading %s"), quoteaf (filename));          Line 810
          return false;                                                         Line 811
        }                                                                       
      if (bytes_read == 0)                                                      Line 813
        break;                                                                  Line 814
      while (bytes_to_write < bytes_read)                                       Line 815
        if (buffer[bytes_to_write++] == line_end && --lines_to_write == 0)      Line 816
          {                                                                     
            off_t n_bytes_past_EOL = bytes_read - bytes_to_write;               Line 818
            /* If we have read more data than that on the specified number      
               of lines, try to seek back to the position we would have         
               gotten to had we been reading one byte at a time.  */            
            if (lseek (fd, -n_bytes_past_EOL, SEEK_CUR) < 0)                    Line 822
              {                                                                 
                struct stat st;                                                 Line 824
                if (fstat (fd, &st) != 0 || S_ISREG (st.st_mode))               Line 825...!syscalls auto-comment......!syscalls auto-comment...
                  elseek (fd, -n_bytes_past_EOL, SEEK_CUR, filename);           Line 826
              }                                                                 
            break;                                                              Line 828
          }                                                                     
      xwrite_stdout (buffer, bytes_to_write);                                   Line 830
    }                                                                           
  return true;                                                                  Line 832
}                                                                               Block 17
                                                                                
static bool                                                                     Line 835
head (const char *filename, int fd, uintmax_t n_units, bool count_lines,        Line 836
      bool elide_from_end)                                                      Line 837
{                                                                               
  if (print_headers)                                                            Line 839
    write_header (filename);                                                    Line 840
                                                                                
  if (elide_from_end)                                                           Line 842
    {                                                                           
      off_t current_pos = -1;                                                   Line 844
      struct stat st;                                                           Line 845
      if (fstat (fd, &st) != 0)                                                 Line 846...!syscalls auto-comment......!syscalls auto-comment...
        {                                                                       
          error (0, errno, _("cannot fstat %s"),                                Line 848
                 quoteaf (filename));                                           Line 849
          return false;                                                         Line 850
        }                                                                       
      if (! presume_input_pipe && usable_st_size (&st))                         Line 852
        {                                                                       
          current_pos = elseek (fd, 0, SEEK_CUR, filename);                     Line 854
          if (current_pos < 0)                                                  Line 855
            return false;                                                       Line 856
        }                                                                       
      if (count_lines)                                                          Line 858
        return elide_tail_lines_file (filename, fd, n_units, &st, current_pos); Line 859
      else                                                                      Line 860
        return elide_tail_bytes_file (filename, fd, n_units, &st, current_pos); Line 861
    }                                                                           
  if (count_lines)                                                              Line 863
    return head_lines (filename, fd, n_units);                                  Line 864
  else                                                                          Line 865
    return head_bytes (filename, fd, n_units);                                  Line 866
}                                                                               Block 18
                                                                                
static bool                                                                     Line 869
head_file (const char *filename, uintmax_t n_units, bool count_lines,           Line 870
           bool elide_from_end)                                                 Line 871
{                                                                               
  int fd;                                                                       Line 873
  bool ok;                                                                      Line 874
  bool is_stdin = STREQ (filename, "-");                                        Line 875
                                                                                
  if (is_stdin)                                                                 Line 877
    {                                                                           
      have_read_stdin = true;                                                   Line 879
      fd = STDIN_FILENO;                                                        Line 880
      filename = _("standard input");                                           Line 881
      xset_binary_mode (STDIN_FILENO, O_BINARY);                                Line 882
    }                                                                           
  else                                                                          Line 884
    {                                                                           
      fd = open (filename, O_RDONLY | O_BINARY);                                Line 886...!syscalls auto-comment...
      if (fd < 0)                                                               Line 887
        {                                                                       
          error (0, errno, _("cannot open %s for reading"), quoteaf (filename));Line 889
          return false;                                                         Line 890
        }                                                                       
    }                                                                           
                                                                                
  ok = head (filename, fd, n_units, count_lines, elide_from_end);               Line 894
  if (!is_stdin && close (fd) != 0)                                             Line 895...!syscalls auto-comment...
    {                                                                           
      error (0, errno, _("failed to close %s"), quoteaf (filename));            Line 897
      return false;                                                             Line 898
    }                                                                           
  return ok;                                                                    Line 900
}                                                                               Block 19
                                                                                
/* Convert a string of decimal digits, N_STRING, with an optional suffix        
   to an integral value.  Upon successful conversion,                           
   return that value.  If it cannot be converted, give a diagnostic and exit.   
   COUNT_LINES indicates whether N_STRING is a number of bytes or a number      
   of lines.  It is used solely to give a more specific diagnostic.  */         
                                                                                
static uintmax_t                                                                Line 909
string_to_integer (bool count_lines, const char *n_string)                      Line 910
{                                                                               
  return xdectoumax (n_string, 0, UINTMAX_MAX, "bkKmMGTPEZY0",                  Line 912
                     count_lines ? _("invalid number of lines")                 Line 913
                                 : _("invalid number of bytes"), 0);            Line 914
}                                                                               Block 20
                                                                                
int                                                                             
main (int argc, char **argv)                                                    Line 918
{                                                                               
  enum header_mode header_mode = multiple_files;                                Line 920
  bool ok = true;                                                               Line 921
  int c;                                                                        Line 922
  size_t i;                                                                     Line 923
                                                                                
  /* Number of items to print. */                                               
  uintmax_t n_units = DEFAULT_NUMBER;                                           Line 926
                                                                                
  /* If true, interpret the numeric argument as the number of lines.            
     Otherwise, interpret it as the number of bytes.  */                        
  bool count_lines = true;                                                      Line 930
                                                                                
  /* Elide the specified number of lines or bytes, counting from                
     the end of the file.  */                                                   
  bool elide_from_end = false;                                                  Line 934
                                                                                
  /* Initializer for file_list if no file-arguments                             
     were specified on the command line.  */                                    
  static char const *const default_file_list[] = {"-", NULL};                   Line 938
  char const *const *file_list;                                                 Line 939
                                                                                
  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)
                                                                                
  have_read_stdin = false;                                                      Line 949
                                                                                
  print_headers = false;                                                        Line 951
                                                                                
  line_end = '\n';                                                              Line 953
                                                                                
  if (1 < argc && argv[1][0] == '-' && ISDIGIT (argv[1][1]))                    Line 955
    {                                                                           
      char *a = argv[1];                                                        Line 957
      char *n_string = ++a;                                                     Line 958
      char *end_n_string;                                                       Line 959
      char multiplier_char = 0;                                                 Line 960
                                                                                
      /* Old option syntax; a dash, one or more digits, and one or              
         more option letters.  Move past the number. */                         
      do ++a;                                                                   Line 964
      while (ISDIGIT (*a));                                                     Line 965
                                                                                
      /* Pointer to the byte after the last digit.  */                          
      end_n_string = a;                                                         Line 968
                                                                                
      /* Parse any appended option letters. */                                  
      for (; *a; a++)                                                           Line 971
        {                                                                       
          switch (*a)                                                           Line 973
            {                                                                   
            case 'c':                                                           Line 975
              count_lines = false;                                              Line 976
              multiplier_char = 0;                                              Line 977
              break;                                                            Line 978
                                                                                
            case 'b':                                                           Line 980
            case 'k':                                                           Line 981
            case 'm':                                                           Line 982
              count_lines = false;                                              Line 983
              multiplier_char = *a;                                             Line 984
              break;                                                            Line 985
                                                                                
            case 'l':                                                           Line 987
              count_lines = true;                                               Line 988
              break;                                                            Line 989
                                                                                
            case 'q':                                                           Line 991
              header_mode = never;                                              Line 992
              break;                                                            Line 993
                                                                                
            case 'v':                                                           Line 995
              header_mode = always;                                             Line 996
              break;                                                            Line 997
                                                                                
            case 'z':                                                           Line 999
              line_end = '\0';                                                  Line 1000
              break;                                                            Line 1001
                                                                                
            default:                                                            Line 1003
              error (0, 0, _("invalid trailing option -- %c"), *a);             Line 1004
              usage (EXIT_FAILURE);                                             Line 1005
            }                                                                   
        }                                                                       
                                                                                
      /* Append the multiplier character (if any) onto the end of               
         the digit string.  Then add NUL byte if necessary.  */                 
      *end_n_string = multiplier_char;                                          Line 1011
      if (multiplier_char)                                                      Line 1012
        *(++end_n_string) = 0;                                                  Line 1013
                                                                                
      n_units = string_to_integer (count_lines, n_string);                      Line 1015
                                                                                
      /* Make the options we just parsed invisible to getopt. */                
      argv[1] = argv[0];                                                        Line 1018
      argv++;                                                                   Line 1019
      argc--;                                                                   Line 1020
    }                                                                           
                                                                                
  while ((c = getopt_long (argc, argv, "c:n:qvz0123456789", long_options, NULL))Line 1023
         != -1)                                                                 Line 1024
    {                                                                           
      switch (c)                                                                Line 1026
        {                                                                       
        case PRESUME_INPUT_PIPE_OPTION:                                         Line 1028
          presume_input_pipe = true;                                            Line 1029
          break;                                                                Line 1030
                                                                                
        case 'c':                                                               Line 1032
          count_lines = false;                                                  Line 1033
          elide_from_end = (*optarg == '-');                                    Line 1034
          if (elide_from_end)                                                   Line 1035
            ++optarg;                                                           Line 1036
          n_units = string_to_integer (count_lines, optarg);                    Line 1037
          break;                                                                Line 1038
                                                                                
        case 'n':                                                               Line 1040
          count_lines = true;                                                   Line 1041
          elide_from_end = (*optarg == '-');                                    Line 1042
          if (elide_from_end)                                                   Line 1043
            ++optarg;                                                           Line 1044
          n_units = string_to_integer (count_lines, optarg);                    Line 1045
          break;                                                                Line 1046
                                                                                
        case 'q':                                                               Line 1048
          header_mode = never;                                                  Line 1049
          break;                                                                Line 1050
                                                                                
        case 'v':                                                               Line 1052
          header_mode = always;                                                 Line 1053
          break;                                                                Line 1054
                                                                                
        case 'z':                                                               Line 1056
          line_end = '\0';                                                      Line 1057
          break;                                                                Line 1058
                                                                                
        case_GETOPT_HELP_CHAR;                                                  Line 1060
                                                                                
        case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);                       Line 1062
                                                                                
        default:                                                                Line 1064
          if (ISDIGIT (c))                                                      Line 1065
            error (0, 0, _("invalid trailing option -- %c"), c);                Line 1066
          usage (EXIT_FAILURE);                                                 Line 1067
        }                                                                       
    }                                                                           
                                                                                
  if (header_mode == always                                                     Line 1071
      || (header_mode == multiple_files && optind < argc - 1))                  Line 1072
    print_headers = true;                                                       Line 1073
                                                                                
  if ( ! count_lines && elide_from_end && OFF_T_MAX < n_units)                  Line 1075
    {                                                                           
      char umax_buf[INT_BUFSIZE_BOUND (n_units)];                               Line 1077
      die (EXIT_FAILURE, EOVERFLOW, "%s: %s", _("invalid number of bytes"),     Line 1078
           quote (umaxtostr (n_units, umax_buf)));                              Line 1079
    }                                                                           
                                                                                
  file_list = (optind < argc                                                    Line 1082
               ? (char const *const *) &argv[optind]                            Line 1083
               : default_file_list);                                            Line 1084
                                                                                
  xset_binary_mode (STDOUT_FILENO, O_BINARY);                                   Line 1086
                                                                                
  for (i = 0; file_list[i]; ++i)                                                Line 1088
    ok &= head_file (file_list[i], n_units, count_lines, elide_from_end);       Line 1089
                                                                                
  if (have_read_stdin && close (STDIN_FILENO) < 0)                              Line 1091...!syscalls auto-comment...
    die (EXIT_FAILURE, errno, "-");                                             Line 1092
                                                                                
  return ok ? EXIT_SUCCESS : EXIT_FAILURE;                                      Line 1094
}                                                                               Block 21