Most .c files (AUTHORS): Revert the WRITTEN_BY/AUTHORS change
[platform/upstream/coreutils.git] / src / printf.c
1 /* printf - format and print data
2    Copyright (C) 1990-2003, 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 2, or (at your option)
7    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, write to the Free Software Foundation,
16    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
17
18 /* Usage: printf format [argument...]
19
20    A front end to the printf function that lets it be used from the shell.
21
22    Backslash escapes:
23
24    \" = double quote
25    \\ = backslash
26    \a = alert (bell)
27    \b = backspace
28    \c = produce no further output
29    \f = form feed
30    \n = new line
31    \r = carriage return
32    \t = horizontal tab
33    \v = vertical tab
34    \ooo = octal number (ooo is 1 to 3 digits)
35    \xhh = hexadecimal number (hhh is 1 to 2 digits)
36    \uhhhh = 16-bit Unicode character (hhhh is 4 digits)
37    \Uhhhhhhhh = 32-bit Unicode character (hhhhhhhh is 8 digits)
38
39    Additional directive:
40
41    %b = print an argument string, interpreting backslash escapes,
42      except that octal escapes are of the form \0 or \0ooo.
43
44    The `format' argument is re-used as many times as necessary
45    to convert all of the given arguments.
46
47    David MacKenzie <djm@gnu.ai.mit.edu> */
48
49 #include <config.h>
50 #include <stdio.h>
51 #include <sys/types.h>
52 #include <getopt.h>
53
54 #include "system.h"
55 #include "long-options.h"
56 #include "error.h"
57 #include "unicodeio.h"
58
59 /* The official name of this program (e.g., no `g' prefix).  */
60 #define PROGRAM_NAME "printf"
61
62 #define AUTHORS "David MacKenzie"
63
64 #ifndef STDC_HEADERS
65 double strtod ();
66 long int strtol ();
67 unsigned long int strtoul ();
68 #endif
69
70 #define isodigit(c) ((c) >= '0' && (c) <= '7')
71 #define hextobin(c) ((c) >= 'a' && (c) <= 'f' ? (c) - 'a' + 10 : \
72                      (c) >= 'A' && (c) <= 'F' ? (c) - 'A' + 10 : (c) - '0')
73 #define octtobin(c) ((c) - '0')
74
75 /* A value for field_width or precision that indicates it was not specified.  */
76 #define UNSPECIFIED INT_MIN
77
78 /* The value to return to the calling program.  */
79 static int exit_status;
80
81 /* Non-zero if the POSIXLY_CORRECT environment variable is set.  */
82 static int posixly_correct;
83
84 /* This message appears in N_() here rather than just in _() below because
85    the sole use would have been in a #define.  */
86 static char *const cfcc_msg =
87  N_("warning: %s: character(s) following character constant have been ignored");
88
89 /* The name this program was run with. */
90 char *program_name;
91
92 void
93 usage (int status)
94 {
95   if (status != 0)
96     fprintf (stderr, _("Try `%s --help' for more information.\n"),
97              program_name);
98   else
99     {
100       printf (_("\
101 Usage: %s FORMAT [ARGUMENT]...\n\
102   or:  %s OPTION\n\
103 "),
104               program_name, program_name);
105       fputs (_("\
106 Print ARGUMENT(s) according to FORMAT.\n\
107 \n\
108 "), stdout);
109       fputs (HELP_OPTION_DESCRIPTION, stdout);
110       fputs (VERSION_OPTION_DESCRIPTION, stdout);
111       fputs (_("\
112 \n\
113 FORMAT controls the output as in C printf.  Interpreted sequences are:\n\
114 \n\
115   \\\"      double quote\n\
116   \\NNN    character with octal value NNN (1 to 3 digits)\n\
117   \\\\      backslash\n\
118 "), stdout);
119       fputs (_("\
120   \\a      alert (BEL)\n\
121   \\b      backspace\n\
122   \\c      produce no further output\n\
123   \\f      form feed\n\
124 "), stdout);
125       fputs (_("\
126   \\n      new line\n\
127   \\r      carriage return\n\
128   \\t      horizontal tab\n\
129   \\v      vertical tab\n\
130 "), stdout);
131       fputs (_("\
132   \\xNN    byte with hexadecimal value NN (1 to 2 digits)\n\
133 \n\
134   \\uNNNN  character with hexadecimal value NNNN (4 digits)\n\
135   \\UNNNNNNNN  character with hexadecimal value NNNNNNNN (8 digits)\n\
136 "), stdout);
137       fputs (_("\
138   %%      a single %\n\
139   %b      ARGUMENT as a string with `\\' escapes interpreted,\n\
140             except that octal escapes are of the form \\0 or \\0NNN\n\
141 \n\
142 and all C format specifications ending with one of diouxXfeEgGcs, with\n\
143 ARGUMENTs converted to proper type first.  Variable widths are handled.\n\
144 "), stdout);
145       printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
146     }
147   exit (status);
148 }
149
150 static void
151 verify (const char *s, const char *end)
152 {
153   if (errno)
154     {
155       error (0, errno, "%s", s);
156       exit_status = 1;
157     }
158   else if (*end)
159     {
160       if (s == end)
161         error (0, 0, _("%s: expected a numeric value"), s);
162       else
163         error (0, 0, _("%s: value not completely converted"), s);
164       exit_status = 1;
165     }
166 }
167
168 #define STRTOX(TYPE, FUNC_NAME, LIB_FUNC_EXPR)                           \
169 static TYPE                                                              \
170 FUNC_NAME (s)                                                            \
171      const char *s;                                                      \
172 {                                                                        \
173   char *end;                                                             \
174   TYPE val;                                                              \
175                                                                          \
176   if (*s == '\"' || *s == '\'')                                          \
177     {                                                                    \
178       val = *(unsigned char *) ++s;                                      \
179       /* If POSIXLY_CORRECT is not set, then give a warning that there   \
180          are characters following the character constant and that GNU    \
181          printf is ignoring those characters.  If POSIXLY_CORRECT *is*   \
182          set, then don't give the warning.  */                           \
183       if (*++s != 0 && !posixly_correct)                                 \
184         error (0, 0, _(cfcc_msg), s);                                    \
185     }                                                                    \
186   else                                                                   \
187     {                                                                    \
188       errno = 0;                                                         \
189       val = LIB_FUNC_EXPR;                                               \
190       verify (s, end);                                                   \
191     }                                                                    \
192   return val;                                                            \
193 }                                                                        \
194
195 STRTOX (unsigned long int, xstrtoul, (strtoul (s, &end, 0)))
196 STRTOX (long int,          xstrtol,  (strtol  (s, &end, 0)))
197 STRTOX (double,            xstrtod,  (strtod  (s, &end)))
198
199 /* Output a single-character \ escape.  */
200
201 static void
202 print_esc_char (int c)
203 {
204   switch (c)
205     {
206     case 'a':                   /* Alert. */
207       putchar (7);
208       break;
209     case 'b':                   /* Backspace. */
210       putchar (8);
211       break;
212     case 'c':                   /* Cancel the rest of the output. */
213       exit (EXIT_SUCCESS);
214       break;
215     case 'f':                   /* Form feed. */
216       putchar (12);
217       break;
218     case 'n':                   /* New line. */
219       putchar (10);
220       break;
221     case 'r':                   /* Carriage return. */
222       putchar (13);
223       break;
224     case 't':                   /* Horizontal tab. */
225       putchar (9);
226       break;
227     case 'v':                   /* Vertical tab. */
228       putchar (11);
229       break;
230     default:
231       putchar (c);
232       break;
233     }
234 }
235
236 /* Print a \ escape sequence starting at ESCSTART.
237    Return the number of characters in the escape sequence
238    besides the backslash.
239    If OCTAL_0 is nonzero, octal escapes are of the form \0ooo, where o
240    is an octal digit; otherwise they are of the form \ooo.  */
241
242 static int
243 print_esc (const char *escstart, bool octal_0)
244 {
245   register const char *p = escstart + 1;
246   int esc_value = 0;            /* Value of \nnn escape. */
247   int esc_length;               /* Length of \nnn escape. */
248
249   if (!posixly_correct && *p == 'x')
250     {
251       /* A hexadecimal \xhh escape sequence must have 1 or 2 hex. digits.  */
252       for (esc_length = 0, ++p;
253            esc_length < 2 && ISXDIGIT (*p);
254            ++esc_length, ++p)
255         esc_value = esc_value * 16 + hextobin (*p);
256       if (esc_length == 0)
257         error (EXIT_FAILURE, 0, _("missing hexadecimal number in escape"));
258       putchar (esc_value);
259     }
260   else if (isodigit (*p))
261     {
262       /* Parse \0ooo (if octal_0 && *p == '0') or \ooo (otherwise).
263          Allow \ooo if octal_0 && *p != '0'; this is an undocumented
264          extension to POSIX that is compatible with Bash 2.05b.  */
265       for (esc_length = 0, p += octal_0 && *p == '0';
266            esc_length < 3 && isodigit (*p);
267            ++esc_length, ++p)
268         esc_value = esc_value * 8 + octtobin (*p);
269       putchar (esc_value);
270     }
271   else if (*p && strchr ("\"\\abcfnrtv", *p))
272     print_esc_char (*p++);
273   else if (!posixly_correct && (*p == 'u' || *p == 'U'))
274     {
275       char esc_char = *p;
276       unsigned int uni_value;
277
278       uni_value = 0;
279       for (esc_length = (esc_char == 'u' ? 4 : 8), ++p;
280            esc_length > 0;
281            --esc_length, ++p)
282         {
283           if (!ISXDIGIT (*p))
284             error (EXIT_FAILURE, 0, _("missing hexadecimal number in escape"));
285           uni_value = uni_value * 16 + hextobin (*p);
286         }
287
288       /* A universal character name shall not specify a character short
289          identifier in the range 00000000 through 00000020, 0000007F through
290          0000009F, or 0000D800 through 0000DFFF inclusive. A universal
291          character name shall not designate a character in the required
292          character set.  */
293       if ((uni_value <= 0x9f
294            && uni_value != 0x24 && uni_value != 0x40 && uni_value != 0x60)
295           || (uni_value >= 0xd800 && uni_value <= 0xdfff))
296         error (EXIT_FAILURE, 0, _("invalid universal character name \\%c%0*x"),
297                esc_char, (esc_char == 'u' ? 4 : 8), uni_value);
298
299       print_unicode_char (stdout, uni_value, 0);
300     }
301   else
302     {
303       putchar ('\\');
304       if (*p)
305         {
306           putchar (*p);
307           p++;
308         }
309     }
310   return p - escstart - 1;
311 }
312
313 /* Print string STR, evaluating \ escapes. */
314
315 static void
316 print_esc_string (const char *str)
317 {
318   for (; *str; str++)
319     if (*str == '\\')
320       str += print_esc (str, true);
321     else
322       putchar (*str);
323 }
324
325 /* Output a % directive.  START is the start of the directive,
326    LENGTH is its length, and ARGUMENT is its argument.
327    If FIELD_WIDTH or PRECISION is UNSPECIFIED, they are args for
328    '*' values in those fields. */
329
330 static void
331 print_direc (const char *start, size_t length, int field_width,
332              int precision, const char *argument)
333 {
334   char *p;              /* Null-terminated copy of % directive. */
335
336   p = xmalloc ((unsigned) (length + 1));
337   strncpy (p, start, length);
338   p[length] = 0;
339
340   switch (p[length - 1])
341     {
342     case 'd':
343     case 'i':
344       if (field_width == UNSPECIFIED)
345         {
346           if (precision == UNSPECIFIED)
347             printf (p, xstrtol (argument));
348           else
349             printf (p, precision, xstrtol (argument));
350         }
351       else
352         {
353           if (precision == UNSPECIFIED)
354             printf (p, field_width, xstrtol (argument));
355           else
356             printf (p, field_width, precision, xstrtol (argument));
357         }
358       break;
359
360     case 'o':
361     case 'u':
362     case 'x':
363     case 'X':
364       if (field_width == UNSPECIFIED)
365         {
366           if (precision == UNSPECIFIED)
367             printf (p, xstrtoul (argument));
368           else
369             printf (p, precision, xstrtoul (argument));
370         }
371       else
372         {
373           if (precision == UNSPECIFIED)
374             printf (p, field_width, xstrtoul (argument));
375           else
376             printf (p, field_width, precision, xstrtoul (argument));
377         }
378       break;
379
380     case 'f':
381     case 'e':
382     case 'E':
383     case 'g':
384     case 'G':
385       if (field_width == UNSPECIFIED)
386         {
387           if (precision == UNSPECIFIED)
388             printf (p, xstrtod (argument));
389           else
390             printf (p, precision, xstrtod (argument));
391         }
392       else
393         {
394           if (precision == UNSPECIFIED)
395             printf (p, field_width, xstrtod (argument));
396           else
397             printf (p, field_width, precision, xstrtod (argument));
398         }
399       break;
400
401     case 'c':
402       printf (p, *argument);
403       break;
404
405     case 's':
406       if (field_width == UNSPECIFIED)
407         {
408           if (precision == UNSPECIFIED)
409             printf (p, argument);
410           else
411             printf (p, precision, argument);
412         }
413       else
414         {
415           if (precision == UNSPECIFIED)
416             printf (p, field_width, argument);
417           else
418             printf (p, field_width, precision, argument);
419         }
420       break;
421     }
422
423   free (p);
424 }
425
426 /* Print the text in FORMAT, using ARGV (with ARGC elements) for
427    arguments to any `%' directives.
428    Return the number of elements of ARGV used.  */
429
430 static int
431 print_formatted (const char *format, int argc, char **argv)
432 {
433   int save_argc = argc;         /* Preserve original value.  */
434   const char *f;                /* Pointer into `format'.  */
435   const char *direc_start;      /* Start of % directive.  */
436   size_t direc_length;          /* Length of % directive.  */
437   int field_width;              /* Arg to first '*', or UNSPECIFIED if none. */
438   int precision;                /* Arg to second '*', or UNSPECIFIED if none. */
439
440   for (f = format; *f; ++f)
441     {
442       switch (*f)
443         {
444         case '%':
445           direc_start = f++;
446           direc_length = 1;
447           field_width = precision = UNSPECIFIED;
448           if (*f == '%')
449             {
450               putchar ('%');
451               break;
452             }
453           if (*f == 'b')
454             {
455               if (argc > 0)
456                 {
457                   print_esc_string (*argv);
458                   ++argv;
459                   --argc;
460                 }
461               break;
462             }
463           while (*f == ' ' || *f == '#' || *f == '+' || *f == '-')
464             {
465               ++f;
466               ++direc_length;
467             }
468           if (*f == '*')
469             {
470               ++f;
471               ++direc_length;
472               if (argc > 0)
473                 {
474                   field_width = xstrtoul (*argv);
475                   if (field_width == UNSPECIFIED)
476                     error (EXIT_FAILURE, 0, _("invalid field width: %s"),
477                            *argv);
478                   ++argv;
479                   --argc;
480                 }
481               else
482                 field_width = 0;
483             }
484           else
485             while (ISDIGIT (*f))
486               {
487                 ++f;
488                 ++direc_length;
489               }
490           if (*f == '.')
491             {
492               ++f;
493               ++direc_length;
494               if (*f == '*')
495                 {
496                   ++f;
497                   ++direc_length;
498                   if (argc > 0)
499                     {
500                       precision = xstrtoul (*argv);
501                       if (precision == UNSPECIFIED)
502                         error (EXIT_FAILURE, 0, _("invalid precision: %s"),
503                                *argv);
504                       ++argv;
505                       --argc;
506                     }
507                   else
508                     precision = 0;
509                 }
510               else
511                 while (ISDIGIT (*f))
512                   {
513                     ++f;
514                     ++direc_length;
515                   }
516             }
517           if (*f == 'l' || *f == 'L' || *f == 'h')
518             {
519               ++f;
520               ++direc_length;
521             }
522           if (! (*f && strchr ("diouxXfeEgGcs", *f)))
523             error (EXIT_FAILURE, 0, _("%%%c: invalid directive"), *f);
524           ++direc_length;
525           if (argc > 0)
526             {
527               print_direc (direc_start, direc_length, field_width,
528                            precision, *argv);
529               ++argv;
530               --argc;
531             }
532           else
533             print_direc (direc_start, direc_length, field_width,
534                          precision, "");
535           break;
536
537         case '\\':
538           f += print_esc (f, false);
539           break;
540
541         default:
542           putchar (*f);
543         }
544     }
545
546   return save_argc - argc;
547 }
548
549 int
550 main (int argc, char **argv)
551 {
552   char *format;
553   int args_used;
554
555   initialize_main (&argc, &argv);
556   program_name = argv[0];
557   setlocale (LC_ALL, "");
558   bindtextdomain (PACKAGE, LOCALEDIR);
559   textdomain (PACKAGE);
560
561   atexit (close_stdout);
562
563   exit_status = 0;
564
565   /* Don't recognize --help or --version if POSIXLY_CORRECT is set.  */
566   posixly_correct = (getenv ("POSIXLY_CORRECT") != NULL);
567   if (!posixly_correct)
568     parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
569                         usage, AUTHORS, NULL);
570
571   /* The above handles --help and --version.
572      Since there is no other invocation of getopt, handle `--' here.  */
573   if (1 < argc && STREQ (argv[1], "--"))
574     {
575       --argc;
576       ++argv;
577     }
578
579   if (argc <= 1)
580     {
581       fprintf (stderr, _("Usage: %s format [argument...]\n"), program_name);
582       exit (EXIT_FAILURE);
583     }
584
585   format = argv[1];
586   argc -= 2;
587   argv += 2;
588
589   do
590     {
591       args_used = print_formatted (format, argc, argv);
592       argc -= args_used;
593       argv += args_used;
594     }
595   while (args_used > 0 && argc > 0);
596
597   if (argc > 0)
598     error (0, 0,
599            _("warning: ignoring excess arguments, starting with `%s'"),
600            argv[0]);
601
602   exit (exit_status);
603 }