Imported from ../bash-2.04.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 double getdouble __P((void));
92 static int asciicode __P((void));
93
94 static WORD_LIST *garglist;
95 static int retval;
96
97 extern char *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 = 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                 p = getdouble ();
311                 PF(start, p);
312                 break;
313               }
314
315             /* We don't output unrecognized format characters; we print an
316                error message and return a failure exit status. */
317             default:
318               builtin_error ("`%c': invalid format character", convch);
319               PRETURN (EXECUTION_FAILURE);
320             }
321
322           fmt[1] = nextch;
323         }
324     }
325   while (garglist && garglist != list->next);
326
327   PRETURN (retval);
328 }
329
330 /* We duplicate a lot of what printf(3) does here. */
331 static void
332 printstr (fmt, string, len, fieldwidth, precision)
333      char *fmt;                 /* format */
334      char *string;              /* expanded string argument */
335      int len;                   /* length of expanded string */
336      int fieldwidth;            /* argument for width of `*' */
337      int precision;             /* argument for precision of `*' */
338 {
339 #if 0
340   char *s;
341 #endif
342   int padlen, nc, ljust, i;
343   int fw, pr;                   /* fieldwidth and precision */
344
345   if (string == 0 || *string == '\0')
346     return;
347
348 #if 0
349   s = fmt;
350 #endif
351   if (*fmt == '%')
352     fmt++;
353
354   ljust = fw = pr = 0;
355
356   /* skip flags */
357   while (*fmt == '#' || *fmt == '-' || *fmt == '+' || *fmt == ' ' || *fmt == '0')
358     {
359       if (*fmt == '-')
360         ljust = 1;
361       fmt++;
362     }
363
364   /* get fieldwidth, if present */
365   if (*fmt == '*')
366     {
367       fmt++;
368       fw = fieldwidth;
369     }
370   else if (isdigit (*fmt))
371     {
372       fw = *fmt++ - '0';
373       while (isdigit (*fmt))
374         fw = (fw * 10) + (*fmt++ - '0');
375     }
376
377   /* get precision, if present */
378   if (*fmt == '.')
379     {
380       fmt++;
381       if (*fmt == '*')
382         {
383           fmt++;
384           pr = precision;
385         }
386       else if (isdigit (*fmt))
387         {
388           pr = *fmt++ - '0';
389           while (isdigit (*fmt))
390             pr = (pr * 10) + (*fmt++ - '0');
391         }
392     }
393
394 #if 0
395   /* If we remove this, get rid of `s'. */
396   if (*fmt != 'b' && *fmt != 'q')
397     {
398       internal_error ("format parsing problem: %s", s);
399       fw = pr = 0;
400     }
401 #endif
402
403   /* chars from string to print */
404   nc = (pr > 0 && pr <= len) ? pr : len;
405
406   padlen = fw - nc;
407   if (padlen < 0)
408     padlen = 0;
409   if (ljust)
410     padlen = -padlen;
411
412   /* leading pad characters */
413   for (; padlen > 0; padlen--)
414     putchar (' ');
415
416   /* output NC characters from STRING */
417   for (i = 0; i < nc; i++)
418     putchar (string[i]);
419
420   /* output any necessary trailing padding */
421   for (; padlen < 0; padlen++)
422     putchar (' ');
423 }
424   
425 /* Convert STRING by expanding the escape sequences specified by the
426    POSIX standard for printf's `%b' format string.  If SAWC is non-null,
427    recognize `\c' and use that as a string terminator.  If we see \c, set
428    *SAWC to 1 before returning.  LEN is the length of STRING. */
429
430 #ifdef isoctal
431 #undef isoctal
432 #endif
433
434 #define isoctal(c)      ((c) >= '0' && (c) <= '7')
435
436 #define OCTVALUE(c)     ((c) - '0')
437
438 #ifndef isxdigit
439 #  define isxdigit(c)   (isdigit((c)) || ((c) >= 'a' && (c) <= 'f') || ((c) >= 'A' && (c) <= 'F'))
440 #endif
441
442 #define HEXVALUE(c) \
443   ((c) >= 'a' && (c) <= 'f' ? (c)-'a'+10 : (c) >= 'A' && (c) <= 'F' ? (c)-'A'+10 : (c)-'0')
444
445 /* Translate a single backslash-escape sequence starting at ESTART (the
446    character after the backslash) and return the number of characters
447    consumed by the sequence.  CP is the place to return the translated
448    value.  *SAWC is set to 1 if the escape sequence was \c, since that means
449    to short-circuit the rest of the processing.  If SAWC is null, we don't
450    do the \c short-circuiting, and \c is treated as an unrecognized escape
451    sequence.  */
452 static int
453 tescape (estart, trans_squote, cp, sawc)
454      char *estart;
455      int trans_squote;
456      char *cp;
457      int *sawc;
458 {
459   register char *p;
460   int temp, c, evalue;
461
462   p = estart;
463
464   switch (c = *p++)
465     {
466 #if defined (__STDC__)
467       case 'a': *cp = '\a'; break;
468 #else
469       case 'a': *cp = '\007'; break;
470 #endif
471
472       case 'b': *cp = '\b'; break;
473
474       case 'e': *cp = '\033'; break;    /* ESC -- non-ANSI */
475
476       case 'f': *cp = '\f'; break;
477
478       case 'n': *cp = '\n'; break;
479
480       case 'r': *cp = '\r'; break;
481
482       case 't': *cp = '\t'; break;
483
484       case 'v': *cp = '\v'; break;
485
486       /* %b octal constants are `\0' followed by one, two, or three
487          octal digits... */
488       case '0':
489         for (temp = 3, evalue = 0; isoctal (*p) && temp--; p++)
490           evalue = (evalue * 8) + OCTVALUE (*p);
491         *cp = evalue;
492         break;
493
494       /* but, as an extension, the other echo-like octal escape
495          sequences are supported as well. */
496       case '1': case '2': case '3': case '4':
497       case '5': case '6': case '7':
498         for (temp = 2, evalue = c - '0'; isoctal (*p) && temp--; p++)
499           evalue = (evalue * 8) + OCTVALUE (*p);
500         *cp = evalue;
501         break;
502
503       /* And, as another extension, we allow \xNNN, where each N is a
504          hex digit. */
505       case 'x':
506         for (temp = 3, evalue = 0; isxdigit (*p) && temp--; p++)
507           evalue = (evalue * 16) + HEXVALUE (*p);
508         if (temp == 3)
509           {
510             builtin_error ("missing hex digit for \\x");
511             *cp = '\\';
512             return 0;
513           }
514         *cp = evalue;
515         break;
516
517       case '\\':        /* \\ -> \ */
518         *cp = c;
519         break;
520
521       case '\'':        /* TRANS_SQUOTE != 0 means \' -> ' */
522         if (trans_squote)
523           *cp = c;
524         else
525           {
526             *cp = '\\';
527             return 0;
528           }
529         break;
530
531       case 'c':
532         if (sawc)
533           {
534             *sawc = 1;
535             break;
536           }
537       /* other backslash escapes are passed through unaltered */
538       default:
539         *cp = '\\';
540         return 0;
541       }
542   return (p - estart);
543 }
544
545 static char *
546 bexpand (string, len, sawc, lenp)
547      char *string;
548      int len, *sawc, *lenp;
549 {
550   int temp;
551   char *ret, *r, *s, c;
552
553   if (string == 0 || *string == '\0')
554     {
555       if (sawc)
556         *sawc = 0;
557       if (lenp)
558         *lenp = 0;
559       return ((char *)NULL);
560     }
561
562   ret = xmalloc (len + 1);
563   for (r = ret, s = string; s && *s; )
564     {
565       c = *s++;
566       if (c != '\\' || *s == '\0')
567         {
568           *r++ = c;
569           continue;
570         }
571       temp = 0;
572       s += tescape (s, 0, &c, &temp);
573       if (temp)
574         {
575           if (sawc)
576             *sawc = 1;
577           break;
578         }
579
580       *r++ = c;
581     }
582
583   *r = '\0';
584   if (lenp)
585     *lenp = r - ret;
586   return ret;
587 }
588
589 static char *
590 mklong (str, ch)
591      char *str;
592      int ch;
593 {
594   static char copy[64];
595   int len;
596
597   len = strlen (str) + 2;
598   FASTCOPY (str, copy, len - 3);
599   copy[len - 3] = 'l';
600   copy[len - 2] = ch;
601   copy[len - 1] = '\0';
602   return (copy);
603 }
604
605 static int
606 getchr ()
607 {
608   int ret;
609
610   if (garglist == 0)
611     return ('\0');
612
613   ret = (int)garglist->word->word[0];
614   garglist = garglist->next;
615   return ret;
616 }
617
618 static char *
619 getstr ()
620 {
621   char *ret;
622
623   if (garglist == 0)
624     return ("");
625
626   ret = garglist->word->word;
627   garglist = garglist->next;
628   return ret;
629 }
630
631 static int
632 getint ()
633 {
634   long ret;
635
636   if (getlong (&ret))
637     return (0);
638
639   if (ret > INT_MAX)
640     {
641       builtin_error ("%s: %s", garglist->word->word, strerror(ERANGE));
642       return (0);
643     }
644
645   return ((int)ret);
646 }
647
648 static int
649 getlong (lp)
650      long *lp;
651 {
652   long ret;
653   char *ep;
654
655   if (garglist == 0)
656     {
657       *lp = 0L;
658       return (0);
659     }
660
661   if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"')
662     {
663       *lp =  (long)asciicode ();
664       return (0);
665     }
666
667   errno = 0;
668   /* If we use 0 as the third argument, we can handle octal and hex, which
669      legal_number does not.  (This was
670           if (legal_number (garglist->word->word, &ret) == 0)
671      ) */
672   ret = strtol (garglist->word->word, &ep, 0);
673   if (*ep != '\0')
674     {
675       builtin_error ("%s: invalid number", garglist->word->word);
676       return (1);
677     }
678   else if (errno == ERANGE)
679     {
680       builtin_error ("%s: %s", garglist->word->word, strerror(ERANGE));
681       return (1);
682     }
683
684   *lp = ret;
685   garglist = garglist->next;
686   return (0);
687 }
688
689 static int
690 getulong (ulp)
691      unsigned long *ulp;
692 {
693   unsigned long ret;
694   char *ep;
695
696   if (garglist == 0)
697     {
698       *ulp = (unsigned long)0;
699       return (0);
700     }
701
702   if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"')
703     {
704       *ulp =  (unsigned long)asciicode ();
705       return (0);
706     }
707
708   errno = 0;
709   ret = strtoul (garglist->word->word, &ep, 0);
710   
711   if (*ep)
712     {
713       builtin_error ("%s: invalid number", garglist->word->word);
714       return (1);
715     }
716   else if (errno == ERANGE)
717     {
718       builtin_error ("%s: %s", garglist->word->word, strerror(ERANGE));
719       return (1);
720     }
721
722   *ulp = ret;
723   garglist = garglist->next;
724   return (0);
725 }
726
727 static double
728 getdouble ()
729 {
730   double ret;
731
732   if (garglist == 0)
733     return ((double)0);
734
735   if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"')
736     return ((double)asciicode ());
737
738   /* This should use strtod if it is available. */
739   ret = atof (garglist->word->word);
740   garglist = garglist->next;
741   return (ret);
742 }
743
744 /* NO check is needed for garglist here. */
745 static int
746 asciicode ()
747 {
748   register int ch;
749
750   ch = garglist->word->word[1];
751   garglist = garglist->next;
752   return (ch);
753 }