]> git.ipfire.org Git - thirdparty/bash.git/blame - builtins/printf.def
Imported from ../bash-2.05.tar.gz.
[thirdparty/bash.git] / builtins / printf.def
CommitLineData
cce855bc
JA
1This file is printf.def, from which is created printf.c.
2It implements the builtin "printf" in Bash.
3
4Copyright (C) 1997 Free Software Foundation, Inc.
5
6This file is part of GNU Bash, the Bourne Again SHell.
7
8Bash is free software; you can redistribute it and/or modify it under
9the terms of the GNU General Public License as published by the Free
bb70624e 10Software Foundation; either version 2, or (at your option) any later
cce855bc
JA
11version.
12
13Bash is distributed in the hope that it will be useful, but WITHOUT ANY
14WARRANTY; without even the implied warranty of MERCHANTABILITY or
15FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16for more details.
17
18You should have received a copy of the GNU General Public License along
19with Bash; see the file COPYING. If not, write to the Free Software
20Foundation, 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]
27printf formats and prints ARGUMENTS under control of the FORMAT. FORMAT
28is a character string which contains three types of objects: plain
29characters, which are simply copied to standard output, character escape
30sequences which are converted and copied to the standard output, and
31format specifications, each of which causes printing of the next successive
32argument. In addition to the standard printf(1) formats, %b means to
33expand backslash escape sequences in the corresponding argument, and %q
34means 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"
bb70624e 57#include "stdc.h"
cce855bc
JA
58#include "bashgetopt.h"
59
60#if !defined (errno)
61extern 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) \
bb70624e 77 do { /* free (format); */ fflush (stdout); return (value); } while (0)
cce855bc
JA
78
79#define SKIP1 "#-+ 0"
80#define SKIP2 "*0123456789"
81
82static void printstr __P((char *, char *, int, int, int));
bb70624e 83static int tescape __P((char *, int, char *, int *));
cce855bc
JA
84static char *bexpand __P((char *, int, int *, int *));
85static char *mklong __P((char *, int));
86static int getchr __P((void));
87static char *getstr __P((void));
88static int getint __P((void));
89static int getlong __P((long *));
90static int getulong __P((unsigned long *));
28ef6c31 91static int getdouble __P((double *));
cce855bc
JA
92static int asciicode __P((void));
93
94static WORD_LIST *garglist;
95static int retval;
96
28ef6c31 97extern char *sh_backslash_quote ();
cce855bc
JA
98
99int
100printf_builtin (list)
101 WORD_LIST *list;
102{
b72432fd 103 int ch, end, fieldwidth, precision, foundmod, fmtlen;
cce855bc
JA
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
bb70624e 129 format = list->word->word;
cce855bc
JA
130
131 garglist = list->next;
132
bc4cd23c 133 /* If the format string is empty after preprocessing, return immediately. */
bb70624e 134 if (format == 0 || *format == 0)
bc4cd23c
JA
135 return (EXECUTION_SUCCESS);
136
cce855bc
JA
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 */
bb70624e 147 for (fmt = format; *fmt; fmt++)
cce855bc
JA
148 {
149 precision = fieldwidth = foundmod = 0;
150
bb70624e
JA
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
cce855bc
JA
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 ;
cce855bc
JA
194
195 /* skip possible format modifiers */
196 if (*fmt == 'l' || *fmt == 'L' || *fmt == 'h')
197 {
198 fmt++;
199 foundmod = 1;
200 }
201
b72432fd
JA
202 if (*fmt == 0)
203 {
204 builtin_error ("`%s': missing format character", start);
205 PRETURN (EXECUTION_FAILURE);
206 }
207
cce855bc
JA
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 ();
28ef6c31 258 xp = sh_backslash_quote (p);
cce855bc
JA
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
28ef6c31
JA
310 if (getdouble (&p))
311 PRETURN (EXECUTION_FAILURE);
cce855bc
JA
312 PF(start, p);
313 break;
314 }
315
bb70624e
JA
316 /* We don't output unrecognized format characters; we print an
317 error message and return a failure exit status. */
cce855bc 318 default:
bb70624e 319 builtin_error ("`%c': invalid format character", convch);
cce855bc
JA
320 PRETURN (EXECUTION_FAILURE);
321 }
322
323 fmt[1] = nextch;
324 }
325 }
bc4cd23c 326 while (garglist && garglist != list->next);
cce855bc
JA
327
328 PRETURN (retval);
329}
330
331/* We duplicate a lot of what printf(3) does here. */
332static void
333printstr (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')
bb70624e
JA
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. */
453static int
454tescape (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
28ef6c31
JA
475 case 'e':
476 case 'E': *cp = '\033'; break; /* ESC -- non-ANSI */
bb70624e
JA
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
28ef6c31 489 octal digits... */
bb70624e
JA
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
cce855bc
JA
547static char *
548bexpand (string, len, sawc, lenp)
549 char *string;
550 int len, *sawc, *lenp;
551{
bb70624e
JA
552 int temp;
553 char *ret, *r, *s, c;
cce855bc
JA
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 }
bb70624e
JA
573 temp = 0;
574 s += tescape (s, 0, &c, &temp);
575 if (temp)
cce855bc 576 {
cce855bc
JA
577 if (sawc)
578 *sawc = 1;
bb70624e 579 break;
cce855bc
JA
580 }
581
582 *r++ = c;
583 }
584
585 *r = '\0';
586 if (lenp)
587 *lenp = r - ret;
588 return ret;
589}
590
591static char *
592mklong (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
607static int
608getchr ()
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
620static char *
621getstr ()
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
633static int
634getint ()
635{
636 long ret;
637
638 if (getlong (&ret))
639 return (0);
640
641 if (ret > INT_MAX)
642 {
28ef6c31
JA
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;
cce855bc
JA
650 }
651
652 return ((int)ret);
653}
654
655static int
656getlong (lp)
657 long *lp;
658{
659 long ret;
bb70624e 660 char *ep;
cce855bc
JA
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;
bb70624e
JA
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')
cce855bc 681 {
bb70624e 682 builtin_error ("%s: invalid number", garglist->word->word);
cce855bc
JA
683 return (1);
684 }
685 else if (errno == ERANGE)
28ef6c31 686 builtin_error ("warning: %s: %s", garglist->word->word, strerror(ERANGE));
cce855bc
JA
687
688 *lp = ret;
689 garglist = garglist->next;
690 return (0);
691}
692
693static int
694getulong (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 {
bb70624e 717 builtin_error ("%s: invalid number", garglist->word->word);
cce855bc
JA
718 return (1);
719 }
720 else if (errno == ERANGE)
28ef6c31 721 builtin_error ("warning: %s: %s", garglist->word->word, strerror(ERANGE));
cce855bc
JA
722
723 *ulp = ret;
724 garglist = garglist->next;
725 return (0);
726}
727
28ef6c31
JA
728static int
729getdouble (dp)
730 double *dp;
cce855bc
JA
731{
732 double ret;
28ef6c31 733 char *ep;
cce855bc
JA
734
735 if (garglist == 0)
28ef6c31
JA
736 {
737 *dp = (double)0;
738 return (0);
739 }
cce855bc
JA
740
741 if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"')
28ef6c31
JA
742 {
743 *dp = (double)asciicode ();
744 return (0);
745 }
cce855bc 746
28ef6c31
JA
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;
cce855bc 758 garglist = garglist->next;
28ef6c31 759 return (0);
cce855bc
JA
760}
761
762/* NO check is needed for garglist here. */
763static int
764asciicode ()
765{
766 register int ch;
767
768 ch = garglist->word->word[1];
769 garglist = garglist->next;
770 return (ch);
771}