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