]> git.ipfire.org Git - thirdparty/bash.git/blob - builtins/printf.def
Imported from ../bash-2.04.tar.gz.
[thirdparty/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 }