/* printf - format and print data                                               This is the printf utility
   Copyright (C) 1990-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
                                                                                
/* Usage: printf format [argument...]                                           
                                                                                
   A front end to the printf function that lets it be used from the shell.      
                                                                                
   Backslash escapes:                                                           
                                                                                
   \" = double quote                                                            
   \\ = backslash                                                               
   \a = alert (bell)                                                            
   \b = backspace                                                               
   \c = produce no further output                                               
   \e = escape                                                                  
   \f = form feed                                                               
   \n = new line                                                                
   \r = carriage return                                                         
   \t = horizontal tab                                                          
   \v = vertical tab                                                            
   \ooo = octal number (ooo is 1 to 3 digits)                                   
   \xhh = hexadecimal number (hhh is 1 to 2 digits)                             
   \uhhhh = 16-bit Unicode character (hhhh is 4 digits)                         
   \Uhhhhhhhh = 32-bit Unicode character (hhhhhhhh is 8 digits)                 
                                                                                
   Additional directive:                                                        
                                                                                
   %b = print an argument string, interpreting backslash escapes,               
     except that octal escapes are of the form \0 or \0ooo.                     
                                                                                
   %q = print an argument string in a format that can be                        
     reused as shell input.  Escaped characters used the proposed               
     POSIX $'' syntax supported by most shells.                                 
                                                                                
   The 'format' argument is re-used as many times as necessary                  
   to convert all of the given arguments.                                       
                                                                                
   David MacKenzie <djm@gnu.ai.mit.edu> */                                      
                                                                                
#include <config.h>                                                             Provides system specific information
#include <stdio.h>                                                              Provides standard I/O capability
#include <sys/types.h>                                                          Provides system data types
                                                                                
#include "system.h"                                                             ...!includes auto-comment...
#include "c-strtod.h"                                                           ...!includes auto-comment...
#include "die.h"                                                                ...!includes auto-comment...
#include "error.h"                                                              ...!includes auto-comment...
#include "quote.h"                                                              ...!includes auto-comment...
#include "unicodeio.h"                                                          ...!includes auto-comment...
#include "xprintf.h"                                                            ...!includes auto-comment...
                                                                                
/* The official name of this program (e.g., no 'g' prefix).  */                 
#define PROGRAM_NAME "printf"                                                   Line 66
                                                                                
#define AUTHORS proper_name ("David MacKenzie")                                 Line 68
                                                                                
#define isodigit(c) ((c) >= '0' && (c) <= '7')                                  Line 70
#define hextobin(c) ((c) >= 'a' && (c) <= 'f' ? (c) - 'a' + 10 : \              Line 71
                     (c) >= 'A' && (c) <= 'F' ? (c) - 'A' + 10 : (c) - '0')     Line 72
#define octtobin(c) ((c) - '0')                                                 Line 73
                                                                                
/* The value to return to the calling program.  */                              
static int exit_status;                                                         Line 76
                                                                                
/* True if the POSIXLY_CORRECT environment variable is set.  */                 
static bool posixly_correct;                                                    Line 79
                                                                                
/* This message appears in N_() here rather than just in _() below because      
   the sole use would have been in a #define.  */                               
static char const *const cfcc_msg =                                             Line 83
 N_("warning: %s: character(s) following character constant have been ignored");Line 84
                                                                                
