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 : }
|