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