/* 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