Imported from ../bash-2.05.tar.gz.
[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 2, 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 int tescape __P((char *, int, char *, int *));
84 static char *bexpand __P((char *, int, int *, int *));
85 static char *mklong __P((char *, int));
86 static int getchr __P((void));
87 static char *getstr __P((void));
88 static int  getint __P((void));
89 static int getlong __P((long *));
90 static int getulong __P((unsigned long *));
91 static int getdouble __P((double *));
92 static int asciicode __P((void));
93
94 static WORD_LIST *garglist;
95 static int retval;
96
97 extern char *sh_backslash_quote ();
98
99 int
100 printf_builtin (list)
101      WORD_LIST *list;
102 {
103   int ch, end, fieldwidth, precision, foundmod, fmtlen;
104   char convch, nextch, *format, *fmt, *start;
105
106   retval = EXECUTION_SUCCESS;
107   reset_internal_getopt ();
108   while ((ch = internal_getopt (list, "")) != -1)
109     {
110       switch (ch)
111         {
112         case '?':
113         default:
114           builtin_usage();
115           return (EX_USAGE);
116         }
117     }
118   list = loptend;
119
120   if (list == 0)
121     {
122       builtin_usage ();
123       return (EX_USAGE);
124     }
125
126   if (list->word->word == 0 || list->word->word[0] == '\0')
127     return (EXECUTION_SUCCESS);
128
129   format = list->word->word;
130
131   garglist = list->next;
132
133   /* If the format string is empty after preprocessing, return immediately. */
134   if (format == 0 || *format == 0)
135     return (EXECUTION_SUCCESS);
136           
137   /* Basic algorithm is to scan the format string for conversion
138      specifications -- once one is found, find out if the field
139      width or precision is a '*'; if it is, gather up value.  Note,
140      format strings are reused as necessary to use up the provided
141      arguments, arguments of zero/null string are provided to use
142      up the format string. */
143
144   do
145     {
146       /* find next format specification */
147       for (fmt = format; *fmt; fmt++)
148         {
149           precision = fieldwidth = foundmod = 0;
150
151           if (*fmt == '\\')
152             {
153               fmt++;
154               /* A NULL third argument to tescape means to not do special
155                  processing for \c. */
156               fmt += tescape (fmt, 1, &nextch, (int *)NULL);
157               putchar (nextch);
158               fmt--;    /* for loop will increment it for us again */
159               continue;
160             }
161
162           if (*fmt != '%')
163             {
164               putchar (*fmt);
165               continue;
166             }
167
168           /* ASSERT(*fmt == '%') */
169           start = fmt++;
170
171           if (*fmt == '%')              /* %% prints a % */
172             {
173               putchar ('%');
174               continue;
175             }
176
177           /* found format specification, skip to field width */
178           for (; *fmt && strchr(SKIP1, *fmt); ++fmt)
179             ;
180           fieldwidth = (*fmt == '*') ? getint () : 0;
181
182           /* skip to possible '.', get following precision */
183           for (; *fmt && strchr(SKIP2, *fmt); ++fmt)
184             ;
185           if (*fmt == '.')
186             {
187               ++fmt;
188               precision = (*fmt == '*') ? getint () : 0;
189             }
190
191           /* skip to conversion char */
192           for (; *fmt && strchr(SKIP2, *fmt); ++fmt)
193             ;
194
195           /* skip possible format modifiers */
196           if (*fmt == 'l' || *fmt == 'L' || *fmt == 'h')
197             {
198               fmt++;
199               foundmod = 1;
200             }
201             
202           if (*fmt == 0)
203             {
204               builtin_error ("`%s': missing format character", start);
205               PRETURN (EXECUTION_FAILURE);
206             }
207
208           convch = *fmt;
209           nextch = fmt[1];
210           fmt[1] = '\0';
211           switch(convch)
212             {
213             case 'c':
214               {
215                 char p;
216
217                 p = getchr ();
218                 PF(start, p);
219                 break;
220               }
221
222             case 's':
223               {
224                 char *p;
225
226                 p = getstr ();
227                 PF(start, p);
228                 break;
229               }
230
231             case 'b':           /* expand escapes in argument */
232               {
233                 char *p, *xp;
234                 int rlen;
235
236                 p = getstr ();
237                 ch = rlen = 0;
238                 xp = bexpand (p, strlen (p), &ch, &rlen);
239
240                 if (xp)
241                   {
242                     /* Have to use printstr because of possible NUL bytes
243                        in XP -- printf does not handle that well. */
244                     printstr (start, xp, rlen, fieldwidth, precision);
245                     free (xp);
246                   }
247
248                 if (ch)
249                   PRETURN (retval);
250                 break;
251               }
252
253             case 'q':           /* print with shell quoting */
254               {
255                 char *p, *xp;
256
257                 p = getstr ();
258                 xp = sh_backslash_quote (p);
259                 if (xp)
260                   {
261                     /* Use printstr to get fieldwidth and precision right. */
262                     printstr (start, xp, strlen (xp), fieldwidth, precision);
263                     free (xp);
264                   }
265                 break;
266               }
267
268             case 'd':
269             case 'i':
270               {
271                 long p;
272                 char *f;
273
274                 if (foundmod == 0 && ((f = mklong (start, convch)) == NULL))
275                   PRETURN (EXECUTION_FAILURE);
276                 else
277                   f = start;
278                 if (getlong (&p))
279                   PRETURN (EXECUTION_FAILURE);
280                 PF(f, p);
281                 break;
282               }
283
284             case 'o':
285             case 'u':
286             case 'x':
287             case 'X':
288               {
289                 unsigned long p;
290                 char *f;
291
292                 if (foundmod == 0 && ((f = mklong (start, convch)) == NULL))
293                   PRETURN (EXECUTION_FAILURE);
294                 else
295                   f = start;
296                 if (getulong (&p))
297                   PRETURN (EXECUTION_FAILURE);
298                 PF (f, p);
299                 break;
300               }
301
302             case 'e':
303             case 'E':
304             case 'f':
305             case 'g':
306             case 'G':
307               {
308                 double p;
309
310                 if (getdouble (&p))
311                   PRETURN (EXECUTION_FAILURE);
312                 PF(start, p);
313                 break;
314               }
315
316             /* We don't output unrecognized format characters; we print an
317                error message and return a failure exit status. */
318             default:
319               builtin_error ("`%c': invalid format character", convch);
320               PRETURN (EXECUTION_FAILURE);
321             }
322
323           fmt[1] = nextch;
324         }
325     }
326   while (garglist && garglist != list->next);
327
328   PRETURN (retval);
329 }
330
331 /* We duplicate a lot of what printf(3) does here. */
332 static void
333 printstr (fmt, string, len, fieldwidth, precision)
334      char *fmt;                 /* format */
335      char *string;              /* expanded string argument */
336      int len;                   /* length of expanded string */
337      int fieldwidth;            /* argument for width of `*' */
338      int precision;             /* argument for precision of `*' */
339 {
340 #if 0
341   char *s;
342 #endif
343   int padlen, nc, ljust, i;
344   int fw, pr;                   /* fieldwidth and precision */
345
346   if (string == 0 || *string == '\0')
347     return;
348
349 #if 0
350   s = fmt;
351 #endif
352   if (*fmt == '%')
353     fmt++;
354
355   ljust = fw = pr = 0;
356
357   /* skip flags */
358   while (*fmt == '#' || *fmt == '-' || *fmt == '+' || *fmt == ' ' || *fmt == '0')
359     {
360       if (*fmt == '-')
361         ljust = 1;
362       fmt++;
363     }
364
365   /* get fieldwidth, if present */
366   if (*fmt == '*')
367     {
368       fmt++;
369       fw = fieldwidth;
370     }
371   else if (isdigit (*fmt))
372     {
373       fw = *fmt++ - '0';
374       while (isdigit (*fmt))
375         fw = (fw * 10) + (*fmt++ - '0');
376     }
377
378   /* get precision, if present */
379   if (*fmt == '.')
380     {
381       fmt++;
382       if (*fmt == '*')
383         {
384           fmt++;
385           pr = precision;
386         }
387       else if (isdigit (*fmt))
388         {
389           pr = *fmt++ - '0';
390           while (isdigit (*fmt))
391             pr = (pr * 10) + (*fmt++ - '0');
392         }
393     }
394
395 #if 0
396   /* If we remove this, get rid of `s'. */
397   if (*fmt != 'b' && *fmt != 'q')
398     {
399       internal_error ("format parsing problem: %s", s);
400       fw = pr = 0;
401     }
402 #endif
403
404   /* chars from string to print */
405   nc = (pr > 0 && pr <= len) ? pr : len;
406
407   padlen = fw - nc;
408   if (padlen < 0)
409     padlen = 0;
410   if (ljust)
411     padlen = -padlen;
412
413   /* leading pad characters */
414   for (; padlen > 0; padlen--)
415     putchar (' ');
416
417   /* output NC characters from STRING */
418   for (i = 0; i < nc; i++)
419     putchar (string[i]);
420
421   /* output any necessary trailing padding */
422   for (; padlen < 0; padlen++)
423     putchar (' ');
424 }
425   
426 /* Convert STRING by expanding the escape sequences specified by the
427    POSIX standard for printf's `%b' format string.  If SAWC is non-null,
428    recognize `\c' and use that as a string terminator.  If we see \c, set
429    *SAWC to 1 before returning.  LEN is the length of STRING. */
430
431 #ifdef isoctal
432 #undef isoctal
433 #endif
434
435 #define isoctal(c)      ((c) >= '0' && (c) <= '7')
436
437 #define OCTVALUE(c)     ((c) - '0')
438
439 #ifndef isxdigit
440 #  define isxdigit(c)   (isdigit((c)) || ((c) >= 'a' && (c) <= 'f') || ((c) >= 'A' && (c) <= 'F'))
441 #endif
442
443 #define HEXVALUE(c) \
444   ((c) >= 'a' && (c) <= 'f' ? (c)-'a'+10 : (c) >= 'A' && (c) <= 'F' ? (c)-'A'+10 : (c)-'0')
445
446 /* Translate a single backslash-escape sequence starting at ESTART (the
447    character after the backslash) and return the number of characters
448    consumed by the sequence.  CP is the place to return the translated
449    value.  *SAWC is set to 1 if the escape sequence was \c, since that means
450    to short-circuit the rest of the processing.  If SAWC is null, we don't
451    do the \c short-circuiting, and \c is treated as an unrecognized escape
452    sequence.  */
453 static int
454 tescape (estart, trans_squote, cp, sawc)
455      char *estart;
456      int trans_squote;
457      char *cp;
458      int *sawc;
459 {
460   register char *p;
461   int temp, c, evalue;
462
463   p = estart;
464
465   switch (c = *p++)
466     {
467 #if defined (__STDC__)
468       case 'a': *cp = '\a'; break;
469 #else
470       case 'a': *cp = '\007'; break;
471 #endif
472
473       case 'b': *cp = '\b'; break;
474
475       case 'e':
476       case 'E': *cp = '\033'; break;    /* ESC -- non-ANSI */
477
478       case 'f': *cp = '\f'; break;
479
480       case 'n': *cp = '\n'; break;
481
482       case 'r': *cp = '\r'; break;
483
484       case 't': *cp = '\t'; break;
485
486       case 'v': *cp = '\v'; break;
487
488       /* %b octal constants are `\0' followed by one, two, or three
489          octal digits... */
490       case '0':
491         for (temp = 3, evalue = 0; isoctal (*p) && temp--; p++)
492           evalue = (evalue * 8) + OCTVALUE (*p);
493         *cp = evalue;
494         break;
495
496       /* but, as an extension, the other echo-like octal escape
497          sequences are supported as well. */
498       case '1': case '2': case '3': case '4':
499       case '5': case '6': case '7':
500         for (temp = 2, evalue = c - '0'; isoctal (*p) && temp--; p++)
501           evalue = (evalue * 8) + OCTVALUE (*p);
502         *cp = evalue;
503         break;
504
505       /* And, as another extension, we allow \xNNN, where each N is a
506          hex digit. */
507       case 'x':
508         for (temp = 3, evalue = 0; isxdigit (*p) && temp--; p++)
509           evalue = (evalue * 16) + HEXVALUE (*p);
510         if (temp == 3)
511           {
512             builtin_error ("missing hex digit for \\x");
513             *cp = '\\';
514             return 0;
515           }
516         *cp = evalue;
517         break;
518
519       case '\\':        /* \\ -> \ */
520         *cp = c;
521         break;
522
523       case '\'':        /* TRANS_SQUOTE != 0 means \' -> ' */
524         if (trans_squote)
525           *cp = c;
526         else
527           {
528             *cp = '\\';
529             return 0;
530           }
531         break;
532
533       case 'c':
534         if (sawc)
535           {
536             *sawc = 1;
537             break;
538           }
539       /* other backslash escapes are passed through unaltered */
540       default:
541         *cp = '\\';
542         return 0;
543       }
544   return (p - estart);
545 }
546
547 static char *
548 bexpand (string, len, sawc, lenp)
549      char *string;
550      int len, *sawc, *lenp;
551 {
552   int temp;
553   char *ret, *r, *s, c;
554
555   if (string == 0 || *string == '\0')
556     {
557       if (sawc)
558         *sawc = 0;
559       if (lenp)
560         *lenp = 0;
561       return ((char *)NULL);
562     }
563
564   ret = xmalloc (len + 1);
565   for (r = ret, s = string; s && *s; )
566     {
567       c = *s++;
568       if (c != '\\' || *s == '\0')
569         {
570           *r++ = c;
571           continue;
572         }
573       temp = 0;
574       s += tescape (s, 0, &c, &temp);
575       if (temp)
576         {
577           if (sawc)
578             *sawc = 1;
579           break;
580         }
581
582       *r++ = c;
583     }
584
585   *r = '\0';
586   if (lenp)
587     *lenp = r - ret;
588   return ret;
589 }
590
591 static char *
592 mklong (str, ch)
593      char *str;
594      int ch;
595 {
596   static char copy[64];
597   int len;
598
599   len = strlen (str) + 2;
600   FASTCOPY (str, copy, len - 3);
601   copy[len - 3] = 'l';
602   copy[len - 2] = ch;
603   copy[len - 1] = '\0';
604   return (copy);
605 }
606
607 static int
608 getchr ()
609 {
610   int ret;
611
612   if (garglist == 0)
613     return ('\0');
614
615   ret = (int)garglist->word->word[0];
616   garglist = garglist->next;
617   return ret;
618 }
619
620 static char *
621 getstr ()
622 {
623   char *ret;
624
625   if (garglist == 0)
626     return ("");
627
628   ret = garglist->word->word;
629   garglist = garglist->next;
630   return ret;
631 }
632
633 static int
634 getint ()
635 {
636   long ret;
637
638   if (getlong (&ret))
639     return (0);
640
641   if (ret > INT_MAX)
642     {
643       builtin_error ("warning: %s: %s", garglist->word->word, strerror(ERANGE));
644       ret = INT_MAX;
645     }
646   else if (ret < INT_MIN)
647     {
648       builtin_error ("warning: %s: %s", garglist->word->word, strerror(ERANGE));
649       ret = INT_MIN;
650     }
651
652   return ((int)ret);
653 }
654
655 static int
656 getlong (lp)
657      long *lp;
658 {
659   long ret;
660   char *ep;
661
662   if (garglist == 0)
663     {
664       *lp = 0L;
665       return (0);
666     }
667
668   if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"')
669     {
670       *lp =  (long)asciicode ();
671       return (0);
672     }
673
674   errno = 0;
675   /* If we use 0 as the third argument, we can handle octal and hex, which
676      legal_number does not.  (This was
677           if (legal_number (garglist->word->word, &ret) == 0)
678      ) */
679   ret = strtol (garglist->word->word, &ep, 0);
680   if (*ep != '\0')
681     {
682       builtin_error ("%s: invalid number", garglist->word->word);
683       return (1);
684     }
685   else if (errno == ERANGE)
686     builtin_error ("warning: %s: %s", garglist->word->word, strerror(ERANGE));
687
688   *lp = ret;
689   garglist = garglist->next;
690   return (0);
691 }
692
693 static int
694 getulong (ulp)
695      unsigned long *ulp;
696 {
697   unsigned long ret;
698   char *ep;
699
700   if (garglist == 0)
701     {
702       *ulp = (unsigned long)0;
703       return (0);
704     }
705
706   if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"')
707     {
708       *ulp =  (unsigned long)asciicode ();
709       return (0);
710     }
711
712   errno = 0;
713   ret = strtoul (garglist->word->word, &ep, 0);
714   
715   if (*ep)
716     {
717       builtin_error ("%s: invalid number", garglist->word->word);
718       return (1);
719     }
720   else if (errno == ERANGE)
721     builtin_error ("warning: %s: %s", garglist->word->word, strerror(ERANGE));
722
723   *ulp = ret;
724   garglist = garglist->next;
725   return (0);
726 }
727
728 static int
729 getdouble (dp)
730      double *dp;
731 {
732   double ret;
733   char *ep;
734
735   if (garglist == 0)
736     {
737       *dp = (double)0;
738       return (0);
739     }
740
741   if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"')
742     {
743       *dp = (double)asciicode ();
744       return (0);
745     }
746
747   errno = 0;
748   ret = strtod (garglist->word->word, &ep);
749   if (*ep)
750     {
751       builtin_error ("%s: invalid number", garglist->word->word);
752       return (1);
753     }
754   else if (errno == ERANGE)
755     builtin_error ("warning: %s: %s", garglist->word->word, strerror(ERANGE));
756
757   *dp = ret;
758   garglist = garglist->next;
759   return (0);
760 }
761
762 /* NO check is needed for garglist here. */
763 static int
764 asciicode ()
765 {
766   register int ch;
767
768   ch = garglist->word->word[1];
769   garglist = garglist->next;
770   return (ch);
771 }