void                                                                            Line 86
usage (int status)                                                              Line 87
{                                                                               
  if (status != EXIT_SUCCESS)                                                   Line 89
    emit_try_help ();                                                           ...!common auto-comment...
  else                                                                          Line 91
    {                                                                           
      printf (_("\                                                              Line 93
Usage: %s FORMAT [ARGUMENT]...\n\                                               Line 94
  or:  %s OPTION\n\                                                             Line 95
"),                                                                             Line 96
              program_name, program_name);                                      Line 97
      fputs (_("\                                                               Line 98
Print ARGUMENT(s) according to FORMAT, or execute according to OPTION:\n\       Line 99
\n\                                                                             
"), stdout);                                                                    Line 101
      fputs (HELP_OPTION_DESCRIPTION, stdout);                                  Line 102
      fputs (VERSION_OPTION_DESCRIPTION, stdout);                               Line 103
      fputs (_("\                                                               Line 104
\n\                                                                             
FORMAT controls the output as in C printf.  Interpreted sequences are:\n\       Line 106
\n\                                                                             
  \\\"      double quote\n\                                                     Line 108
"), stdout);                                                                    Line 109
      fputs (_("\                                                               Line 110
  \\\\      backslash\n\                                                        Line 111
  \\a      alert (BEL)\n\                                                       Line 112
  \\b      backspace\n\                                                         Line 113
  \\c      produce no further output\n\                                         Line 114
  \\e      escape\n\                                                            Line 115
  \\f      form feed\n\                                                         Line 116
  \\n      new line\n\                                                          Line 117
  \\r      carriage return\n\                                                   Line 118
  \\t      horizontal tab\n\                                                    Line 119
  \\v      vertical tab\n\                                                      Line 120
"), stdout);                                                                    Line 121
      fputs (_("\                                                               Line 122
  \\NNN    byte with octal value NNN (1 to 3 digits)\n\                         Line 123
  \\xHH    byte with hexadecimal value HH (1 to 2 digits)\n\                    Line 124
  \\uHHHH  Unicode (ISO/IEC 10646) character with hex value HHHH (4 digits)\n\  Line 125
  \\UHHHHHHHH  Unicode character with hex value HHHHHHHH (8 digits)\n\          Line 126
"), stdout);                                                                    Line 127
      fputs (_("\                                                               Line 128
  %%      a single %\n\                                                         Line 129
  %b      ARGUMENT as a string with '\\' escapes interpreted,\n\                Line 130
          except that octal escapes are of the form \\0 or \\0NNN\n\            Line 131
  %q      ARGUMENT is printed in a format that can be reused as shell input,\n\ Line 132
          escaping non-printable characters with the proposed POSIX $'' syntax.\Line 133
\n\n\                                                                           Line 134
and all C format specifications ending with one of diouxXfeEgGcs, with\n\       Line 135
ARGUMENTs converted to proper type first.  Variable widths are handled.\n\      Line 136
"), stdout);                                                                    Line 137
      printf (USAGE_BUILTIN_WARNING, PROGRAM_NAME);                             Line 138
      emit_ancillary_info (PROGRAM_NAME);                                       Line 139
    }                                                                           
  exit (status);                                                                Line 141
}                                                                               Block 1
                                                                                
static void                                                                     Line 144
verify_numeric (const char *s, const char *end)                                 Line 145
{                                                                               
  if (errno)                                                                    Line 147
    {                                                                           
      error (0, errno, "%s", quote (s));                                        Line 149
      exit_status = EXIT_FAILURE;                                               Line 150
    }                                                                           
  else if (*end)                                                                Line 152
    {                                                                           
      if (s == end)                                                             Line 154
        error (0, 0, _("%s: expected a numeric value"), quote (s));             Line 155
      else                                                                      Line 156
        error (0, 0, _("%s: value not completely converted"), quote (s));       Line 157
      exit_status = EXIT_FAILURE;                                               Line 158
    }                                                                           
}                                                                               Block 2
                                                                                
#define STRTOX(TYPE, FUNC_NAME, LIB_FUNC_EXPR)     \                            Line 162
static TYPE         \                                                           Line 163
FUNC_NAME (char const *s)       \                                               Line 164
{          \                                                                    Line 165
  char *end;         \                                                          Line 166
  TYPE val;         \                                                           Line 167
                                                                         \      
  if ((*s == '\"' || *s == '\'') && *(s + 1))     \                             Line 169
    {          \                                                                Line 170
      unsigned char ch = *++s;       \                                          Line 171
      val = ch;         \                                                       Line 172
      /* If POSIXLY_CORRECT is not set, then give a warning that there  \       
         are characters following the character constant and that GNU  \        
         printf is ignoring those characters.  If POSIXLY_CORRECT *is*  \       
         set, then don't give the warning.  */     \                            Line 176
      if (*++s != 0 && !posixly_correct)     \                                  Line 177
        error (0, 0, _(cfcc_msg), s);      \                                    Line 178
    }          \                                                                Line 179
  else          \                                                               Line 180
    {          \                                                                Line 181
      errno = 0;        \                                                       Line 182
      val = (LIB_FUNC_EXPR);       \                                            Line 183
      verify_numeric (s, end);       \                                          Line 184
    }          \                                                                Line 185
  return val;         \                                                         Line 186
}          \                                                                    Line 187Block 3
                                                                                
STRTOX (intmax_t,    vstrtoimax, strtoimax (s, &end, 0))                        Line 189
STRTOX (uintmax_t,   vstrtoumax, strtoumax (s, &end, 0))                        Line 190
STRTOX (long double, vstrtold,   c_strtold (s, &end))                           Line 191
                                                                                
/* Output a single-character \ escape.  */                                      
                                                                                
static void                                                                     Line 195
print_esc_char (char c)                                                         Line 196
{                                                                               
  switch (c)                                                                    Line 198
    {                                                                           
    case 'a':   /* Alert. */                                                    Line 200
      putchar ('\a');                                                           Line 201
      break;                                                                    Line 202
    case 'b':   /* Backspace. */                                                Line 203
      putchar ('\b');                                                           Line 204
      break;                                                                    Line 205
    case 'c':   /* Cancel the rest of the output. */                            Line 206
      exit (EXIT_SUCCESS);                                                      Line 207
      break;                                                                    Line 208
    case 'e':   /* Escape. */                                                   Line 209
      putchar ('\x1B');                                                         Line 210
      break;                                                                    Line 211
    case 'f':   /* Form feed. */                                                Line 212
      putchar ('\f');                                                           Line 213
      break;                                                                    Line 214
    case 'n':   /* New line. */                                                 Line 215
      putchar ('\n');                                                           Line 216
      break;                                                                    Line 217
    case 'r':   /* Carriage return. */                                          Line 218
      putchar ('\r');                                                           Line 219
      break;                                                                    Line 220
    case 't':   /* Horizontal tab. */                                           Line 221
      putchar ('\t');                                                           Line 222
      break;                                                                    Line 223
    case 'v':   /* Vertical tab. */                                             Line 224
      putchar ('\v');                                                           Line 225
      break;                                                                    Line 226
    default:                                                                    Line 227
      putchar (c);                                                              Line 228
      break;                                                                    Line 229
    }                                                                           
}                                                                               Block 4
                                                                                
/* Print a \ escape sequence starting at ESCSTART.                              
   Return the number of characters in the escape sequence                       
   besides the backslash.                                                       
   If OCTAL_0 is nonzero, octal escapes are of the form \0ooo, where o          
   is an octal digit; otherwise they are of the form \ooo.  */                  
                                                                                
static int                                                                      Line 239
print_esc (const char *escstart, bool octal_0)                                  Line 240
{                                                                               
  const char *p = escstart + 1;                                                 Line 242
  int esc_value = 0;  /* Value of \nnn escape. */                               Line 243
  int esc_length;  /* Length of \nnn escape. */                                 Line 244
                                                                                
  if (*p == 'x')                                                                Line 246
    {                                                                           
      /* A hexadecimal \xhh escape sequence must have 1 or 2 hex. digits.  */   
      for (esc_length = 0, ++p;                                                 Line 249
           esc_length < 2 && isxdigit (to_uchar (*p));                          Line 250
           ++esc_length, ++p)                                                   Line 251
        esc_value = esc_value * 16 + hextobin (*p);                             Line 252
      if (esc_length == 0)                                                      Line 253
        die (EXIT_FAILURE, 0, _("missing hexadecimal number in escape"));       Line 254
      putchar (esc_value);                                                      Line 255
    }                                                                           
  else if (isodigit (*p))                                                       Line 257
    {                                                                           
      /* Parse \0ooo (if octal_0 && *p == '0') or \ooo (otherwise).             
         Allow \ooo if octal_0 && *p != '0'; this is an undocumented            
         extension to POSIX that is compatible with Bash 2.05b.  */             
      for (esc_length = 0, p += octal_0 && *p == '0';                           Line 262
           esc_length < 3 && isodigit (*p);                                     Line 263
           ++esc_length, ++p)                                                   Line 264
        esc_value = esc_value * 8 + octtobin (*p);                              Line 265
      putchar (esc_value);                                                      Line 266
    }                                                                           
  else if (*p && strchr ("\"\\abcefnrtv", *p))                                  Line 268
    print_esc_char (*p++);                                                      Line 269
  else if (*p == 'u' || *p == 'U')                                              Line 270
    {                                                                           
      char esc_char = *p;                                                       Line 272
      unsigned int uni_value;                                                   Line 273
                                                                                
      uni_value = 0;                                                            Line 275
      for (esc_length = (esc_char == 'u' ? 4 : 8), ++p;                         Line 276
           esc_length > 0;                                                      Line 277
           --esc_length, ++p)                                                   Line 278
        {                                                                       
          if (! isxdigit (to_uchar (*p)))                                       Line 280
            die (EXIT_FAILURE, 0, _("missing hexadecimal number in escape"));   Line 281
          uni_value = uni_value * 16 + hextobin (*p);                           Line 282
        }                                                                       
                                                                                
      /* A universal character name shall not specify a character short         
         identifier in the range 00000000 through 00000020, 0000007F through    
         0000009F, or 0000D800 through 0000DFFF inclusive. A universal          
         character name shall not designate a character in the required         
         character set.  */                                                     
      if ((uni_value <= 0x9f                                                    Line 290
           && uni_value != 0x24 && uni_value != 0x40 && uni_value != 0x60)      Line 291
          || (uni_value >= 0xd800 && uni_value <= 0xdfff))                      Line 292
        die (EXIT_FAILURE, 0, _("invalid universal character name \\%c%0*x"),   Line 293
             esc_char, (esc_char == 'u' ? 4 : 8), uni_value);                   Line 294
                                                                                
      print_unicode_char (stdout, uni_value, 0);                                Line 296
    }                                                                           
  else                                                                          Line 298
    {                                                                           
      putchar ('\\');                                                           Line 300
      if (*p)                                                                   Line 301
        {                                                                       
          putchar (*p);                                                         Line 303
          p++;                                                                  Line 304
        }                                                                       
    }                                                                           
  return p - escstart - 1;                                                      Line 307
}                                                                               Block 5
                                                                                
/* Print string STR, evaluating \ escapes. */                                   
                                                                                
static void                                                                     Line 312
print_esc_string (const char *str)                                              Line 313
{                                                                               
  for (; *str; str++)                                                           Line 315
    if (*str == '\\')                                                           Line 316
      str += print_esc (str, true);                                             Line 317
    else                                                                        Line 318
      putchar (*str);                                                           Line 319
}                                                                               Block 6
                                                                                
/* Evaluate a printf conversion specification.  START is the start of           
   the directive, LENGTH is its length, and CONVERSION specifies the            
   type of conversion.  LENGTH does not include any length modifier or          
   the conversion specifier itself.  FIELD_WIDTH and PRECISION are the          
   field width and precision for '*' values, if HAVE_FIELD_WIDTH and            
   HAVE_PRECISION are true, respectively.  ARGUMENT is the argument to          
   be formatted.  */                                                            
                                                                                
static void                                                                     Line 330
print_direc (const char *start, size_t length, char conversion,                 Line 331
             bool have_field_width, int field_width,                            Line 332
             bool have_precision, int precision,                                Line 333
             char const *argument)                                              Line 334
{                                                                               
  char *p;  /* Null-terminated copy of % directive. */                          Line 336
                                                                                
  /* Create a null-terminated copy of the % directive, with an                  
     intmax_t-wide length modifier substituted for any existing                 
     integer length modifier.  */                                               
  {                                                                             
    char *q;                                                                    Line 342
    char const *length_modifier;                                                Line 343
    size_t length_modifier_len;                                                 Line 344
                                                                                
    switch (conversion)                                                         Line 346
      {                                                                         
      case 'd': case 'i': case 'o': case 'u': case 'x': case 'X':               Line 348
        length_modifier = PRIdMAX;                                              Line 349
        length_modifier_len = sizeof PRIdMAX - 2;                               Line 350
        break;                                                                  Line 351
                                                                                
      case 'a': case 'e': case 'f': case 'g':                                   Line 353
      case 'A': case 'E': case 'F': case 'G':                                   Line 354
        length_modifier = "L";                                                  Line 355
        length_modifier_len = 1;                                                Line 356
        break;                                                                  Line 357
                                                                                
      default:                                                                  Line 359
        length_modifier = start;  /* Any valid pointer will do.  */             Line 360
        length_modifier_len = 0;                                                Line 361
        break;                                                                  Line 362
      }                                                                         
                                                                                
    p = xmalloc (length + length_modifier_len + 2);                             Line 365
    q = mempcpy (p, start, length);                                             Line 366
    q = mempcpy (q, length_modifier, length_modifier_len);                      Line 367
    *q++ = conversion;                                                          Line 368
    *q = '\0';                                                                  Line 369
  }                                                                             
                                                                                
  switch (conversion)                                                           Line 372
    {                                                                           
    case 'd':                                                                   Line 374
    case 'i':                                                                   Line 375
      {                                                                         
        intmax_t arg = vstrtoimax (argument);                                   Line 377
        if (!have_field_width)                                                  Line 378
          {                                                                     
            if (!have_precision)                                                Line 380
              xprintf (p, arg);                                                 Line 381
            else                                                                Line 382
              xprintf (p, precision, arg);                                      Line 383
          }                                                                     
        else                                                                    Line 385
          {                                                                     
            if (!have_precision)                                                Line 387
              xprintf (p, field_width, arg);                                    Line 388
            else                                                                Line 389
              xprintf (p, field_width, precision, arg);                         Line 390
          }                                                                     
      }                                                                         
      break;                                                                    Line 393
                                                                                
    case 'o':                                                                   Line 395
    case 'u':                                                                   Line 396
    case 'x':                                                                   Line 397
    case 'X':                                                                   Line 398
      {                                                                         
        uintmax_t arg = vstrtoumax (argument);                                  Line 400
        if (!have_field_width)                                                  Line 401
          {                                                                     
            if (!have_precision)                                                Line 403
              xprintf (p, arg);                                                 Line 404
            else                                                                Line 405
              xprintf (p, precision, arg);                                      Line 406
          }                                                                     
        else                                                                    Line 408
          {                                                                     
            if (!have_precision)                                                Line 410
              xprintf (p, field_width, arg);                                    Line 411
            else                                                                Line 412
              xprintf (p, field_width, precision, arg);                         Line 413
          }                                                                     
      }                                                                         
      break;                                                                    Line 416
                                                                                
    case 'a':                                                                   Line 418
    case 'A':                                                                   Line 419
    case 'e':                                                                   Line 420
    case 'E':                                                                   Line 421
    case 'f':                                                                   Line 422
    case 'F':                                                                   Line 423
    case 'g':                                                                   Line 424
    case 'G':                                                                   Line 425
      {                                                                         
        long double arg = vstrtold (argument);                                  Line 427
        if (!have_field_width)                                                  Line 428
          {                                                                     
            if (!have_precision)                                                Line 430
              xprintf (p, arg);                                                 Line 431
            else                                                                Line 432
              xprintf (p, precision, arg);                                      Line 433
          }                                                                     
        else                                                                    Line 435
          {                                                                     
            if (!have_precision)                                                Line 437
              xprintf (p, field_width, arg);                                    Line 438
            else                                                                Line 439
              xprintf (p, field_width, precision, arg);                         Line 440
          }                                                                     
      }                                                                         
      break;                                                                    Line 443
                                                                                
    case 'c':                                                                   Line 445
      if (!have_field_width)                                                    Line 446
        xprintf (p, *argument);                                                 Line 447
      else                                                                      Line 448
        xprintf (p, field_width, *argument);                                    Line 449
      break;                                                                    Line 450
                                                                                
    case 's':                                                                   Line 452
      if (!have_field_width)                                                    Line 453
        {                                                                       
          if (!have_precision)                                                  Line 455
            xprintf (p, argument);                                              Line 456
          else                                                                  Line 457
            xprintf (p, precision, argument);                                   Line 458
        }                                                                       
      else                                                                      Line 460
        {                                                                       
          if (!have_precision)                                                  Line 462
            xprintf (p, field_width, argument);                                 Line 463
          else                                                                  Line 464
            xprintf (p, field_width, precision, argument);                      Line 465
        }                                                                       
      break;                                                                    Line 467
    }                                                                           
                                                                                
  free (p);                                                                     Line 470
}                                                                               Block 7
                                                                                
/* Print the text in FORMAT, using ARGV (with ARGC elements) for                
   arguments to any '%' directives.                                             
   Return the number of elements of ARGV used.  */                              
                                                                                
static int                                                                      Line 477
print_formatted (const char *format, int argc, char **argv)                     Line 478
{                                                                               
  int save_argc = argc;  /* Preserve original value.  */                        Line 480
  const char *f;  /* Pointer into 'format'.  */                                 Line 481
  const char *direc_start; /* Start of % directive.  */                         Line 482
  size_t direc_length;  /* Length of % directive.  */                           Line 483
  bool have_field_width; /* True if FIELD_WIDTH is valid.  */                   Line 484
  int field_width = 0;  /* Arg to first '*'.  */                                Line 485
  bool have_precision;  /* True if PRECISION is valid.  */                      Line 486
  int precision = 0;  /* Arg to second '*'.  */                                 Line 487
  char ok[UCHAR_MAX + 1]; /* ok['x'] is true if %x is allowed.  */              Line 488
                                                                                
  for (f = format; *f; ++f)                                                     Line 490
    {                                                                           
      switch (*f)                                                               Line 492
        {                                                                       
        case '%':                                                               Line 494
          direc_start = f++;                                                    Line 495
          direc_length = 1;                                                     Line 496
          have_field_width = have_precision = false;                            Line 497
          if (*f == '%')                                                        Line 498
            {                                                                   
              putchar ('%');                                                    Line 500
              break;                                                            Line 501
            }                                                                   
          if (*f == 'b')                                                        Line 503
            {                                                                   
              /* FIXME: Field width and precision are not supported             
                 for %b, even though POSIX requires it.  */                     
              if (argc > 0)                                                     Line 507
                {                                                               
                  print_esc_string (*argv);                                     Line 509
                  ++argv;                                                       Line 510
                  --argc;                                                       Line 511
                }                                                               
              break;                                                            Line 513
            }                                                                   
                                                                                
          if (*f == 'q')                                                        Line 516
            {                                                                   
              if (argc > 0)                                                     Line 518
                {                                                               
                  fputs (quotearg_style (shell_escape_quoting_style, *argv),    Line 520
                         stdout);                                               Line 521
                  ++argv;                                                       Line 522
                  --argc;                                                       Line 523
                }                                                               
              break;                                                            Line 525
            }                                                                   
                                                                                
          memset (ok, 0, sizeof ok);                                            Line 528
          ok['a'] = ok['A'] = ok['c'] = ok['d'] = ok['e'] = ok['E'] =           Line 529
            ok['f'] = ok['F'] = ok['g'] = ok['G'] = ok['i'] = ok['o'] =         Line 530
            ok['s'] = ok['u'] = ok['x'] = ok['X'] = 1;                          Line 531
                                                                                
          for (;; f++, direc_length++)                                          Line 533
            switch (*f)                                                         Line 534
              {                                                                 
#if (__GLIBC__ == 2 && 2 <= __GLIBC_MINOR__) || 3 <= __GLIBC__                  Line 536
              case 'I':                                                         Line 537
#endif                                                                          Line 538
              case '\'':                                                        Line 539
                ok['a'] = ok['A'] = ok['c'] = ok['e'] = ok['E'] =               Line 540
                  ok['o'] = ok['s'] = ok['x'] = ok['X'] = 0;                    Line 541
                break;                                                          Line 542
              case '-': case '+': case ' ':                                     Line 543
                break;                                                          Line 544
              case '#':                                                         Line 545
                ok['c'] = ok['d'] = ok['i'] = ok['s'] = ok['u'] = 0;            Line 546
                break;                                                          Line 547
              case '0':                                                         Line 548
                ok['c'] = ok['s'] = 0;                                          Line 549
                break;                                                          Line 550
              default:                                                          Line 551
                goto no_more_flag_characters;                                   Line 552
              }                                                                 
        no_more_flag_characters:                                                Line 554
                                                                                
          if (*f == '*')                                                        Line 556
            {                                                                   
              ++f;                                                              Line 558
              ++direc_length;                                                   Line 559
              if (argc > 0)                                                     Line 560
                {                                                               
                  intmax_t width = vstrtoimax (*argv);                          Line 562
                  if (INT_MIN <= width && width <= INT_MAX)                     Line 563
                    field_width = width;                                        Line 564
                  else                                                          Line 565
                    die (EXIT_FAILURE, 0, _("invalid field width: %s"),         Line 566
                         quote (*argv));                                        Line 567
                  ++argv;                                                       Line 568
                  --argc;                                                       Line 569
                }                                                               
              else                                                              Line 571
                field_width = 0;                                                Line 572
              have_field_width = true;                                          Line 573
            }                                                                   
          else                                                                  Line 575
            while (ISDIGIT (*f))                                                Line 576
              {                                                                 
                ++f;                                                            Line 578
                ++direc_length;                                                 Line 579
              }                                                                 
          if (*f == '.')                                                        Line 581
            {                                                                   
              ++f;                                                              Line 583
              ++direc_length;                                                   Line 584
              ok['c'] = 0;                                                      Line 585
              if (*f == '*')                                                    Line 586
                {                                                               
                  ++f;                                                          Line 588
                  ++direc_length;                                               Line 589
                  if (argc > 0)                                                 Line 590
                    {                                                           
                      intmax_t prec = vstrtoimax (*argv);                       Line 592
                      if (prec < 0)                                             Line 593
                        {                                                       
                          /* A negative precision is taken as if the            
                             precision were omitted, so -1 is safe              
                             here even if prec < INT_MIN.  */                   
                          precision = -1;                                       Line 598
                        }                                                       
                      else if (INT_MAX < prec)                                  Line 600
                        die (EXIT_FAILURE, 0, _("invalid precision: %s"),       Line 601
                             quote (*argv));                                    Line 602
                      else                                                      Line 603
                        precision = prec;                                       Line 604
                      ++argv;                                                   Line 605
                      --argc;                                                   Line 606
                    }                                                           
                  else                                                          Line 608
                    precision = 0;                                              Line 609
                  have_precision = true;                                        Line 610
                }                                                               
              else                                                              Line 612
                while (ISDIGIT (*f))                                            Line 613
                  {                                                             
                    ++f;                                                        Line 615
                    ++direc_length;                                             Line 616
                  }                                                             
            }                                                                   
                                                                                
          while (*f == 'l' || *f == 'L' || *f == 'h'                            Line 620
                 || *f == 'j' || *f == 't' || *f == 'z')                        Line 621
            ++f;                                                                Line 622
                                                                                
          {                                                                     
            unsigned char conversion = *f;                                      Line 625
            if (! ok[conversion])                                               Line 626
              die (EXIT_FAILURE, 0,                                             Line 627
                   _("%.*s: invalid conversion specification"),                 Line 628
                   (int) (f + 1 - direc_start), direc_start);                   Line 629
          }                                                                     
                                                                                
          print_direc (direc_start, direc_length, *f,                           Line 632
                       have_field_width, field_width,                           Line 633
                       have_precision, precision,                               Line 634
                       (argc <= 0 ? "" : (argc--, *argv++)));                   Line 635
          break;                                                                Line 636
                                                                                
        case '\\':                                                              Line 638
          f += print_esc (f, false);                                            Line 639
          break;                                                                Line 640
                                                                                
        default:                                                                Line 642
          putchar (*f);                                                         Line 643
        }                                                                       
    }                                                                           
                                                                                
  return save_argc - argc;                                                      Line 647
}                                                                               Block 8
                                                                                
int                                                                             
main (int argc, char **argv)                                                    Line 651
{                                                                               
  char *format;                                                                 Line 653
  int args_used;                                                                Line 654
                                                                                
  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)
                                                                                
  exit_status = EXIT_SUCCESS;                                                   Line 664
                                                                                
  posixly_correct = (getenv ("POSIXLY_CORRECT") != NULL);                       Line 666
                                                                                
  /* We directly parse options, rather than use parse_long_options, in          
     order to avoid accepting abbreviations.  */                                
  if (argc == 2)                                                                Line 670
    {                                                                           
      if (STREQ (argv[1], "--help"))                                            Line 672
        usage (EXIT_SUCCESS);                                                   Line 673
                                                                                
      if (STREQ (argv[1], "--version"))                                         Line 675
        {                                                                       
          version_etc (stdout, PROGRAM_NAME, PACKAGE_NAME, Version, AUTHORS,    Line 677
                       (char *) NULL);                                          Line 678
          return EXIT_SUCCESS;                                                  Line 679
        }                                                                       
    }                                                                           
                                                                                
  /* The above handles --help and --version.                                    
     Since there is no other invocation of getopt, handle '--' here.  */        
  if (1 < argc && STREQ (argv[1], "--"))                                        Line 685
    {                                                                           
      --argc;                                                                   Line 687
      ++argv;                                                                   Line 688
    }                                                                           
                                                                                
  if (argc <= 1)                                                                Line 691
    {                                                                           
      error (0, 0, _("missing operand"));                                       Line 693
      usage (EXIT_FAILURE);                                                     Line 694
    }                                                                           
                                                                                
  format = argv[1];                                                             Line 697
  argc -= 2;                                                                    Line 698
  argv += 2;                                                                    Line 699
                                                                                
  do                                                                            
    {                                                                           
      args_used = print_formatted (format, argc, argv);                         Line 703
      argc -= args_used;                                                        Line 704
      argv += args_used;                                                        Line 705
    }                                                                           
  while (args_used > 0 && argc > 0);                                            Line 707
                                                                                
  if (argc > 0)                                                                 Line 709
    error (0, 0,                                                                Line 710
           _("warning: ignoring excess arguments, starting with %s"),           Line 711
           quote (argv[0]));                                                    Line 712
                                                                                
  return exit_status;                                                           Line 714
}                                                                               Block 9