LCOV - code coverage report
Current view: top level - src - printf.c (source / functions) Hit Total Coverage
Test: coreutils.info Lines: 263 282 93.3 %
Date: 2018-01-30 Functions: 11 11 100.0 %

          Line data    Source code
       1             : /* printf - format and print data
       2             :    Copyright (C) 1990-2008 Free Software Foundation, Inc.
       3             : 
       4             :    This program is free software: you can redistribute it and/or modify
       5             :    it under the terms of the GNU General Public License as published by
       6             :    the Free Software Foundation, either version 3 of the License, or
       7             :    (at your option) any later version.
       8             : 
       9             :    This program is distributed in the hope that it will be useful,
      10             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             :    GNU General Public License for more details.
      13             : 
      14             :    You should have received a copy of the GNU General Public License
      15             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
      16             : 
      17             : /* Usage: printf format [argument...]
      18             : 
      19             :    A front end to the printf function that lets it be used from the shell.
      20             : 
      21             :    Backslash escapes:
      22             : 
      23             :    \" = double quote
      24             :    \\ = backslash
      25             :    \a = alert (bell)
      26             :    \b = backspace
      27             :    \c = produce no further output
      28             :    \f = form feed
      29             :    \n = new line
      30             :    \r = carriage return
      31             :    \t = horizontal tab
      32             :    \v = vertical tab
      33             :    \ooo = octal number (ooo is 1 to 3 digits)
      34             :    \xhh = hexadecimal number (hhh is 1 to 2 digits)
      35             :    \uhhhh = 16-bit Unicode character (hhhh is 4 digits)
      36             :    \Uhhhhhhhh = 32-bit Unicode character (hhhhhhhh is 8 digits)
      37             : 
      38             :    Additional directive:
      39             : 
      40             :    %b = print an argument string, interpreting backslash escapes,
      41             :      except that octal escapes are of the form \0 or \0ooo.
      42             : 
      43             :    The `format' argument is re-used as many times as necessary
      44             :    to convert all of the given arguments.
      45             : 
      46             :    David MacKenzie <djm@gnu.ai.mit.edu> */
      47             : 
      48             : #include <config.h>
      49             : #include <stdio.h>
      50             : #include <sys/types.h>
      51             : 
      52             : #include "system.h"
      53             : #include "c-strtod.h"
      54             : #include "error.h"
      55             : #include "long-options.h"
      56             : #include "quote.h"
      57             : #include "unicodeio.h"
      58             : #include "xprintf.h"
      59             : 
      60             : /* The official name of this program (e.g., no `g' prefix).  */
      61             : #define PROGRAM_NAME "printf"
      62             : 
      63             : #define AUTHORS "David MacKenzie"
      64             : 
      65             : #define isodigit(c) ((c) >= '0' && (c) <= '7')
      66             : #define hextobin(c) ((c) >= 'a' && (c) <= 'f' ? (c) - 'a' + 10 : \
      67             :                      (c) >= 'A' && (c) <= 'F' ? (c) - 'A' + 10 : (c) - '0')
      68             : #define octtobin(c) ((c) - '0')
      69             : 
      70             : /* The value to return to the calling program.  */
      71             : static int exit_status;
      72             : 
      73             : /* True if the POSIXLY_CORRECT environment variable is set.  */
      74             : static bool posixly_correct;
      75             : 
      76             : /* This message appears in N_() here rather than just in _() below because
      77             :    the sole use would have been in a #define.  */
      78             : static char const *const cfcc_msg =
      79             :  N_("warning: %s: character(s) following character constant have been ignored");
      80             : 
      81             : /* The name this program was run with. */
      82             : char *program_name;
      83             : 
      84             : void
      85           4 : usage (int status)
      86             : {
      87           4 :   if (status != EXIT_SUCCESS)
      88           2 :     fprintf (stderr, _("Try `%s --help' for more information.\n"),
      89             :              program_name);
      90             :   else
      91             :     {
      92           2 :       printf (_("\
      93             : Usage: %s FORMAT [ARGUMENT]...\n\
      94             :   or:  %s OPTION\n\
      95             : "),
      96             :               program_name, program_name);
      97           2 :       fputs (_("\
      98             : Print ARGUMENT(s) according to FORMAT, or execute according to OPTION:\n\
      99             : \n\
     100             : "), stdout);
     101           2 :       fputs (HELP_OPTION_DESCRIPTION, stdout);
     102           2 :       fputs (VERSION_OPTION_DESCRIPTION, stdout);
     103           2 :       fputs (_("\
     104             : \n\
     105             : FORMAT controls the output as in C printf.  Interpreted sequences are:\n\
     106             : \n\
     107             :   \\\"      double quote\n\
     108             :   \\NNN    character with octal value NNN (1 to 3 digits)\n\
     109             :   \\\\      backslash\n\
     110             : "), stdout);
     111           2 :       fputs (_("\
     112             :   \\a      alert (BEL)\n\
     113             :   \\b      backspace\n\
     114             :   \\c      produce no further output\n\
     115             :   \\f      form feed\n\
     116             : "), stdout);
     117           2 :       fputs (_("\
     118             :   \\n      new line\n\
     119             :   \\r      carriage return\n\
     120             :   \\t      horizontal tab\n\
     121             :   \\v      vertical tab\n\
     122             : "), stdout);
     123           2 :       fputs (_("\
     124             :   \\xHH    byte with hexadecimal value HH (1 to 2 digits)\n\
     125             :   \\uHHHH  Unicode (ISO/IEC 10646) character with hex value HHHH (4 digits)\n\
     126             :   \\UHHHHHHHH  Unicode character with hex value HHHHHHHH (8 digits)\n\
     127             : "), stdout);
     128           2 :       fputs (_("\
     129             :   %%      a single %\n\
     130             :   %b      ARGUMENT as a string with `\\' escapes interpreted,\n\
     131             :           except that octal escapes are of the form \\0 or \\0NNN\n\
     132             : \n\
     133             : and all C format specifications ending with one of diouxXfeEgGcs, with\n\
     134             : ARGUMENTs converted to proper type first.  Variable widths are handled.\n\
     135             : "), stdout);
     136           2 :       printf (USAGE_BUILTIN_WARNING, PROGRAM_NAME);
     137           2 :       emit_bug_reporting_address ();
     138             :     }
     139           4 :   exit (status);
     140             : }
     141             : 
     142             : static void
     143          40 : verify_numeric (const char *s, const char *end)
     144             : {
     145          40 :   if (errno)
     146             :     {
     147           0 :       error (0, errno, "%s", s);
     148           0 :       exit_status = EXIT_FAILURE;
     149             :     }
     150          40 :   else if (*end)
     151             :     {
     152           3 :       if (s == end)
     153           2 :         error (0, 0, _("%s: expected a numeric value"), s);
     154             :       else
     155           1 :         error (0, 0, _("%s: value not completely converted"), s);
     156           3 :       exit_status = EXIT_FAILURE;
     157             :     }
     158          40 : }
     159             : 
     160             : #define STRTOX(TYPE, FUNC_NAME, LIB_FUNC_EXPR)                           \
     161             : static TYPE                                                              \
     162             : FUNC_NAME (char const *s)                                                \
     163             : {                                                                        \
     164             :   char *end;                                                             \
     165             :   TYPE val;                                                              \
     166             :                                                                          \
     167             :   if (*s == '\"' || *s == '\'')                                             \
     168             :     {                                                                    \
     169             :       unsigned char ch = *++s;                                           \
     170             :       val = ch;                                                          \
     171             :       /* If POSIXLY_CORRECT is not set, then give a warning that there   \
     172             :          are characters following the character constant and that GNU    \
     173             :          printf is ignoring those characters.  If POSIXLY_CORRECT *is*   \
     174             :          set, then don't give the warning.  */                           \
     175             :       if (*++s != 0 && !posixly_correct)                                 \
     176             :         error (0, 0, _(cfcc_msg), s);                                    \
     177             :     }                                                                    \
     178             :   else                                                                   \
     179             :     {                                                                    \
     180             :       errno = 0;                                                         \
     181             :       val = (LIB_FUNC_EXPR);                                             \
     182             :       verify_numeric (s, end);                                           \
     183             :     }                                                                    \
     184             :   return val;                                                            \
     185             : }                                                                        \
     186             : 
     187          15 : STRTOX (intmax_t,    vstrtoimax, strtoimax (s, &end, 0))
     188          18 : STRTOX (uintmax_t,   vstrtoumax, strtoumax (s, &end, 0))
     189          18 : STRTOX (long double, vstrtold,   c_strtold (s, &end))
     190             : 
     191             : /* Output a single-character \ escape.  */
     192             : 
     193             : static void
     194          11 : print_esc_char (char c)
     195             : {
     196          11 :   switch (c)
     197             :     {
     198           1 :     case 'a':                   /* Alert. */
     199           1 :       putchar ('\a');
     200           1 :       break;
     201           1 :     case 'b':                   /* Backspace. */
     202           1 :       putchar ('\b');
     203           1 :       break;
     204           1 :     case 'c':                   /* Cancel the rest of the output. */
     205           1 :       exit (EXIT_SUCCESS);
     206             :       break;
     207           1 :     case 'f':                   /* Form feed. */
     208           1 :       putchar ('\f');
     209           1 :       break;
     210           1 :     case 'n':                   /* New line. */
     211           1 :       putchar ('\n');
     212           1 :       break;
     213           1 :     case 'r':                   /* Carriage return. */
     214           1 :       putchar ('\r');
     215           1 :       break;
     216           1 :     case 't':                   /* Horizontal tab. */
     217           1 :       putchar ('\t');
     218           1 :       break;
     219           1 :     case 'v':                   /* Vertical tab. */
     220           1 :       putchar ('\v');
     221           1 :       break;
     222           3 :     default:
     223           3 :       putchar (c);
     224           3 :       break;
     225             :     }
     226          10 : }
     227             : 
     228             : /* Print a \ escape sequence starting at ESCSTART.
     229             :    Return the number of characters in the escape sequence
     230             :    besides the backslash.
     231             :    If OCTAL_0 is nonzero, octal escapes are of the form \0ooo, where o
     232             :    is an octal digit; otherwise they are of the form \ooo.  */
     233             : 
     234             : static int
     235          51 : print_esc (const char *escstart, bool octal_0)
     236             : {
     237          51 :   const char *p = escstart + 1;
     238          51 :   int esc_value = 0;            /* Value of \nnn escape. */
     239             :   int esc_length;               /* Length of \nnn escape. */
     240             : 
     241          51 :   if (*p == 'x')
     242             :     {
     243             :       /* A hexadecimal \xhh escape sequence must have 1 or 2 hex. digits.  */
     244          37 :       for (esc_length = 0, ++p;
     245          21 :            esc_length < 2 && isxdigit (to_uchar (*p));
     246           9 :            ++esc_length, ++p)
     247           9 :         esc_value = esc_value * 16 + hextobin (*p);
     248          14 :       if (esc_length == 0)
     249           7 :         error (EXIT_FAILURE, 0, _("missing hexadecimal number in escape"));
     250           7 :       putchar (esc_value);
     251             :     }
     252          37 :   else if (isodigit (*p))
     253             :     {
     254             :       /* Parse \0ooo (if octal_0 && *p == '0') or \ooo (otherwise).
     255             :          Allow \ooo if octal_0 && *p != '0'; this is an undocumented
     256             :          extension to POSIX that is compatible with Bash 2.05b.  */
     257          14 :       for (esc_length = 0, p += octal_0 && *p == '0';
     258           9 :            esc_length < 3 && isodigit (*p);
     259           6 :            ++esc_length, ++p)
     260           6 :         esc_value = esc_value * 8 + octtobin (*p);
     261           4 :       putchar (esc_value);
     262             :     }
     263          33 :   else if (*p && strchr ("\"\\abcfnrtv", *p))
     264          11 :     print_esc_char (*p++);
     265          22 :   else if (*p == 'u' || *p == 'U')
     266           0 :     {
     267           5 :       char esc_char = *p;
     268             :       unsigned int uni_value;
     269             : 
     270           5 :       uni_value = 0;
     271          13 :       for (esc_length = (esc_char == 'u' ? 4 : 8), ++p;
     272             :            esc_length > 0;
     273           3 :            --esc_length, ++p)
     274             :         {
     275           8 :           if (! isxdigit (to_uchar (*p)))
     276           5 :             error (EXIT_FAILURE, 0, _("missing hexadecimal number in escape"));
     277           3 :           uni_value = uni_value * 16 + hextobin (*p);
     278             :         }
     279             : 
     280             :       /* A universal character name shall not specify a character short
     281             :          identifier in the range 00000000 through 00000020, 0000007F through
     282             :          0000009F, or 0000D800 through 0000DFFF inclusive. A universal
     283             :          character name shall not designate a character in the required
     284             :          character set.  */
     285           0 :       if ((uni_value <= 0x9f
     286           0 :            && uni_value != 0x24 && uni_value != 0x40 && uni_value != 0x60)
     287           0 :           || (uni_value >= 0xd800 && uni_value <= 0xdfff))
     288           0 :         error (EXIT_FAILURE, 0, _("invalid universal character name \\%c%0*x"),
     289             :                esc_char, (esc_char == 'u' ? 4 : 8), uni_value);
     290             : 
     291           0 :       print_unicode_char (stdout, uni_value, 0);
     292             :     }
     293             :   else
     294             :     {
     295          17 :       putchar ('\\');
     296          17 :       if (*p)
     297             :         {
     298           1 :           putchar (*p);
     299           1 :           p++;
     300             :         }
     301             :     }
     302          38 :   return p - escstart - 1;
     303             : }
     304             : 
     305             : /* Print string STR, evaluating \ escapes. */
     306             : 
     307             : static void
     308          12 : print_esc_string (const char *str)
     309             : {
     310          17 :   for (; *str; str++)
     311           7 :     if (*str == '\\')
     312           4 :       str += print_esc (str, true);
     313             :     else
     314           3 :       putchar (*str);
     315          10 : }
     316             : 
     317             : /* Evaluate a printf conversion specification.  START is the start of
     318             :    the directive, LENGTH is its length, and CONVERSION specifies the
     319             :    type of conversion.  LENGTH does not include any length modifier or
     320             :    the conversion specifier itself.  FIELD_WIDTH and PRECISION are the
     321             :    field width and precision for '*' values, if HAVE_FIELD_WIDTH and
     322             :    HAVE_PRECISION are true, respectively.  ARGUMENT is the argument to
     323             :    be formatted.  */
     324             : 
     325             : static void
     326          45 : print_direc (const char *start, size_t length, char conversion,
     327             :              bool have_field_width, int field_width,
     328             :              bool have_precision, int precision,
     329             :              char const *argument)
     330             : {
     331             :   char *p;              /* Null-terminated copy of % directive. */
     332             : 
     333             :   /* Create a null-terminated copy of the % directive, with an
     334             :      intmax_t-wide length modifier substituted for any existing
     335             :      integer length modifier.  */
     336             :   {
     337             :     char *q;
     338             :     char const *length_modifier;
     339             :     size_t length_modifier_len;
     340             : 
     341          45 :     switch (conversion)
     342             :       {
     343          22 :       case 'd': case 'i': case 'o': case 'u': case 'x': case 'X':
     344          22 :         length_modifier = PRIdMAX;
     345          22 :         length_modifier_len = sizeof PRIdMAX - 2;
     346          22 :         break;
     347             : 
     348          18 :       case 'a': case 'e': case 'f': case 'g':
     349             :       case 'A': case 'E': case 'F': case 'G':
     350          18 :         length_modifier = "L";
     351          18 :         length_modifier_len = 1;
     352          18 :         break;
     353             : 
     354           5 :       default:
     355           5 :         length_modifier = start;  /* Any valid pointer will do.  */
     356           5 :         length_modifier_len = 0;
     357           5 :         break;
     358             :       }
     359             : 
     360          45 :     p = xmalloc (length + length_modifier_len + 2);
     361          45 :     q = mempcpy (p, start, length);
     362          45 :     q = mempcpy (q, length_modifier, length_modifier_len);
     363          45 :     *q++ = conversion;
     364          45 :     *q = '\0';
     365             :   }
     366             : 
     367          45 :   switch (conversion)
     368             :     {
     369           4 :     case 'd':
     370             :     case 'i':
     371             :       {
     372           4 :         intmax_t arg = vstrtoimax (argument);
     373           4 :         if (!have_field_width)
     374             :           {
     375           3 :             if (!have_precision)
     376           3 :               xprintf (p, arg);
     377             :             else
     378           0 :               xprintf (p, precision, arg);
     379             :           }
     380             :         else
     381             :           {
     382           1 :             if (!have_precision)
     383           1 :               xprintf (p, field_width, arg);
     384             :             else
     385           0 :               xprintf (p, field_width, precision, arg);
     386             :           }
     387             :       }
     388           4 :       break;
     389             : 
     390          18 :     case 'o':
     391             :     case 'u':
     392             :     case 'x':
     393             :     case 'X':
     394             :       {
     395          18 :         uintmax_t arg = vstrtoumax (argument);
     396          18 :         if (!have_field_width)
     397             :           {
     398          16 :             if (!have_precision)
     399          16 :               xprintf (p, arg);
     400             :             else
     401           0 :               xprintf (p, precision, arg);
     402             :           }
     403             :         else
     404             :           {
     405           2 :             if (!have_precision)
     406           2 :               xprintf (p, field_width, arg);
     407             :             else
     408           0 :               xprintf (p, field_width, precision, arg);
     409             :           }
     410             :       }
     411          18 :       break;
     412             : 
     413          18 :     case 'a':
     414             :     case 'A':
     415             :     case 'e':
     416             :     case 'E':
     417             :     case 'f':
     418             :     case 'F':
     419             :     case 'g':
     420             :     case 'G':
     421             :       {
     422          18 :         long double arg = vstrtold (argument);
     423          18 :         if (!have_field_width)
     424             :           {
     425          17 :             if (!have_precision)
     426          17 :               xprintf (p, arg);
     427             :             else
     428           0 :               xprintf (p, precision, arg);
     429             :           }
     430             :         else
     431             :           {
     432           1 :             if (!have_precision)
     433           1 :               xprintf (p, field_width, arg);
     434             :             else
     435           0 :               xprintf (p, field_width, precision, arg);
     436             :           }
     437             :       }
     438          18 :       break;
     439             : 
     440           2 :     case 'c':
     441           2 :       if (!have_field_width)
     442           1 :         xprintf (p, *argument);
     443             :       else
     444           1 :         xprintf (p, field_width, *argument);
     445           2 :       break;
     446             : 
     447           3 :     case 's':
     448           3 :       if (!have_field_width)
     449             :         {
     450           2 :           if (!have_precision)
     451           2 :             xprintf (p, argument);
     452             :           else
     453           0 :             xprintf (p, precision, argument);
     454             :         }
     455             :       else
     456             :         {
     457           1 :           if (!have_precision)
     458           1 :             xprintf (p, field_width, argument);
     459             :           else
     460           0 :             xprintf (p, field_width, precision, argument);
     461             :         }
     462           3 :       break;
     463             :     }
     464             : 
     465          45 :   free (p);
     466          45 : }
     467             : 
     468             : /* Print the text in FORMAT, using ARGV (with ARGC elements) for
     469             :    arguments to any `%' directives.
     470             :    Return the number of elements of ARGV used.  */
     471             : 
     472             : static int
     473         144 : print_formatted (const char *format, int argc, char **argv)
     474             : {
     475         144 :   int save_argc = argc;         /* Preserve original value.  */
     476             :   const char *f;                /* Pointer into `format'.  */
     477             :   const char *direc_start;      /* Start of % directive.  */
     478             :   size_t direc_length;          /* Length of % directive.  */
     479             :   bool have_field_width;        /* True if FIELD_WIDTH is valid.  */
     480         144 :   int field_width = 0;          /* Arg to first '*'.  */
     481             :   bool have_precision;          /* True if PRECISION is valid.  */
     482         144 :   int precision = 0;            /* Arg to second '*'.  */
     483             :   char ok[UCHAR_MAX + 1];       /* ok['x'] is true if %x is allowed.  */
     484             : 
     485         381 :   for (f = format; *f; ++f)
     486             :     {
     487         277 :       switch (*f)
     488             :         {
     489          87 :         case '%':
     490          87 :           direc_start = f++;
     491          87 :           direc_length = 1;
     492          87 :           have_field_width = have_precision = false;
     493          87 :           if (*f == '%')
     494             :             {
     495           2 :               putchar ('%');
     496           2 :               break;
     497             :             }
     498          85 :           if (*f == 'b')
     499             :             {
     500             :               /* FIXME: Field width and precision are not supported
     501             :                  for %b, even though POSIX requires it.  */
     502          13 :               if (argc > 0)
     503             :                 {
     504          12 :                   print_esc_string (*argv);
     505          10 :                   ++argv;
     506          10 :                   --argc;
     507             :                 }
     508          11 :               break;
     509             :             }
     510             : 
     511          72 :           memset (ok, 0, sizeof ok);
     512          72 :           ok['a'] = ok['A'] = ok['c'] = ok['d'] = ok['e'] = ok['E'] =
     513          72 :             ok['f'] = ok['F'] = ok['g'] = ok['G'] = ok['i'] = ok['o'] =
     514          72 :             ok['s'] = ok['u'] = ok['x'] = ok['X'] = 1;
     515             : 
     516          28 :           for (;; f++, direc_length++)
     517         128 :             switch (*f)
     518             :               {
     519             : #if (__GLIBC__ == 2 && 2 <= __GLIBC_MINOR__) || 3 <= __GLIBC__
     520           2 :               case 'I':
     521             : #endif
     522             :               case '\'':
     523           2 :                 ok['a'] = ok['A'] = ok['c'] = ok['e'] = ok['E'] =
     524           2 :                   ok['o'] = ok['s'] = ok['x'] = ok['X'] = 0;
     525           2 :                 break;
     526          19 :               case '-': case '+': case ' ':
     527          19 :                 break;
     528           4 :               case '#':
     529           4 :                 ok['c'] = ok['d'] = ok['i'] = ok['s'] = ok['u'] = 0;
     530           4 :                 break;
     531           3 :               case '0':
     532           3 :                 ok['c'] = ok['s'] = 0;
     533           3 :                 break;
     534          72 :               default:
     535          72 :                 goto no_more_flag_characters;
     536             :               }
     537          72 :         no_more_flag_characters:;
     538             : 
     539          72 :           if (*f == '*')
     540             :             {
     541          18 :               ++f;
     542          18 :               ++direc_length;
     543          18 :               if (argc > 0)
     544             :                 {
     545          10 :                   intmax_t width = vstrtoimax (*argv);
     546          10 :                   if (INT_MIN <= width && width <= INT_MAX)
     547          10 :                     field_width = width;
     548             :                   else
     549           0 :                     error (EXIT_FAILURE, 0, _("invalid field width: %s"),
     550             :                            *argv);
     551          10 :                   ++argv;
     552          10 :                   --argc;
     553             :                 }
     554             :               else
     555           8 :                 field_width = 0;
     556          18 :               have_field_width = true;
     557             :             }
     558             :           else
     559         122 :             while (ISDIGIT (*f))
     560             :               {
     561          14 :                 ++f;
     562          14 :                 ++direc_length;
     563             :               }
     564          72 :           if (*f == '.')
     565             :             {
     566           9 :               ++f;
     567           9 :               ++direc_length;
     568           9 :               ok['c'] = 0;
     569           9 :               if (*f == '*')
     570             :                 {
     571           2 :                   ++f;
     572           2 :                   ++direc_length;
     573           2 :                   if (argc > 0)
     574             :                     {
     575           1 :                       intmax_t prec = vstrtoimax (*argv);
     576           1 :                       if (prec < 0)
     577             :                         {
     578             :                           /* A negative precision is taken as if the
     579             :                              precision were omitted, so -1 is safe
     580             :                              here even if prec < INT_MIN.  */
     581           0 :                           precision = -1;
     582             :                         }
     583           1 :                       else if (INT_MAX < prec)
     584           0 :                         error (EXIT_FAILURE, 0, _("invalid precision: %s"),
     585             :                                *argv);
     586             :                       else
     587           1 :                         precision = prec;
     588           1 :                       ++argv;
     589           1 :                       --argc;
     590             :                     }
     591             :                   else
     592           1 :                     precision = 0;
     593           2 :                   have_precision = true;
     594             :                 }
     595             :               else
     596          15 :                 while (ISDIGIT (*f))
     597             :                   {
     598           1 :                     ++f;
     599           1 :                     ++direc_length;
     600             :                   }
     601             :             }
     602             : 
     603         154 :           while (*f == 'l' || *f == 'L' || *f == 'h'
     604          75 :                  || *f == 'j' || *f == 't' || *f == 'z')
     605          10 :             ++f;
     606             : 
     607             :           {
     608          72 :             unsigned char conversion = *f;
     609          72 :             if (! ok[conversion])
     610          27 :               error (EXIT_FAILURE, 0,
     611             :                      _("%.*s: invalid conversion specification"),
     612          27 :                      (int) (f + 1 - direc_start), direc_start);
     613             :           }
     614             : 
     615          53 :           print_direc (direc_start, direc_length, *f,
     616             :                        have_field_width, field_width,
     617             :                        have_precision, precision,
     618           8 :                        (argc <= 0 ? "" : (argc--, *argv++)));
     619          45 :           break;
     620             : 
     621          47 :         case '\\':
     622          47 :           f += print_esc (f, false);
     623          36 :           break;
     624             : 
     625         143 :         default:
     626         143 :           putchar (*f);
     627             :         }
     628             :     }
     629             : 
     630         104 :   return save_argc - argc;
     631             : }
     632             : 
     633             : int
     634         146 : main (int argc, char **argv)
     635             : {
     636             :   char *format;
     637             :   int args_used;
     638             : 
     639             :   initialize_main (&argc, &argv);
     640         146 :   program_name = argv[0];
     641         146 :   setlocale (LC_ALL, "");
     642             :   bindtextdomain (PACKAGE, LOCALEDIR);
     643             :   textdomain (PACKAGE);
     644             : 
     645         146 :   atexit (close_stdout);
     646             : 
     647         146 :   exit_status = EXIT_SUCCESS;
     648             : 
     649         146 :   posixly_correct = (getenv ("POSIXLY_CORRECT") != NULL);
     650             : 
     651         146 :   parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE_NAME, VERSION,
     652             :                       usage, AUTHORS, (char const *) NULL);
     653             : 
     654             :   /* The above handles --help and --version.
     655             :      Since there is no other invocation of getopt, handle `--' here.  */
     656         143 :   if (1 < argc && STREQ (argv[1], "--"))
     657             :     {
     658           6 :       --argc;
     659           6 :       ++argv;
     660             :     }
     661             : 
     662         143 :   if (argc <= 1)
     663             :     {
     664           2 :       error (0, 0, _("missing operand"));
     665           2 :       usage (EXIT_FAILURE);
     666             :     }
     667             : 
     668         141 :   format = argv[1];
     669         141 :   argc -= 2;
     670         141 :   argv += 2;
     671             : 
     672             :   do
     673             :     {
     674         144 :       args_used = print_formatted (format, argc, argv);
     675         104 :       argc -= args_used;
     676         104 :       argv += args_used;
     677             :     }
     678         104 :   while (args_used > 0 && argc > 0);
     679             : 
     680         101 :   if (argc > 0)
     681          26 :     error (0, 0,
     682             :            _("warning: ignoring excess arguments, starting with %s"),
     683             :            quote (argv[0]));
     684             : 
     685         101 :   exit (exit_status);
     686             : }

Generated by: LCOV version 1.10