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-2005 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 [-v var] 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 | If the -v option is supplied, the output is placed into the value of the
|
---|
36 | shell variable VAR rather than being sent to the standard output.
|
---|
37 | $END
|
---|
38 |
|
---|
39 | #include <config.h>
|
---|
40 |
|
---|
41 | #include "../bashtypes.h"
|
---|
42 |
|
---|
43 | #include <errno.h>
|
---|
44 | #if defined (HAVE_LIMITS_H)
|
---|
45 | # include <limits.h>
|
---|
46 | #else
|
---|
47 | /* Assume 32-bit ints. */
|
---|
48 | # define INT_MAX 2147483647
|
---|
49 | # define INT_MIN (-2147483647-1)
|
---|
50 | #endif
|
---|
51 |
|
---|
52 | #include <stdio.h>
|
---|
53 | #include <chartypes.h>
|
---|
54 |
|
---|
55 | #ifdef HAVE_INTTYPES_H
|
---|
56 | # include <inttypes.h>
|
---|
57 | #endif
|
---|
58 |
|
---|
59 | #include "../bashansi.h"
|
---|
60 | #include "../bashintl.h"
|
---|
61 |
|
---|
62 | #include "../shell.h"
|
---|
63 | #include "stdc.h"
|
---|
64 | #include "bashgetopt.h"
|
---|
65 | #include "common.h"
|
---|
66 |
|
---|
67 | #if !defined (PRIdMAX)
|
---|
68 | # if HAVE_LONG_LONG
|
---|
69 | # define PRIdMAX "lld"
|
---|
70 | # else
|
---|
71 | # define PRIdMAX "ld"
|
---|
72 | # endif
|
---|
73 | #endif
|
---|
74 |
|
---|
75 | #if !defined (errno)
|
---|
76 | extern int errno;
|
---|
77 | #endif
|
---|
78 |
|
---|
79 | #define PC(c) \
|
---|
80 | do { \
|
---|
81 | char b[2]; \
|
---|
82 | tw++; \
|
---|
83 | b[0] = c; b[1] = '\0'; \
|
---|
84 | if (vflag) \
|
---|
85 | vbadd (b, 1); \
|
---|
86 | else \
|
---|
87 | putchar (c); \
|
---|
88 | } while (0)
|
---|
89 |
|
---|
90 | #define PF(f, func) \
|
---|
91 | do { \
|
---|
92 | char *b = 0; \
|
---|
93 | int nw; \
|
---|
94 | if (have_fieldwidth && have_precision) \
|
---|
95 | nw = asprintf(&b, f, fieldwidth, precision, func); \
|
---|
96 | else if (have_fieldwidth) \
|
---|
97 | nw = asprintf(&b, f, fieldwidth, func); \
|
---|
98 | else if (have_precision) \
|
---|
99 | nw = asprintf(&b, f, precision, func); \
|
---|
100 | else \
|
---|
101 | nw = asprintf(&b, f, func); \
|
---|
102 | tw += nw; \
|
---|
103 | if (b) \
|
---|
104 | { \
|
---|
105 | if (vflag) \
|
---|
106 | (void)vbadd (b, nw); \
|
---|
107 | else \
|
---|
108 | (void)fputs (b, stdout); \
|
---|
109 | free (b); \
|
---|
110 | } \
|
---|
111 | } while (0)
|
---|
112 |
|
---|
113 | /* We free the buffer used by mklong() if it's `too big'. */
|
---|
114 | #define PRETURN(value) \
|
---|
115 | do \
|
---|
116 | { \
|
---|
117 | if (vflag) \
|
---|
118 | { \
|
---|
119 | bind_variable (vname, vbuf, 0); \
|
---|
120 | stupidly_hack_special_variables (vname); \
|
---|
121 | } \
|
---|
122 | if (conv_bufsize > 4096 ) \
|
---|
123 | { \
|
---|
124 | free (conv_buf); \
|
---|
125 | conv_bufsize = 0; \
|
---|
126 | conv_buf = 0; \
|
---|
127 | } \
|
---|
128 | if (vbsize > 4096) \
|
---|
129 | { \
|
---|
130 | free (vbuf); \
|
---|
131 | vbsize = 0; \
|
---|
132 | vbuf = 0; \
|
---|
133 | } \
|
---|
134 | fflush (stdout); \
|
---|
135 | return (value); \
|
---|
136 | } \
|
---|
137 | while (0)
|
---|
138 |
|
---|
139 | #define SKIP1 "#'-+ 0"
|
---|
140 | #define LENMODS "hjlLtz"
|
---|
141 |
|
---|
142 | static void printf_erange __P((char *));
|
---|
143 | static int printstr __P((char *, char *, int, int, int));
|
---|
144 | static int tescape __P((char *, char *, int *));
|
---|
145 | static char *bexpand __P((char *, int, int *, int *));
|
---|
146 | static char *vbadd __P((char *, int));
|
---|
147 | static char *mklong __P((char *, char *, size_t));
|
---|
148 | static int getchr __P((void));
|
---|
149 | static char *getstr __P((void));
|
---|
150 | static int getint __P((void));
|
---|
151 | static intmax_t getintmax __P((void));
|
---|
152 | static uintmax_t getuintmax __P((void));
|
---|
153 |
|
---|
154 | #if defined (HAVE_LONG_DOUBLE) && HAVE_DECL_STRTOLD && !defined(STRTOLD_BROKEN)
|
---|
155 | typedef long double floatmax_t;
|
---|
156 | # define FLOATMAX_CONV "L"
|
---|
157 | # define strtofltmax strtold
|
---|
158 | #else
|
---|
159 | typedef double floatmax_t;
|
---|
160 | # define FLOATMAX_CONV ""
|
---|
161 | # define strtofltmax strtod
|
---|
162 | #endif
|
---|
163 | static floatmax_t getfloatmax __P((void));
|
---|
164 |
|
---|
165 | static int asciicode __P((void));
|
---|
166 |
|
---|
167 | static WORD_LIST *garglist;
|
---|
168 | static int retval;
|
---|
169 | static int conversion_error;
|
---|
170 |
|
---|
171 | /* printf -v var support */
|
---|
172 | static int vflag = 0;
|
---|
173 | static char *vbuf, *vname;
|
---|
174 | static size_t vbsize;
|
---|
175 | static int vblen;
|
---|
176 |
|
---|
177 | static intmax_t tw;
|
---|
178 |
|
---|
179 | static char *conv_buf;
|
---|
180 | static size_t conv_bufsize;
|
---|
181 |
|
---|
182 | int
|
---|
183 | printf_builtin (list)
|
---|
184 | WORD_LIST *list;
|
---|
185 | {
|
---|
186 | int ch, fieldwidth, precision;
|
---|
187 | int have_fieldwidth, have_precision;
|
---|
188 | char convch, thisch, nextch, *format, *modstart, *fmt, *start;
|
---|
189 |
|
---|
190 | conversion_error = 0;
|
---|
191 | retval = EXECUTION_SUCCESS;
|
---|
192 |
|
---|
193 | vflag = 0;
|
---|
194 |
|
---|
195 | reset_internal_getopt ();
|
---|
196 | while ((ch = internal_getopt (list, "v:")) != -1)
|
---|
197 | {
|
---|
198 | switch (ch)
|
---|
199 | {
|
---|
200 | case 'v':
|
---|
201 | if (legal_identifier (vname = list_optarg))
|
---|
202 | {
|
---|
203 | vflag = 1;
|
---|
204 | vblen = 0;
|
---|
205 | }
|
---|
206 | else
|
---|
207 | {
|
---|
208 | sh_invalidid (vname);
|
---|
209 | return (EX_USAGE);
|
---|
210 | }
|
---|
211 | break;
|
---|
212 | default:
|
---|
213 | builtin_usage ();
|
---|
214 | return (EX_USAGE);
|
---|
215 | }
|
---|
216 | }
|
---|
217 | list = loptend; /* skip over possible `--' */
|
---|
218 |
|
---|
219 | if (list == 0)
|
---|
220 | {
|
---|
221 | builtin_usage ();
|
---|
222 | return (EX_USAGE);
|
---|
223 | }
|
---|
224 |
|
---|
225 | if (list->word->word == 0 || list->word->word[0] == '\0')
|
---|
226 | return (EXECUTION_SUCCESS);
|
---|
227 |
|
---|
228 | format = list->word->word;
|
---|
229 | tw = 0;
|
---|
230 |
|
---|
231 | garglist = list->next;
|
---|
232 |
|
---|
233 | /* If the format string is empty after preprocessing, return immediately. */
|
---|
234 | if (format == 0 || *format == 0)
|
---|
235 | return (EXECUTION_SUCCESS);
|
---|
236 |
|
---|
237 | /* Basic algorithm is to scan the format string for conversion
|
---|
238 | specifications -- once one is found, find out if the field
|
---|
239 | width or precision is a '*'; if it is, gather up value. Note,
|
---|
240 | format strings are reused as necessary to use up the provided
|
---|
241 | arguments, arguments of zero/null string are provided to use
|
---|
242 | up the format string. */
|
---|
243 | do
|
---|
244 | {
|
---|
245 | tw = 0;
|
---|
246 | /* find next format specification */
|
---|
247 | for (fmt = format; *fmt; fmt++)
|
---|
248 | {
|
---|
249 | precision = fieldwidth = 0;
|
---|
250 | have_fieldwidth = have_precision = 0;
|
---|
251 |
|
---|
252 | if (*fmt == '\\')
|
---|
253 | {
|
---|
254 | fmt++;
|
---|
255 | /* A NULL third argument to tescape means to bypass the
|
---|
256 | special processing for arguments to %b. */
|
---|
257 | fmt += tescape (fmt, &nextch, (int *)NULL);
|
---|
258 | PC (nextch);
|
---|
259 | fmt--; /* for loop will increment it for us again */
|
---|
260 | continue;
|
---|
261 | }
|
---|
262 |
|
---|
263 | if (*fmt != '%')
|
---|
264 | {
|
---|
265 | PC (*fmt);
|
---|
266 | continue;
|
---|
267 | }
|
---|
268 |
|
---|
269 | /* ASSERT(*fmt == '%') */
|
---|
270 | start = fmt++;
|
---|
271 |
|
---|
272 | if (*fmt == '%') /* %% prints a % */
|
---|
273 | {
|
---|
274 | PC ('%');
|
---|
275 | continue;
|
---|
276 | }
|
---|
277 |
|
---|
278 | /* found format specification, skip to field width */
|
---|
279 | for (; *fmt && strchr(SKIP1, *fmt); ++fmt)
|
---|
280 | ;
|
---|
281 |
|
---|
282 | /* Skip optional field width. */
|
---|
283 | if (*fmt == '*')
|
---|
284 | {
|
---|
285 | fmt++;
|
---|
286 | have_fieldwidth = 1;
|
---|
287 | fieldwidth = getint ();
|
---|
288 | }
|
---|
289 | else
|
---|
290 | while (DIGIT (*fmt))
|
---|
291 | fmt++;
|
---|
292 |
|
---|
293 | /* Skip optional '.' and precision */
|
---|
294 | if (*fmt == '.')
|
---|
295 | {
|
---|
296 | ++fmt;
|
---|
297 | if (*fmt == '*')
|
---|
298 | {
|
---|
299 | fmt++;
|
---|
300 | have_precision = 1;
|
---|
301 | precision = getint ();
|
---|
302 | }
|
---|
303 | else
|
---|
304 | {
|
---|
305 | /* Negative precisions are allowed but treated as if the
|
---|
306 | precision were missing; I would like to allow a leading
|
---|
307 | `+' in the precision number as an extension, but lots
|
---|
308 | of asprintf/fprintf implementations get this wrong. */
|
---|
309 | #if 0
|
---|
310 | if (*fmt == '-' || *fmt == '+')
|
---|
311 | #else
|
---|
312 | if (*fmt == '-')
|
---|
313 | #endif
|
---|
314 | fmt++;
|
---|
315 | while (DIGIT (*fmt))
|
---|
316 | fmt++;
|
---|
317 | }
|
---|
318 | }
|
---|
319 |
|
---|
320 | /* skip possible format modifiers */
|
---|
321 | modstart = fmt;
|
---|
322 | while (*fmt && strchr (LENMODS, *fmt))
|
---|
323 | fmt++;
|
---|
324 |
|
---|
325 | if (*fmt == 0)
|
---|
326 | {
|
---|
327 | builtin_error (_("`%s': missing format character"), start);
|
---|
328 | PRETURN (EXECUTION_FAILURE);
|
---|
329 | }
|
---|
330 |
|
---|
331 | convch = *fmt;
|
---|
332 | thisch = modstart[0];
|
---|
333 | nextch = modstart[1];
|
---|
334 | modstart[0] = convch;
|
---|
335 | modstart[1] = '\0';
|
---|
336 |
|
---|
337 | switch(convch)
|
---|
338 | {
|
---|
339 | case 'c':
|
---|
340 | {
|
---|
341 | char p;
|
---|
342 |
|
---|
343 | p = getchr ();
|
---|
344 | PF(start, p);
|
---|
345 | break;
|
---|
346 | }
|
---|
347 |
|
---|
348 | case 's':
|
---|
349 | {
|
---|
350 | char *p;
|
---|
351 |
|
---|
352 | p = getstr ();
|
---|
353 | PF(start, p);
|
---|
354 | break;
|
---|
355 | }
|
---|
356 |
|
---|
357 | case 'n':
|
---|
358 | {
|
---|
359 | char *var;
|
---|
360 |
|
---|
361 | var = getstr ();
|
---|
362 | if (var && *var)
|
---|
363 | {
|
---|
364 | if (legal_identifier (var))
|
---|
365 | bind_var_to_int (var, tw);
|
---|
366 | else
|
---|
367 | {
|
---|
368 | sh_invalidid (var);
|
---|
369 | PRETURN (EXECUTION_FAILURE);
|
---|
370 | }
|
---|
371 | }
|
---|
372 | break;
|
---|
373 | }
|
---|
374 |
|
---|
375 | case 'b': /* expand escapes in argument */
|
---|
376 | {
|
---|
377 | char *p, *xp;
|
---|
378 | int rlen, r;
|
---|
379 |
|
---|
380 | p = getstr ();
|
---|
381 | ch = rlen = r = 0;
|
---|
382 | xp = bexpand (p, strlen (p), &ch, &rlen);
|
---|
383 |
|
---|
384 | if (xp)
|
---|
385 | {
|
---|
386 | /* Have to use printstr because of possible NUL bytes
|
---|
387 | in XP -- printf does not handle that well. */
|
---|
388 | r = printstr (start, xp, rlen, fieldwidth, precision);
|
---|
389 | if (r < 0)
|
---|
390 | {
|
---|
391 | sh_wrerror ();
|
---|
392 | clearerr (stdout);
|
---|
393 | retval = EXECUTION_FAILURE;
|
---|
394 | }
|
---|
395 | free (xp);
|
---|
396 | }
|
---|
397 |
|
---|
398 | if (ch || r < 0)
|
---|
399 | PRETURN (retval);
|
---|
400 | break;
|
---|
401 | }
|
---|
402 |
|
---|
403 | case 'q': /* print with shell quoting */
|
---|
404 | {
|
---|
405 | char *p, *xp;
|
---|
406 | int r;
|
---|
407 |
|
---|
408 | r = 0;
|
---|
409 | p = getstr ();
|
---|
410 | if (ansic_shouldquote (p))
|
---|
411 | xp = ansic_quote (p, 0, (int *)0);
|
---|
412 | else
|
---|
413 | xp = sh_backslash_quote (p);
|
---|
414 | if (xp)
|
---|
415 | {
|
---|
416 | /* Use printstr to get fieldwidth and precision right. */
|
---|
417 | r = printstr (start, xp, strlen (xp), fieldwidth, precision);
|
---|
418 | if (r < 0)
|
---|
419 | {
|
---|
420 | sh_wrerror ();
|
---|
421 | clearerr (stdout);
|
---|
422 | }
|
---|
423 | free (xp);
|
---|
424 | }
|
---|
425 |
|
---|
426 | if (r < 0)
|
---|
427 | PRETURN (EXECUTION_FAILURE);
|
---|
428 | break;
|
---|
429 | }
|
---|
430 |
|
---|
431 | case 'd':
|
---|
432 | case 'i':
|
---|
433 | {
|
---|
434 | char *f;
|
---|
435 | long p;
|
---|
436 | intmax_t pp;
|
---|
437 |
|
---|
438 | p = pp = getintmax ();
|
---|
439 | if (p != pp)
|
---|
440 | {
|
---|
441 | f = mklong (start, PRIdMAX, sizeof (PRIdMAX) - 2);
|
---|
442 | PF (f, pp);
|
---|
443 | }
|
---|
444 | else
|
---|
445 | {
|
---|
446 | /* Optimize the common case where the integer fits
|
---|
447 | in "long". This also works around some long
|
---|
448 | long and/or intmax_t library bugs in the common
|
---|
449 | case, e.g. glibc 2.2 x86. */
|
---|
450 | f = mklong (start, "l", 1);
|
---|
451 | PF (f, p);
|
---|
452 | }
|
---|
453 | break;
|
---|
454 | }
|
---|
455 |
|
---|
456 | case 'o':
|
---|
457 | case 'u':
|
---|
458 | case 'x':
|
---|
459 | case 'X':
|
---|
460 | {
|
---|
461 | char *f;
|
---|
462 | unsigned long p;
|
---|
463 | uintmax_t pp;
|
---|
464 |
|
---|
465 | p = pp = getuintmax ();
|
---|
466 | if (p != pp)
|
---|
467 | {
|
---|
468 | f = mklong (start, PRIdMAX, sizeof (PRIdMAX) - 2);
|
---|
469 | PF (f, pp);
|
---|
470 | }
|
---|
471 | else
|
---|
472 | {
|
---|
473 | f = mklong (start, "l", 1);
|
---|
474 | PF (f, p);
|
---|
475 | }
|
---|
476 | break;
|
---|
477 | }
|
---|
478 |
|
---|
479 | case 'e':
|
---|
480 | case 'E':
|
---|
481 | case 'f':
|
---|
482 | case 'F':
|
---|
483 | case 'g':
|
---|
484 | case 'G':
|
---|
485 | #if defined (HAVE_PRINTF_A_FORMAT)
|
---|
486 | case 'a':
|
---|
487 | case 'A':
|
---|
488 | #endif
|
---|
489 | {
|
---|
490 | char *f;
|
---|
491 | floatmax_t p;
|
---|
492 |
|
---|
493 | p = getfloatmax ();
|
---|
494 | f = mklong (start, FLOATMAX_CONV, sizeof(FLOATMAX_CONV) - 1);
|
---|
495 | PF (f, p);
|
---|
496 | break;
|
---|
497 | }
|
---|
498 |
|
---|
499 | /* We don't output unrecognized format characters; we print an
|
---|
500 | error message and return a failure exit status. */
|
---|
501 | default:
|
---|
502 | builtin_error (_("`%c': invalid format character"), convch);
|
---|
503 | PRETURN (EXECUTION_FAILURE);
|
---|
504 | }
|
---|
505 |
|
---|
506 | modstart[0] = thisch;
|
---|
507 | modstart[1] = nextch;
|
---|
508 | }
|
---|
509 |
|
---|
510 | if (ferror (stdout))
|
---|
511 | {
|
---|
512 | sh_wrerror ();
|
---|
513 | clearerr (stdout);
|
---|
514 | PRETURN (EXECUTION_FAILURE);
|
---|
515 | }
|
---|
516 | }
|
---|
517 | while (garglist && garglist != list->next);
|
---|
518 |
|
---|
519 | if (conversion_error)
|
---|
520 | retval = EXECUTION_FAILURE;
|
---|
521 |
|
---|
522 | PRETURN (retval);
|
---|
523 | }
|
---|
524 |
|
---|
525 | static void
|
---|
526 | printf_erange (s)
|
---|
527 | char *s;
|
---|
528 | {
|
---|
529 | builtin_error ("warning: %s: %s", s, strerror(ERANGE));
|
---|
530 | }
|
---|
531 |
|
---|
532 | /* We duplicate a lot of what printf(3) does here. */
|
---|
533 | static int
|
---|
534 | printstr (fmt, string, len, fieldwidth, precision)
|
---|
535 | char *fmt; /* format */
|
---|
536 | char *string; /* expanded string argument */
|
---|
537 | int len; /* length of expanded string */
|
---|
538 | int fieldwidth; /* argument for width of `*' */
|
---|
539 | int precision; /* argument for precision of `*' */
|
---|
540 | {
|
---|
541 | #if 0
|
---|
542 | char *s;
|
---|
543 | #endif
|
---|
544 | int padlen, nc, ljust, i;
|
---|
545 | int fw, pr; /* fieldwidth and precision */
|
---|
546 |
|
---|
547 | #if 0
|
---|
548 | if (string == 0 || *string == '\0')
|
---|
549 | #else
|
---|
550 | if (string == 0 || len == 0)
|
---|
551 | #endif
|
---|
552 | return;
|
---|
553 |
|
---|
554 | #if 0
|
---|
555 | s = fmt;
|
---|
556 | #endif
|
---|
557 | if (*fmt == '%')
|
---|
558 | fmt++;
|
---|
559 |
|
---|
560 | ljust = fw = 0;
|
---|
561 | pr = -1;
|
---|
562 |
|
---|
563 | /* skip flags */
|
---|
564 | while (strchr (SKIP1, *fmt))
|
---|
565 | {
|
---|
566 | if (*fmt == '-')
|
---|
567 | ljust = 1;
|
---|
568 | fmt++;
|
---|
569 | }
|
---|
570 |
|
---|
571 | /* get fieldwidth, if present */
|
---|
572 | if (*fmt == '*')
|
---|
573 | {
|
---|
574 | fmt++;
|
---|
575 | fw = fieldwidth;
|
---|
576 | if (fw < 0)
|
---|
577 | {
|
---|
578 | fw = -fw;
|
---|
579 | ljust = 1;
|
---|
580 | }
|
---|
581 | }
|
---|
582 | else if (DIGIT (*fmt))
|
---|
583 | {
|
---|
584 | fw = *fmt++ - '0';
|
---|
585 | while (DIGIT (*fmt))
|
---|
586 | fw = (fw * 10) + (*fmt++ - '0');
|
---|
587 | }
|
---|
588 |
|
---|
589 | /* get precision, if present */
|
---|
590 | if (*fmt == '.')
|
---|
591 | {
|
---|
592 | fmt++;
|
---|
593 | if (*fmt == '*')
|
---|
594 | {
|
---|
595 | fmt++;
|
---|
596 | pr = precision;
|
---|
597 | }
|
---|
598 | else if (DIGIT (*fmt))
|
---|
599 | {
|
---|
600 | pr = *fmt++ - '0';
|
---|
601 | while (DIGIT (*fmt))
|
---|
602 | pr = (pr * 10) + (*fmt++ - '0');
|
---|
603 | }
|
---|
604 | }
|
---|
605 |
|
---|
606 | #if 0
|
---|
607 | /* If we remove this, get rid of `s'. */
|
---|
608 | if (*fmt != 'b' && *fmt != 'q')
|
---|
609 | {
|
---|
610 | internal_error ("format parsing problem: %s", s);
|
---|
611 | fw = pr = 0;
|
---|
612 | }
|
---|
613 | #endif
|
---|
614 |
|
---|
615 | /* chars from string to print */
|
---|
616 | nc = (pr >= 0 && pr <= len) ? pr : len;
|
---|
617 |
|
---|
618 | padlen = fw - nc;
|
---|
619 | if (padlen < 0)
|
---|
620 | padlen = 0;
|
---|
621 | if (ljust)
|
---|
622 | padlen = -padlen;
|
---|
623 |
|
---|
624 | /* leading pad characters */
|
---|
625 | for (; padlen > 0; padlen--)
|
---|
626 | PC (' ');
|
---|
627 |
|
---|
628 | /* output NC characters from STRING */
|
---|
629 | for (i = 0; i < nc; i++)
|
---|
630 | PC (string[i]);
|
---|
631 |
|
---|
632 | /* output any necessary trailing padding */
|
---|
633 | for (; padlen < 0; padlen++)
|
---|
634 | PC (' ');
|
---|
635 |
|
---|
636 | return (ferror (stdout) ? -1 : 0);
|
---|
637 | }
|
---|
638 |
|
---|
639 | /* Convert STRING by expanding the escape sequences specified by the
|
---|
640 | POSIX standard for printf's `%b' format string. If SAWC is non-null,
|
---|
641 | perform the processing appropriate for %b arguments. In particular,
|
---|
642 | recognize `\c' and use that as a string terminator. If we see \c, set
|
---|
643 | *SAWC to 1 before returning. LEN is the length of STRING. */
|
---|
644 |
|
---|
645 | /* Translate a single backslash-escape sequence starting at ESTART (the
|
---|
646 | character after the backslash) and return the number of characters
|
---|
647 | consumed by the sequence. CP is the place to return the translated
|
---|
648 | value. *SAWC is set to 1 if the escape sequence was \c, since that means
|
---|
649 | to short-circuit the rest of the processing. If SAWC is null, we don't
|
---|
650 | do the \c short-circuiting, and \c is treated as an unrecognized escape
|
---|
651 | sequence; we also bypass the other processing specific to %b arguments. */
|
---|
652 | static int
|
---|
653 | tescape (estart, cp, sawc)
|
---|
654 | char *estart;
|
---|
655 | char *cp;
|
---|
656 | int *sawc;
|
---|
657 | {
|
---|
658 | register char *p;
|
---|
659 | int temp, c, evalue;
|
---|
660 |
|
---|
661 | p = estart;
|
---|
662 |
|
---|
663 | switch (c = *p++)
|
---|
664 | {
|
---|
665 | #if defined (__STDC__)
|
---|
666 | case 'a': *cp = '\a'; break;
|
---|
667 | #else
|
---|
668 | case 'a': *cp = '\007'; break;
|
---|
669 | #endif
|
---|
670 |
|
---|
671 | case 'b': *cp = '\b'; break;
|
---|
672 |
|
---|
673 | case 'e':
|
---|
674 | case 'E': *cp = '\033'; break; /* ESC -- non-ANSI */
|
---|
675 |
|
---|
676 | case 'f': *cp = '\f'; break;
|
---|
677 |
|
---|
678 | case 'n': *cp = '\n'; break;
|
---|
679 |
|
---|
680 | case 'r': *cp = '\r'; break;
|
---|
681 |
|
---|
682 | case 't': *cp = '\t'; break;
|
---|
683 |
|
---|
684 | case 'v': *cp = '\v'; break;
|
---|
685 |
|
---|
686 | /* The octal escape sequences are `\0' followed by up to three octal
|
---|
687 | digits (if SAWC), or `\' followed by up to three octal digits (if
|
---|
688 | !SAWC). As an extension, we allow the latter form even if SAWC. */
|
---|
689 | case '0': case '1': case '2': case '3':
|
---|
690 | case '4': case '5': case '6': case '7':
|
---|
691 | evalue = OCTVALUE (c);
|
---|
692 | for (temp = 2 + (!evalue && !!sawc); ISOCTAL (*p) && temp--; p++)
|
---|
693 | evalue = (evalue * 8) + OCTVALUE (*p);
|
---|
694 | *cp = evalue & 0xFF;
|
---|
695 | break;
|
---|
696 |
|
---|
697 | /* And, as another extension, we allow \xNNN, where each N is a
|
---|
698 | hex digit. */
|
---|
699 | case 'x':
|
---|
700 | #if 0
|
---|
701 | for (evalue = 0; ISXDIGIT ((unsigned char)*p); p++)
|
---|
702 | #else
|
---|
703 | for (temp = 2, evalue = 0; ISXDIGIT ((unsigned char)*p) && temp--; p++)
|
---|
704 | #endif
|
---|
705 | evalue = (evalue * 16) + HEXVALUE (*p);
|
---|
706 | if (p == estart + 1)
|
---|
707 | {
|
---|
708 | builtin_error (_("missing hex digit for \\x"));
|
---|
709 | *cp = '\\';
|
---|
710 | return 0;
|
---|
711 | }
|
---|
712 | *cp = evalue & 0xFF;
|
---|
713 | break;
|
---|
714 |
|
---|
715 | case '\\': /* \\ -> \ */
|
---|
716 | *cp = c;
|
---|
717 | break;
|
---|
718 |
|
---|
719 | /* SAWC == 0 means that \', \", and \? are recognized as escape
|
---|
720 | sequences, though the only processing performed is backslash
|
---|
721 | removal. */
|
---|
722 | case '\'': case '"': case '?':
|
---|
723 | if (!sawc)
|
---|
724 | *cp = c;
|
---|
725 | else
|
---|
726 | {
|
---|
727 | *cp = '\\';
|
---|
728 | return 0;
|
---|
729 | }
|
---|
730 | break;
|
---|
731 |
|
---|
732 | case 'c':
|
---|
733 | if (sawc)
|
---|
734 | {
|
---|
735 | *sawc = 1;
|
---|
736 | break;
|
---|
737 | }
|
---|
738 | /* other backslash escapes are passed through unaltered */
|
---|
739 | default:
|
---|
740 | *cp = '\\';
|
---|
741 | return 0;
|
---|
742 | }
|
---|
743 | return (p - estart);
|
---|
744 | }
|
---|
745 |
|
---|
746 | static char *
|
---|
747 | bexpand (string, len, sawc, lenp)
|
---|
748 | char *string;
|
---|
749 | int len, *sawc, *lenp;
|
---|
750 | {
|
---|
751 | int temp;
|
---|
752 | char *ret, *r, *s, c;
|
---|
753 |
|
---|
754 | #if 0
|
---|
755 | if (string == 0 || *string == '\0')
|
---|
756 | #else
|
---|
757 | if (string == 0 || len == 0)
|
---|
758 | #endif
|
---|
759 | {
|
---|
760 | if (sawc)
|
---|
761 | *sawc = 0;
|
---|
762 | if (lenp)
|
---|
763 | *lenp = 0;
|
---|
764 | return ((char *)NULL);
|
---|
765 | }
|
---|
766 |
|
---|
767 | ret = (char *)xmalloc (len + 1);
|
---|
768 | for (r = ret, s = string; s && *s; )
|
---|
769 | {
|
---|
770 | c = *s++;
|
---|
771 | if (c != '\\' || *s == '\0')
|
---|
772 | {
|
---|
773 | *r++ = c;
|
---|
774 | continue;
|
---|
775 | }
|
---|
776 | temp = 0;
|
---|
777 | s += tescape (s, &c, &temp);
|
---|
778 | if (temp)
|
---|
779 | {
|
---|
780 | if (sawc)
|
---|
781 | *sawc = 1;
|
---|
782 | break;
|
---|
783 | }
|
---|
784 |
|
---|
785 | *r++ = c;
|
---|
786 | }
|
---|
787 |
|
---|
788 | *r = '\0';
|
---|
789 | if (lenp)
|
---|
790 | *lenp = r - ret;
|
---|
791 | return ret;
|
---|
792 | }
|
---|
793 |
|
---|
794 | static char *
|
---|
795 | vbadd (buf, blen)
|
---|
796 | char *buf;
|
---|
797 | int blen;
|
---|
798 | {
|
---|
799 | size_t nlen;
|
---|
800 |
|
---|
801 | nlen = vblen + blen + 1;
|
---|
802 | if (nlen >= vbsize)
|
---|
803 | {
|
---|
804 | vbsize = ((nlen + 63) >> 6) << 6;
|
---|
805 | vbuf = (char *)xrealloc (vbuf, vbsize);
|
---|
806 | }
|
---|
807 |
|
---|
808 | if (blen == 1)
|
---|
809 | vbuf[vblen++] = buf[0];
|
---|
810 | else
|
---|
811 | {
|
---|
812 | FASTCOPY (buf, vbuf + vblen, blen);
|
---|
813 | vblen += blen;
|
---|
814 | }
|
---|
815 | vbuf[vblen] = '\0';
|
---|
816 |
|
---|
817 | #ifdef DEBUG
|
---|
818 | if (strlen (vbuf) != vblen)
|
---|
819 | internal_error ("printf:vbadd: vblen (%d) != strlen (vbuf) (%d)", vblen, strlen (vbuf));
|
---|
820 | #endif
|
---|
821 |
|
---|
822 | return vbuf;
|
---|
823 | }
|
---|
824 |
|
---|
825 | static char *
|
---|
826 | mklong (str, modifiers, mlen)
|
---|
827 | char *str;
|
---|
828 | char *modifiers;
|
---|
829 | size_t mlen;
|
---|
830 | {
|
---|
831 | size_t len, slen;
|
---|
832 |
|
---|
833 | slen = strlen (str);
|
---|
834 | len = slen + mlen + 1;
|
---|
835 |
|
---|
836 | if (len > conv_bufsize)
|
---|
837 | {
|
---|
838 | conv_bufsize = (((len + 1023) >> 10) << 10);
|
---|
839 | conv_buf = (char *)xrealloc (conv_buf, conv_bufsize);
|
---|
840 | }
|
---|
841 |
|
---|
842 | FASTCOPY (str, conv_buf, slen - 1);
|
---|
843 | FASTCOPY (modifiers, conv_buf + slen - 1, mlen);
|
---|
844 |
|
---|
845 | conv_buf[len - 2] = str[slen - 1];
|
---|
846 | conv_buf[len - 1] = '\0';
|
---|
847 | return (conv_buf);
|
---|
848 | }
|
---|
849 |
|
---|
850 | static int
|
---|
851 | getchr ()
|
---|
852 | {
|
---|
853 | int ret;
|
---|
854 |
|
---|
855 | if (garglist == 0)
|
---|
856 | return ('\0');
|
---|
857 |
|
---|
858 | ret = (int)garglist->word->word[0];
|
---|
859 | garglist = garglist->next;
|
---|
860 | return ret;
|
---|
861 | }
|
---|
862 |
|
---|
863 | static char *
|
---|
864 | getstr ()
|
---|
865 | {
|
---|
866 | char *ret;
|
---|
867 |
|
---|
868 | if (garglist == 0)
|
---|
869 | return ("");
|
---|
870 |
|
---|
871 | ret = garglist->word->word;
|
---|
872 | garglist = garglist->next;
|
---|
873 | return ret;
|
---|
874 | }
|
---|
875 |
|
---|
876 | static int
|
---|
877 | getint ()
|
---|
878 | {
|
---|
879 | intmax_t ret;
|
---|
880 |
|
---|
881 | ret = getintmax ();
|
---|
882 |
|
---|
883 | if (ret > INT_MAX)
|
---|
884 | {
|
---|
885 | printf_erange (garglist->word->word);
|
---|
886 | ret = INT_MAX;
|
---|
887 | }
|
---|
888 | else if (ret < INT_MIN)
|
---|
889 | {
|
---|
890 | printf_erange (garglist->word->word);
|
---|
891 | ret = INT_MIN;
|
---|
892 | }
|
---|
893 |
|
---|
894 | return ((int)ret);
|
---|
895 | }
|
---|
896 |
|
---|
897 | static intmax_t
|
---|
898 | getintmax ()
|
---|
899 | {
|
---|
900 | intmax_t ret;
|
---|
901 | char *ep;
|
---|
902 |
|
---|
903 | if (garglist == 0)
|
---|
904 | return (0);
|
---|
905 |
|
---|
906 | if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"')
|
---|
907 | return asciicode ();
|
---|
908 |
|
---|
909 | errno = 0;
|
---|
910 | ret = strtoimax (garglist->word->word, &ep, 0);
|
---|
911 |
|
---|
912 | if (*ep)
|
---|
913 | {
|
---|
914 | sh_invalidnum (garglist->word->word);
|
---|
915 | /* POSIX.2 says ``...a diagnostic message shall be written to standard
|
---|
916 | error, and the utility shall not exit with a zero exit status, but
|
---|
917 | shall continue processing any remaining operands and shall write the
|
---|
918 | value accumulated at the time the error was detected to standard
|
---|
919 | output.'' Yecch. */
|
---|
920 | ret = 0;
|
---|
921 | conversion_error = 1;
|
---|
922 | }
|
---|
923 | else if (errno == ERANGE)
|
---|
924 | printf_erange (garglist->word->word);
|
---|
925 |
|
---|
926 | garglist = garglist->next;
|
---|
927 | return (ret);
|
---|
928 | }
|
---|
929 |
|
---|
930 | static uintmax_t
|
---|
931 | getuintmax ()
|
---|
932 | {
|
---|
933 | uintmax_t ret;
|
---|
934 | char *ep;
|
---|
935 |
|
---|
936 | if (garglist == 0)
|
---|
937 | return (0);
|
---|
938 |
|
---|
939 | if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"')
|
---|
940 | return asciicode ();
|
---|
941 |
|
---|
942 | errno = 0;
|
---|
943 | ret = strtoumax (garglist->word->word, &ep, 0);
|
---|
944 |
|
---|
945 | if (*ep)
|
---|
946 | {
|
---|
947 | sh_invalidnum (garglist->word->word);
|
---|
948 | /* Same POSIX.2 conversion error requirements as getintmax(). */
|
---|
949 | ret = 0;
|
---|
950 | conversion_error = 1;
|
---|
951 | }
|
---|
952 | else if (errno == ERANGE)
|
---|
953 | printf_erange (garglist->word->word);
|
---|
954 |
|
---|
955 | garglist = garglist->next;
|
---|
956 | return (ret);
|
---|
957 | }
|
---|
958 |
|
---|
959 | static floatmax_t
|
---|
960 | getfloatmax ()
|
---|
961 | {
|
---|
962 | floatmax_t ret;
|
---|
963 | char *ep;
|
---|
964 |
|
---|
965 | if (garglist == 0)
|
---|
966 | return (0);
|
---|
967 |
|
---|
968 | if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"')
|
---|
969 | return asciicode ();
|
---|
970 |
|
---|
971 | errno = 0;
|
---|
972 | ret = strtofltmax (garglist->word->word, &ep);
|
---|
973 |
|
---|
974 | if (*ep)
|
---|
975 | {
|
---|
976 | sh_invalidnum (garglist->word->word);
|
---|
977 | /* Same thing about POSIX.2 conversion error requirements. */
|
---|
978 | ret = 0;
|
---|
979 | conversion_error = 1;
|
---|
980 | }
|
---|
981 | else if (errno == ERANGE)
|
---|
982 | printf_erange (garglist->word->word);
|
---|
983 |
|
---|
984 | garglist = garglist->next;
|
---|
985 | return (ret);
|
---|
986 | }
|
---|
987 |
|
---|
988 | /* NO check is needed for garglist here. */
|
---|
989 | static int
|
---|
990 | asciicode ()
|
---|
991 | {
|
---|
992 | register int ch;
|
---|
993 |
|
---|
994 | ch = garglist->word->word[1];
|
---|
995 | garglist = garglist->next;
|
---|
996 | return (ch);
|
---|
997 | }
|
---|