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