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