9d1493bc40c952596eb93a8fd3faa00702ebaa56
[platform/upstream/bash.git] / builtins / printf.def
1 This file is printf.def, from which is created printf.c.
2 It implements the builtin "printf" in Bash.
3
4 Copyright (C) 1997 Free Software Foundation, Inc.
5
6 This file is part of GNU Bash, the Bourne Again SHell.
7
8 Bash is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 1, or (at your option) any later
11 version.
12
13 Bash is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16 for more details.
17
18 You should have received a copy of the GNU General Public License along
19 with Bash; see the file COPYING.  If not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
21
22 $PRODUCES printf.c
23
24 $BUILTIN printf
25 $FUNCTION printf_builtin
26 $SHORT_DOC printf format [arguments]
27 printf formats and prints ARGUMENTS under control of the FORMAT. FORMAT
28 is a character string which contains three types of objects: plain
29 characters, which are simply copied to standard output, character escape
30 sequences which are converted and copied to the standard output, and
31 format specifications, each of which causes printing of the next successive
32 argument.  In addition to the standard printf(1) formats, %b means to
33 expand backslash escape sequences in the corresponding argument, and %q
34 means to quote the argument in a way that can be reused as shell input.
35 $END
36
37 #include <config.h>
38
39 #include "../bashtypes.h"
40
41 #include <errno.h>
42 #if defined (HAVE_LIMITS_H)
43 #  include <limits.h>
44 #else
45    /* Assume 32-bit ints and longs. */
46 #  define LONG_MAX              2147483647L
47 #  define LONG_MIN              (-2147483647L-1)
48 #  define INT_MAX               2147483647
49 #  define INT_MIN               (-2147483647-1)
50 #endif
51
52 #include <stdio.h>
53 #include <ctype.h>
54
55 #include "../bashansi.h"
56 #include "../shell.h"
57 #include "../stdc.h"
58 #include "bashgetopt.h"
59
60 #if !defined (errno)
61 extern int errno;
62 #endif
63
64 #define PF(f, func) \
65   do { \
66     if (fieldwidth && precision) \
67       (void)printf(f, fieldwidth, precision, func); \
68     else if (fieldwidth && precision == 0) \
69       (void)printf(f, fieldwidth, func); \
70     else if (precision) \
71       (void)printf(f, precision, func); \
72     else \
73       (void)printf(f, func); \
74   } while (0)
75
76 #define PRETURN(value) \
77   do { free (format); fflush (stdout); return (value); } while (0)
78
79 #define  SKIP1 "#-+ 0"
80 #define  SKIP2 "*0123456789"
81
82 static void printstr __P((char *, char *, int, int, int));
83 static char *bexpand __P((char *, int, int *, int *));
84 static char *mklong __P((char *, int));
85 static int getchr __P((void));
86 static char *getstr __P((void));
87 static int  getint __P((void));
88 static int getlong __P((long *));
89 static int getulong __P((unsigned long *));
90 static double getdouble __P((void));
91 static int asciicode __P((void));
92
93 static WORD_LIST *garglist;
94 static int retval;
95
96 extern char *backslash_quote ();
97
98 int
99 printf_builtin (list)
100      WORD_LIST *list;
101 {
102   int ch, end, fieldwidth, precision, foundmod;
103   char convch, nextch, *format, *fmt, *start;
104
105   retval = EXECUTION_SUCCESS;
106   reset_internal_getopt ();
107   while ((ch = internal_getopt (list, "")) != -1)
108     {
109       switch (ch)
110         {
111         case '?':
112         default:
113           builtin_usage();
114           return (EX_USAGE);
115         }
116     }
117   list = loptend;
118
119   if (list == 0)
120     {
121       builtin_usage ();
122       return (EX_USAGE);
123     }
124
125   if (list->word->word == 0 || list->word->word[0] == '\0')
126     return (EXECUTION_SUCCESS);
127
128   format = ansicstr (list->word->word, strlen (list->word->word), (int *)NULL, (int *)NULL);
129
130   garglist = list->next;
131
132   /* If the format string is empty after preprocessing, return immediately. */
133   if (format == 0 || *format == 0)
134     return (EXECUTION_SUCCESS);
135           
136   /* Basic algorithm is to scan the format string for conversion
137      specifications -- once one is found, find out if the field
138      width or precision is a '*'; if it is, gather up value.  Note,
139      format strings are reused as necessary to use up the provided
140      arguments, arguments of zero/null string are provided to use
141      up the format string. */
142
143   do
144     {
145       /* find next format specification */
146       for (fmt = format; *fmt; fmt++)
147         {
148           precision = fieldwidth = foundmod = 0;
149
150           if (*fmt != '%')
151             {
152               putchar (*fmt);
153               continue;
154             }
155
156           /* ASSERT(*fmt == '%') */
157           start = fmt++;
158
159           if (*fmt == '%')              /* %% prints a % */
160             {
161               putchar ('%');
162               continue;
163             }
164
165           /* found format specification, skip to field width */
166           for (; *fmt && strchr(SKIP1, *fmt); ++fmt)
167             ;
168           fieldwidth = (*fmt == '*') ? getint () : 0;
169
170           /* skip to possible '.', get following precision */
171           for (; *fmt && strchr(SKIP2, *fmt); ++fmt)
172             ;
173           if (*fmt == '.')
174             {
175               ++fmt;
176               precision = (*fmt == '*') ? getint () : 0;
177             }
178
179           /* skip to conversion char */
180           for (; *fmt && strchr(SKIP2, *fmt); ++fmt)
181             ;
182           if (*fmt == 0)
183             {
184               builtin_error ("`%s': missing format character", start);
185               PRETURN (EXECUTION_FAILURE);
186             }
187
188           /* skip possible format modifiers */
189           if (*fmt == 'l' || *fmt == 'L' || *fmt == 'h')
190             {
191               fmt++;
192               foundmod = 1;
193             }
194             
195           convch = *fmt;
196           nextch = fmt[1];
197           fmt[1] = '\0';
198           switch(convch)
199             {
200             case 'c':
201               {
202                 char p;
203
204                 p = getchr ();
205                 PF(start, p);
206                 break;
207               }
208
209             case 's':
210               {
211                 char *p;
212
213                 p = getstr ();
214                 PF(start, p);
215                 break;
216               }
217
218             case 'b':           /* expand escapes in argument */
219               {
220                 char *p, *xp;
221                 int rlen;
222
223                 p = getstr ();
224                 ch = rlen = 0;
225                 xp = bexpand (p, strlen (p), &ch, &rlen);
226
227                 if (xp)
228                   {
229                     /* Have to use printstr because of possible NUL bytes
230                        in XP -- printf does not handle that well. */
231                     printstr (start, xp, rlen, fieldwidth, precision);
232                     free (xp);
233                   }
234
235                 if (ch)
236                   PRETURN (retval);
237                 break;
238               }
239
240             case 'q':           /* print with shell quoting */
241               {
242                 char *p, *xp;
243
244                 p = getstr ();
245                 xp = backslash_quote (p);
246                 if (xp)
247                   {
248                     /* Use printstr to get fieldwidth and precision right. */
249                     printstr (start, xp, strlen (xp), fieldwidth, precision);
250                     free (xp);
251                   }
252                 break;
253               }
254
255             case 'd':
256             case 'i':
257               {
258                 long p;
259                 char *f;
260
261                 if (foundmod == 0 && ((f = mklong (start, convch)) == NULL))
262                   PRETURN (EXECUTION_FAILURE);
263                 else
264                   f = start;
265                 if (getlong (&p))
266                   PRETURN (EXECUTION_FAILURE);
267                 PF(f, p);
268                 break;
269               }
270
271             case 'o':
272             case 'u':
273             case 'x':
274             case 'X':
275               {
276                 unsigned long p;
277                 char *f;
278
279                 if (foundmod == 0 && ((f = mklong (start, convch)) == NULL))
280                   PRETURN (EXECUTION_FAILURE);
281                 else
282                   f = start;
283                 if (getulong (&p))
284                   PRETURN (EXECUTION_FAILURE);
285                 PF (f, p);
286                 break;
287               }
288
289             case 'e':
290             case 'E':
291             case 'f':
292             case 'g':
293             case 'G':
294               {
295                 double p;
296
297                 p = getdouble ();
298                 PF(start, p);
299                 break;
300               }
301
302             /* We output unrecognized format characters, but we print a
303                warning message and return a failure exit status. */
304             default:
305               builtin_error ("`%c': illegal format character", convch);
306               PRETURN (EXECUTION_FAILURE);
307             }
308
309           fmt[1] = nextch;
310         }
311     }
312   while (garglist && garglist != list->next);
313
314   PRETURN (retval);
315 }
316
317 /* We duplicate a lot of what printf(3) does here. */
318 static void
319 printstr (fmt, string, len, fieldwidth, precision)
320      char *fmt;                 /* format */
321      char *string;              /* expanded string argument */
322      int len;                   /* length of expanded string */
323      int fieldwidth;            /* argument for width of `*' */
324      int precision;             /* argument for precision of `*' */
325 {
326 #if 0
327   char *s;
328 #endif
329   int padlen, nc, ljust, i;
330   int fw, pr;                   /* fieldwidth and precision */
331
332   if (string == 0 || *string == '\0')
333     return;
334
335 #if 0
336   s = fmt;
337 #endif
338   if (*fmt == '%')
339     fmt++;
340
341   ljust = fw = pr = 0;
342
343   /* skip flags */
344   while (*fmt == '#' || *fmt == '-' || *fmt == '+' || *fmt == ' ' || *fmt == '0')
345     {
346       if (*fmt == '-')
347         ljust = 1;
348       fmt++;
349     }
350
351   /* get fieldwidth, if present */
352   if (*fmt == '*')
353     {
354       fmt++;
355       fw = fieldwidth;
356     }
357   else if (isdigit (*fmt))
358     {
359       fw = *fmt++ - '0';
360       while (isdigit (*fmt))
361         fw = (fw * 10) + (*fmt++ - '0');
362     }
363
364   /* get precision, if present */
365   if (*fmt == '.')
366     {
367       fmt++;
368       if (*fmt == '*')
369         {
370           fmt++;
371           pr = precision;
372         }
373       else if (isdigit (*fmt))
374         {
375           pr = *fmt++ - '0';
376           while (isdigit (*fmt))
377             pr = (pr * 10) + (*fmt++ - '0');
378         }
379     }
380
381 #if 0
382   /* If we remove this, get rid of `s'. */
383   if (*fmt != 'b' && *fmt != 'q')
384     {
385       internal_error ("format parsing problem: %s", s);
386       fw = pr = 0;
387     }
388 #endif
389
390   /* chars from string to print */
391   nc = (pr > 0 && pr <= len) ? pr : len;
392
393   padlen = fw - nc;
394   if (padlen < 0)
395     padlen = 0;
396   if (ljust)
397     padlen = -padlen;
398
399   /* leading pad characters */
400   for (; padlen > 0; padlen--)
401     putchar (' ');
402
403   /* output NC characters from STRING */
404   for (i = 0; i < nc; i++)
405     putchar (string[i]);
406
407   /* output any necessary trailing padding */
408   for (; padlen < 0; padlen++)
409     putchar (' ');
410 }
411   
412 /* Convert STRING by expanding the escape sequences specified by the
413    POSIX standard for printf's `%b' format string.  If SAWC is non-null,
414    recognize `\c' and use that as a string terminator.  If we see \c, set
415    *SAWC to 1 before returning.  LEN is the length of STRING. */
416
417 #ifdef isoctal
418 #undef isoctal
419 #endif
420
421 #define isoctal(c)      ((c) >= '0' && (c) <= '7')
422
423 #define OCTVALUE(c)     ((c) - '0')
424
425 #ifndef isxdigit
426 #  define isxdigit(c)   (isdigit((c)) || ((c) >= 'a' && (c) <= 'f') || ((c) >= 'A' && (c) <= 'F'))
427 #endif
428
429 #define HEXVALUE(c) \
430   ((c) >= 'a' && (c) <= 'f' ? (c)-'a'+10 : (c) >= 'A' && (c) <= 'F' ? (c)-'A'+10 : (c)-'0')
431   
432 static char *
433 bexpand (string, len, sawc, lenp)
434      char *string;
435      int len, *sawc, *lenp;
436 {
437   int c, temp;
438   char *ret, *r, *s;
439
440   if (string == 0 || *string == '\0')
441     {
442       if (sawc)
443         *sawc = 0;
444       if (lenp)
445         *lenp = 0;
446       return ((char *)NULL);
447     }
448
449   ret = xmalloc (len + 1);
450   for (r = ret, s = string; s && *s; )
451     {
452       c = *s++;
453       if (c != '\\' || *s == '\0')
454         {
455           *r++ = c;
456           continue;
457         }
458
459       switch (c = *s++)
460         {
461 #if defined (__STDC__)
462         case 'a': c = '\a'; break;
463 #else
464         case 'a': c = '\007'; break;
465 #endif
466
467         case 'b': c = '\b'; break;
468
469         case 'e': c = '\033'; break;    /* ESC -- non-ANSI */
470
471         case 'f': c = '\f'; break;
472
473         case 'n': c = '\n'; break;
474
475         case 'r': c = '\r'; break;
476
477         case 't': c = '\t'; break;
478
479         case 'v': c = '\v'; break;
480
481         /* %b octal constants are `\0' followed by one, two, or three
482            octal digits... */
483         case '0':
484           for (temp = 3, c = 0; isoctal (*s) && temp--; s++)
485             c = (c * 8) + OCTVALUE (*s);
486           break;
487
488         /* but, as an extension, the other echo-like octal escape
489            sequences are supported as well. */
490         case '1': case '2': case '3': case '4':
491         case '5': case '6': case '7':
492           for (temp = 2, c -= '0'; isoctal (*s) && temp--; s++)
493             c = (c * 8) + OCTVALUE (*s);
494           break;
495
496         /* And, as another extension, we allow \xNNN, where each N is a
497            hex digit. */
498         case 'x':
499           for (temp = 3, c = 0; isxdigit (*s) && temp--; s++)
500             c = (c * 16) + HEXVALUE (*s);
501           if (temp == 3)
502             {
503               builtin_error ("missing hex digit for \\x");
504               *r++ = '\\';
505               c = 'x';
506             }
507           break;
508
509         case '\\':
510 #if 0
511         case '\'':              /* XXX */
512         case '"':               /* XXX */
513 #endif
514           break;
515
516         case 'c':
517           if (sawc)
518             *sawc = 1;
519           *r = '\0';
520           if (lenp)
521             *lenp = r - ret;
522           return ret;
523
524         /* other backslash escapes are passed through unaltered */
525         default: *r++ = '\\'; break;
526         }
527
528       *r++ = c;
529     }
530
531   *r = '\0';
532   if (lenp)
533     *lenp = r - ret;
534   return ret;
535 }
536
537 static char *
538 mklong (str, ch)
539      char *str;
540      int ch;
541 {
542   static char copy[64];
543   int len;
544
545   len = strlen (str) + 2;
546   FASTCOPY (str, copy, len - 3);
547   copy[len - 3] = 'l';
548   copy[len - 2] = ch;
549   copy[len - 1] = '\0';
550   return (copy);
551 }
552
553 static int
554 getchr ()
555 {
556   int ret;
557
558   if (garglist == 0)
559     return ('\0');
560
561   ret = (int)garglist->word->word[0];
562   garglist = garglist->next;
563   return ret;
564 }
565
566 static char *
567 getstr ()
568 {
569   char *ret;
570
571   if (garglist == 0)
572     return ("");
573
574   ret = garglist->word->word;
575   garglist = garglist->next;
576   return ret;
577 }
578
579 static int
580 getint ()
581 {
582   long ret;
583
584   if (getlong (&ret))
585     return (0);
586
587   if (ret > INT_MAX)
588     {
589       builtin_error ("%s: %s", garglist->word->word, strerror(ERANGE));
590       return (0);
591     }
592
593   return ((int)ret);
594 }
595
596 static int
597 getlong (lp)
598      long *lp;
599 {
600   long ret;
601
602   if (garglist == 0)
603     {
604       *lp = 0L;
605       return (0);
606     }
607
608   if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"')
609     {
610       *lp =  (long)asciicode ();
611       return (0);
612     }
613
614   errno = 0;
615   /* legal_number does not currently detect overflow, but it should.
616      Someday it will. */
617   if (legal_number (garglist->word->word, &ret) == 0)
618     {
619       builtin_error ("%s: illegal number", garglist->word->word);
620       return (1);
621     }
622   else if (errno == ERANGE)
623     {
624       builtin_error ("%s: %s", garglist->word->word, strerror(ERANGE));
625       return (1);
626     }
627
628   *lp = ret;
629   garglist = garglist->next;
630   return (0);
631 }
632
633 static int
634 getulong (ulp)
635      unsigned long *ulp;
636 {
637   unsigned long ret;
638   char *ep;
639
640   if (garglist == 0)
641     {
642       *ulp = (unsigned long)0;
643       return (0);
644     }
645
646   if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"')
647     {
648       *ulp =  (unsigned long)asciicode ();
649       return (0);
650     }
651
652   errno = 0;
653   ret = strtoul (garglist->word->word, &ep, 0);
654   
655   if (*ep)
656     {
657       builtin_error ("%s: illegal number", garglist->word->word);
658       return (1);
659     }
660   else if (errno == ERANGE)
661     {
662       builtin_error ("%s: %s", garglist->word->word, strerror(ERANGE));
663       return (1);
664     }
665
666   *ulp = ret;
667   garglist = garglist->next;
668   return (0);
669 }
670
671 static double
672 getdouble ()
673 {
674   double ret;
675
676   if (garglist == 0)
677     return ((double)0);
678
679   if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"')
680     return ((double)asciicode ());
681
682   /* This should use strtod if it is available. */
683   ret = atof (garglist->word->word);
684   garglist = garglist->next;
685   return (ret);
686 }
687
688 /* NO check is needed for garglist here. */
689 static int
690 asciicode ()
691 {
692   register int ch;
693
694   ch = garglist->word->word[1];
695   garglist = garglist->next;
696   return (ch);
697 }