c6d476b6feb97387e1850276437fa9b44a0f6b81
[platform/upstream/coreutils.git] / src / printf.c
1 /* printf - format and print data
2    Copyright (C) 1990, 1991 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
16    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 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    \0ooo = octal number (ooo is 0 to 3 digits)
35    \xhhh = hexadecimal number (hhh is 1 to 3 digits)
36
37    Additional directive:
38
39    %b = print an argument string, interpreting backslash escapes
40
41    The `format' argument is re-used as many times as necessary
42    to convert all of the given arguments.
43
44    David MacKenzie <djm@gnu.ai.mit.edu> */
45
46 #ifdef HAVE_CONFIG_H
47 #if defined (CONFIG_BROKETS)
48 /* We use <config.h> instead of "config.h" so that a compilation
49    using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h
50    (which it would do because it found this file in $srcdir).  */
51 #include <config.h>
52 #else
53 #include "config.h"
54 #endif
55 #endif
56
57 #include <stdio.h>
58 #include <ctype.h>
59 #include <sys/types.h>
60 #include <getopt.h>
61
62 #include "system.h"
63 #include "version.h"
64 #include "long-option.h"
65
66 #if !defined (isascii) || defined (STDC_HEADERS)
67 #undef isascii
68 #define isascii(c) 1
69 #endif
70
71 #define ISDIGIT(c) (isascii (c) && isdigit (c))
72 #define ISXDIGIT(c) (isascii (c) && isxdigit (c))
73
74 #ifndef STDC_HEADERS
75 double strtod ();
76 long strtol ();
77 unsigned long strtoul ();
78 #endif
79
80 #define isodigit(c) ((c) >= '0' && (c) <= '7')
81 #define hextobin(c) ((c)>='a'&&(c)<='f' ? (c)-'a'+10 : (c)>='A'&&(c)<='F' ? (c)-'A'+10 : (c)-'0')
82 #define octtobin(c) ((c) - '0')
83
84 char *xmalloc ();
85 void error ();
86
87 static double xstrtod ();
88 static int print_esc ();
89 static int print_formatted ();
90 static long xstrtol ();
91 static unsigned long xstrtoul ();
92 static void print_direc ();
93 static void print_esc_char ();
94 static void print_esc_string ();
95 static void verify ();
96
97 /* The value to return to the calling program.  */
98 static int exit_status;
99
100 /* The name this program was run with. */
101 char *program_name;
102
103 static void
104 usage (status)
105      int status;
106 {
107   fprintf (status == 0 ? stdout : stderr, "\
108 Usage: %s FORMAT [ARGUMENT]...\n\
109   or:  %s OPTION\n\
110 ",
111            program_name, program_name);
112
113   if (status != 0)
114     fprintf (stderr, "Try `%s --help' for more information.\n",
115              program_name);
116   else
117
118     printf ("\
119 \n\
120   --help      display this help and exit\n\
121   --version   output version information and exit\n\
122 \n\
123 FORMAT controls the output as in C printf.  Interpreted sequences are:\n\
124 \n\
125   \\\"      double quote\n\
126   \\0NNN   character with octal value NNN (0 to 3 digits)\n\
127   \\\\      backslash\n\
128   \\a      alert (BEL)\n\
129   \\b      backspace\n\
130   \\c      produce no further output\n\
131   \\f      form feed\n\
132   \\n      new line\n\
133   \\r      carriage return\n\
134   \\t      horizontal tab\n\
135   \\v      vertical tab\n\
136   \\xNNN   character with hexadecimal value NNN (1 to 3 digits)\n\
137 \n\
138   %%%%      a single %%\n\
139   %%b      ARGUMENT as a string with `\\' escapes interpreted\n\
140 \n\
141 and all C format specifications ending with one of diouxXfeEgGcs, with\n\
142 ARGUMENTs converted to proper type first.  Variable widths are handled.\n\
143 ");
144
145   exit (status);
146 }
147
148 void
149 main (argc, argv)
150      int argc;
151      char **argv;
152 {
153   char *format;
154   int args_used;
155
156   program_name = argv[0];
157   exit_status = 0;
158
159   parse_long_options (argc, argv, usage);
160
161   if (argc == 1)
162     {
163       fprintf (stderr, "Usage: %s format [argument...]\n", program_name);
164       exit (1);
165     }
166
167   format = argv[1];
168   argc -= 2;
169   argv += 2;
170
171   do
172     {
173       args_used = print_formatted (format, argc, argv);
174       argc -= args_used;
175       argv += args_used;
176     }
177   while (args_used > 0 && argc > 0);
178
179   exit (exit_status);
180 }
181
182 /* Print the text in FORMAT, using ARGV (with ARGC elements) for
183    arguments to any `%' directives.
184    Return the number of elements of ARGV used.  */
185
186 static int
187 print_formatted (format, argc, argv)
188      char *format;
189      int argc;
190      char **argv;
191 {
192   int save_argc = argc;         /* Preserve original value.  */
193   char *f;                      /* Pointer into `format'.  */
194   char *direc_start;            /* Start of % directive.  */
195   int direc_length;             /* Length of % directive.  */
196   int field_width;              /* Arg to first '*', or -1 if none.  */
197   int precision;                /* Arg to second '*', or -1 if none.  */
198
199   for (f = format; *f; ++f)
200     {
201       switch (*f)
202         {
203         case '%':
204           direc_start = f++;
205           direc_length = 1;
206           field_width = precision = -1;
207           if (*f == '%')
208             {
209               putchar ('%');
210               break;
211             }
212           if (*f == 'b')
213             {
214               if (argc > 0)
215                 {
216                   print_esc_string (*argv);
217                   ++argv;
218                   --argc;
219                 }
220               break;
221             }
222           if (index ("-+ #", *f))
223             {
224               ++f;
225               ++direc_length;
226             }
227           if (*f == '*')
228             {
229               ++f;
230               ++direc_length;
231               if (argc > 0)
232                 {
233                   field_width = xstrtoul (*argv);
234                   ++argv;
235                   --argc;
236                 }
237               else
238                 field_width = 0;
239             }
240           else
241             while (ISDIGIT (*f))
242               {
243                 ++f;
244                 ++direc_length;
245               }
246           if (*f == '.')
247             {
248               ++f;
249               ++direc_length;
250               if (*f == '*')
251                 {
252                   ++f;
253                   ++direc_length;
254                   if (argc > 0)
255                     {
256                       precision = xstrtoul (*argv);
257                       ++argv;
258                       --argc;
259                     }
260                   else
261                     precision = 0;
262                 }
263               else
264                 while (ISDIGIT (*f))
265                   {
266                     ++f;
267                     ++direc_length;
268                   }
269             }
270           if (*f == 'l' || *f == 'L' || *f == 'h')
271             {
272               ++f;
273               ++direc_length;
274             }
275           if (!index ("diouxXfeEgGcs", *f))
276             error (1, 0, "%%%c: invalid directive", *f);
277           ++direc_length;
278           if (argc > 0)
279             {
280               print_direc (direc_start, direc_length, field_width,
281                            precision, *argv);
282               ++argv;
283               --argc;
284             }
285           else
286             print_direc (direc_start, direc_length, field_width,
287                          precision, "");
288           break;
289
290         case '\\':
291           f += print_esc (f);
292           break;
293
294         default:
295           putchar (*f);
296         }
297     }
298
299   return save_argc - argc;
300 }
301
302 /* Print a \ escape sequence starting at ESCSTART.
303    Return the number of characters in the escape sequence
304    besides the backslash. */
305
306 static int
307 print_esc (escstart)
308      char *escstart;
309 {
310   register char *p = escstart + 1;
311   int esc_value = 0;            /* Value of \nnn escape. */
312   int esc_length;               /* Length of \nnn escape. */
313
314   /* \0ooo and \xhhh escapes have maximum length of 3 chars. */
315   if (*p == 'x')
316     {
317       for (esc_length = 0, ++p;
318            esc_length < 3 && ISXDIGIT (*p);
319            ++esc_length, ++p)
320         esc_value = esc_value * 16 + hextobin (*p);
321       if (esc_length == 0)
322         error (1, 0, "missing hexadecimal number in escape");
323       putchar (esc_value);
324     }
325   else if (*p == '0')
326     {
327       for (esc_length = 0, ++p;
328            esc_length < 3 && isodigit (*p);
329            ++esc_length, ++p)
330         esc_value = esc_value * 8 + octtobin (*p);
331       putchar (esc_value);
332     }
333   else if (index ("\"\\abcfnrtv", *p))
334     print_esc_char (*p++);
335   else
336     error (1, 0, "\\%c: invalid escape", *p);
337   return p - escstart - 1;
338 }
339
340 /* Output a single-character \ escape.  */
341
342 static void
343 print_esc_char (c)
344      char c;
345 {
346   switch (c)
347     {
348     case 'a':                   /* Alert. */
349       putchar (7);
350       break;
351     case 'b':                   /* Backspace. */
352       putchar (8);
353       break;
354     case 'c':                   /* Cancel the rest of the output. */
355       exit (0);
356       break;
357     case 'f':                   /* Form feed. */
358       putchar (12);
359       break;
360     case 'n':                   /* New line. */
361       putchar (10);
362       break;
363     case 'r':                   /* Carriage return. */
364       putchar (13);
365       break;
366     case 't':                   /* Horizontal tab. */
367       putchar (9);
368       break;
369     case 'v':                   /* Vertical tab. */
370       putchar (11);
371       break;
372     default:
373       putchar (c);
374       break;
375     }
376 }
377
378 /* Print string STR, evaluating \ escapes. */
379
380 static void
381 print_esc_string (str)
382      char *str;
383 {
384   for (; *str; str++)
385     if (*str == '\\')
386       str += print_esc (str);
387     else
388       putchar (*str);
389 }
390
391 /* Output a % directive.  START is the start of the directive,
392    LENGTH is its length, and ARGUMENT is its argument.
393    If FIELD_WIDTH or PRECISION is non-negative, they are args for
394    '*' values in those fields. */
395
396 static void
397 print_direc (start, length, field_width, precision, argument)
398      char *start;
399      int length;
400      int field_width;
401      int precision;
402      char *argument;
403 {
404   char *p;              /* Null-terminated copy of % directive. */
405
406   p = xmalloc ((unsigned) (length + 1));
407   strncpy (p, start, length);
408   p[length] = 0;
409
410   switch (p[length - 1])
411     {
412     case 'd':
413     case 'i':
414       if (field_width < 0)
415         {
416           if (precision < 0)
417             printf (p, xstrtol (argument));
418           else
419             printf (p, precision, xstrtol (argument));
420         }
421       else
422         {
423           if (precision < 0)
424             printf (p, field_width, xstrtol (argument));
425           else
426             printf (p, field_width, precision, xstrtol (argument));
427         }
428       break;
429
430     case 'o':
431     case 'u':
432     case 'x':
433     case 'X':
434       if (field_width < 0)
435         {
436           if (precision < 0)
437             printf (p, xstrtoul (argument));
438           else
439             printf (p, precision, xstrtoul (argument));
440         }
441       else
442         {
443           if (precision < 0)
444             printf (p, field_width, xstrtoul (argument));
445           else
446             printf (p, field_width, precision, xstrtoul (argument));
447         }
448       break;
449
450     case 'f':
451     case 'e':
452     case 'E':
453     case 'g':
454     case 'G':
455       if (field_width < 0)
456         {
457           if (precision < 0)
458             printf (p, xstrtod (argument));
459           else
460             printf (p, precision, xstrtod (argument));
461         }
462       else
463         {
464           if (precision < 0)
465             printf (p, field_width, xstrtod (argument));
466           else
467             printf (p, field_width, precision, xstrtod (argument));
468         }
469       break;
470
471     case 'c':
472       printf (p, *argument);
473       break;
474
475     case 's':
476       if (field_width < 0)
477         {
478           if (precision < 0)
479             printf (p, argument);
480           else
481             printf (p, precision, argument);
482         }
483       else
484         {
485           if (precision < 0)
486             printf (p, field_width, argument);
487           else
488             printf (p, field_width, precision, argument);
489         }
490       break;
491     }
492
493   free (p);
494 }
495
496 static unsigned long
497 xstrtoul (s)
498      char *s;
499 {
500   char *end;
501   unsigned long val;
502
503   errno = 0;
504   val = strtoul (s, &end, 0);
505   verify (s, end);
506   return val;
507 }
508
509 static long
510 xstrtol (s)
511      char *s;
512 {
513   char *end;
514   long val;
515
516   errno = 0;
517   val = strtol (s, &end, 0);
518   verify (s, end);
519   return val;
520 }
521
522 static double
523 xstrtod (s)
524      char *s;
525 {
526   char *end;
527   double val;
528
529   errno = 0;
530   val = strtod (s, &end);
531   verify (s, end);
532   return val;
533 }
534
535 static void
536 verify (s, end)
537      char *s, *end;
538 {
539   if (errno)
540     {
541       error (0, errno, "%s", s);
542       exit_status = 1;
543     }
544   else if (*end)
545     {
546       if (s == end)
547         error (0, 0, "%s: expected a numeric value", s);
548       else
549         error (0, 0, "%s: value not completely converted", s);
550       exit_status = 1;
551     }
552 }