]> git.ipfire.org Git - thirdparty/bash.git/blob - print_cmd.c
changes to quoting for some globbing characters; regularize error behavior of builtin...
[thirdparty/bash.git] / print_cmd.c
1 /* print_command -- A way to make readable commands from a command tree. */
2
3 /* Copyright (C) 1989-2023 Free Software Foundation, Inc.
4
5 This file is part of GNU Bash, the Bourne Again SHell.
6
7 Bash is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 Bash is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Bash. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "config.h"
22
23 #include <stdio.h>
24
25 #if defined (HAVE_UNISTD_H)
26 # ifdef _MINIX
27 # include <sys/types.h>
28 # endif
29 # include <unistd.h>
30 #endif
31
32 #include <stdarg.h>
33
34 #include "bashansi.h"
35 #include "bashintl.h"
36
37 #define NEED_XTRACE_SET_DECL
38
39 #include "shell.h"
40 #include "flags.h"
41 #include <y.tab.h> /* use <...> so we pick it up from the build directory */
42 #include "input.h"
43
44 #include "shmbutil.h"
45
46 #include "builtins/common.h"
47
48 #if !HAVE_DECL_PRINTF
49 extern int printf (const char *, ...); /* Yuck. Double yuck. */
50 #endif
51
52 static int indentation;
53 static int indentation_amount = 4;
54
55 typedef void PFUNC (const char *, ...);
56
57 static void cprintf (const char *, ...) __attribute__((__format__ (printf, 1, 2)));
58 static void xprintf (const char *, ...) __attribute__((__format__ (printf, 1, 2)));
59
60 static void uw_reset_locals (void *);
61
62 static void newline (char *);
63 static void indent (int);
64 static void semicolon (void);
65 static void the_printed_command_resize (size_t);
66
67 static void make_command_string_internal (COMMAND *);
68 static void _print_word_list (WORD_LIST *, char *, PFUNC *);
69 static void command_print_word_list (WORD_LIST *, char *);
70 static void print_case_clauses (PATTERN_LIST *);
71 static void print_redirection_list (REDIRECT *);
72 static void print_redirection (REDIRECT *);
73 static void print_heredoc_header (REDIRECT *);
74 static void print_heredoc_body (REDIRECT *);
75 static void print_heredocs (REDIRECT *);
76 static void print_heredoc_bodies (REDIRECT *);
77 static void print_deferred_heredocs (const char *);
78
79 static void print_for_command (FOR_COM *);
80 #if defined (ARITH_FOR_COMMAND)
81 static void print_arith_for_command (ARITH_FOR_COM *);
82 #endif
83 #if defined (SELECT_COMMAND)
84 static void print_select_command (SELECT_COM *);
85 #endif
86 static void print_group_command (GROUP_COM *);
87 static void print_case_command (CASE_COM *);
88 static void print_while_command (WHILE_COM *);
89 static void print_until_command (WHILE_COM *);
90 static void print_until_or_while (WHILE_COM *, char *);
91 static void print_if_command (IF_COM *);
92 #if defined (COND_COMMAND)
93 static void print_cond_node (COND_COM *);
94 #endif
95 static void print_function_def (FUNCTION_DEF *);
96
97 #ifdef DEBUG
98 void debug_print_word_list (char *, WORD_LIST *, char *);
99 void debug_print_cond_command (COND_COM *);
100 #endif
101
102 #define PRINTED_COMMAND_INITIAL_SIZE 64
103 #define PRINTED_COMMAND_GROW_SIZE 128
104
105 char *the_printed_command = (char *)NULL;
106 size_t the_printed_command_size = 0;
107 int command_string_index = 0;
108
109 int xtrace_fd = -1;
110 FILE *xtrace_fp = 0;
111
112 #define CHECK_XTRACE_FP xtrace_fp = (xtrace_fp ? xtrace_fp : stderr)
113
114 /* shell expansion characters: used in print_redirection_list */
115 #define EXPCHAR(c) ((c) == '{' || (c) == '~' || (c) == '$' || (c) == '`')
116
117 #define PRINT_DEFERRED_HEREDOCS(x) \
118 do { \
119 if (deferred_heredocs) \
120 print_deferred_heredocs (x); \
121 } while (0)
122
123 /* Non-zero means the stuff being printed is inside of a function def. */
124 static int inside_function_def;
125 static int skip_this_indent;
126 static int was_heredoc;
127 static int printing_connection;
128 static int printing_comsub;
129 static REDIRECT *deferred_heredocs;
130
131 /* The depth of the group commands that we are currently printing. This
132 includes the group command that is a function body. */
133 static int group_command_nesting;
134
135 /* A buffer to indicate the indirection level (PS4) when set -x is enabled. */
136 static char *indirection_string = 0;
137 static size_t indirection_stringsiz = 0;
138
139 /* Print COMMAND (a command tree) on standard output. */
140 void
141 print_command (COMMAND *command)
142 {
143 command_string_index = 0;
144 printf ("%s", make_command_string (command));
145 }
146
147 /* Make a string which is the printed representation of the command
148 tree in COMMAND. We return this string. However, the string is
149 not consed, so you have to do that yourself if you want it to
150 remain around. */
151 char *
152 make_command_string (COMMAND *command)
153 {
154 command_string_index = was_heredoc = 0;
155 deferred_heredocs = 0;
156 make_command_string_internal (command);
157 return (the_printed_command);
158 }
159
160 /* Print a command substitution after parsing it in parse_comsub to turn it
161 back into an external representation without turning newlines into `;'.
162 Placeholder for other changes, if any are necessary. */
163 char *
164 print_comsub (COMMAND *command)
165 {
166 char *ret;
167
168 printing_comsub++;
169 ret = make_command_string (command);
170 printing_comsub--;
171 return ret;
172 }
173
174 /* The internal function. This is the real workhorse. */
175 static void
176 make_command_string_internal (COMMAND *command)
177 {
178 char s[3];
179
180 if (command == 0)
181 cprintf ("");
182 else
183 {
184 if (skip_this_indent)
185 skip_this_indent--;
186 else
187 indent (indentation);
188
189 if (command->flags & CMD_TIME_PIPELINE)
190 {
191 cprintf ("time ");
192 if (command->flags & CMD_TIME_POSIX)
193 cprintf ("-p ");
194 }
195
196 if (command->flags & CMD_INVERT_RETURN)
197 cprintf ("! ");
198
199 switch (command->type)
200 {
201 case cm_for:
202 print_for_command (command->value.For);
203 break;
204
205 #if defined (ARITH_FOR_COMMAND)
206 case cm_arith_for:
207 print_arith_for_command (command->value.ArithFor);
208 break;
209 #endif
210
211 #if defined (SELECT_COMMAND)
212 case cm_select:
213 print_select_command (command->value.Select);
214 break;
215 #endif
216
217 case cm_case:
218 print_case_command (command->value.Case);
219 break;
220
221 case cm_while:
222 print_while_command (command->value.While);
223 break;
224
225 case cm_until:
226 print_until_command (command->value.While);
227 break;
228
229 case cm_if:
230 print_if_command (command->value.If);
231 break;
232
233 #if defined (DPAREN_ARITHMETIC)
234 case cm_arith:
235 print_arith_command (command->value.Arith->exp);
236 break;
237 #endif
238
239 #if defined (COND_COMMAND)
240 case cm_cond:
241 print_cond_command (command->value.Cond);
242 break;
243 #endif
244
245 case cm_simple:
246 print_simple_command (command->value.Simple);
247 break;
248
249 case cm_connection:
250
251 skip_this_indent++;
252 printing_connection++;
253 make_command_string_internal (command->value.Connection->first);
254
255 switch (command->value.Connection->connector)
256 {
257 case '&':
258 case '|':
259 {
260 char c = command->value.Connection->connector;
261
262 s[0] = ' ';
263 s[1] = c;
264 s[2] = '\0';
265
266 print_deferred_heredocs (s);
267
268 if (c != '&' || command->value.Connection->second)
269 {
270 cprintf (" ");
271 skip_this_indent++;
272 }
273 }
274 break;
275
276 case AND_AND:
277 print_deferred_heredocs (" && ");
278 if (command->value.Connection->second)
279 skip_this_indent++;
280 break;
281
282 case OR_OR:
283 print_deferred_heredocs (" || ");
284 if (command->value.Connection->second)
285 skip_this_indent++;
286 break;
287
288 case ';':
289 case '\n': /* special case this */
290 {
291 char c = command->value.Connection->connector;
292 int was_newline;
293
294 s[0] = printing_comsub ? c : ';';
295 s[1] = '\0';
296
297 was_newline = deferred_heredocs == 0 && was_heredoc == 0 && c == '\n';
298 if (deferred_heredocs == 0)
299 {
300 if (was_heredoc == 0)
301 cprintf ("%s", s); /* inside_function_def? */
302 else
303 was_heredoc = 0;
304 }
305 else
306 /* print_deferred_heredocs special-cases `;' */
307 print_deferred_heredocs (inside_function_def ? "" : ";");
308
309 if (inside_function_def)
310 cprintf ("\n");
311 else if (printing_comsub && c == '\n' && was_newline == 0)
312 cprintf ("\n"); /* preserve newlines in comsubs but don't double them */
313 else
314 {
315 if (c == ';')
316 cprintf (" ");
317 if (command->value.Connection->second)
318 skip_this_indent++;
319 }
320 break;
321 }
322
323 default:
324 cprintf (_("print_command: bad connector `%d'"),
325 command->value.Connection->connector);
326 break;
327 }
328
329 make_command_string_internal (command->value.Connection->second);
330 /* If this is a recursive call to make_command_string_internal to
331 print a connection with more than two components, defer printing
332 the here-document bodies until our caller can print the
333 connector. Remember that the parser builds lists to be left-side
334 heavy. */
335 if (printing_connection == 1)
336 PRINT_DEFERRED_HEREDOCS ("");
337 printing_connection--;
338 break;
339
340 case cm_function_def:
341 print_function_def (command->value.Function_def);
342 break;
343
344 case cm_group:
345 print_group_command (command->value.Group);
346 break;
347
348 case cm_subshell:
349 cprintf ("( ");
350 skip_this_indent++;
351 make_command_string_internal (command->value.Subshell->command);
352 PRINT_DEFERRED_HEREDOCS ("");
353 cprintf (" )");
354 was_heredoc = 0; /* last wasn't heredoc/newline */
355 break;
356
357 case cm_coproc:
358 cprintf ("coproc %s ", command->value.Coproc->name);
359 skip_this_indent++;
360 make_command_string_internal (command->value.Coproc->command);
361 break;
362
363 default:
364 command_error ("print_command", CMDERR_BADTYPE, command->type, 0);
365 break;
366 }
367
368
369 if (command->redirects)
370 {
371 cprintf (" ");
372 print_redirection_list (command->redirects);
373 }
374 }
375 }
376
377 static void
378 _print_word_list (WORD_LIST *list, char *separator, PFUNC *pfunc)
379 {
380 WORD_LIST *w;
381
382 for (w = list; w; w = w->next)
383 (*pfunc) ("%s%s", w->word->word, w->next ? separator : "");
384 }
385
386 void
387 print_word_list (WORD_LIST *list, char *separator)
388 {
389 _print_word_list (list, separator, xprintf);
390 }
391
392 void
393 xtrace_set (int fd, FILE *fp)
394 {
395 if (fd >= 0 && sh_validfd (fd) == 0)
396 {
397 internal_error (_("xtrace_set: %d: invalid file descriptor"), fd);
398 return;
399 }
400 if (fp == 0)
401 {
402 internal_error (_("xtrace_set: NULL file pointer"));
403 return;
404 }
405 if (fd >= 0 && fileno (fp) != fd)
406 internal_warning (_("xtrace fd (%d) != fileno xtrace fp (%d)"), fd, fileno (fp));
407
408 xtrace_fd = fd;
409 xtrace_fp = fp;
410 }
411
412 void
413 xtrace_init (void)
414 {
415 xtrace_set (-1, stderr);
416 }
417
418 void
419 xtrace_reset (void)
420 {
421 if (xtrace_fd >= 0 && xtrace_fp)
422 {
423 fflush (xtrace_fp);
424 fclose (xtrace_fp);
425 }
426 else if (xtrace_fd >= 0)
427 close (xtrace_fd);
428
429 xtrace_fd = -1;
430 xtrace_fp = stderr;
431 }
432
433 void
434 xtrace_fdchk (int fd)
435 {
436 if (fd == xtrace_fd)
437 xtrace_reset ();
438 }
439
440 /* Return a string denoting what our indirection level is. */
441
442 char *
443 indirection_level_string (void)
444 {
445 register int i, j;
446 char *ps4;
447 char ps4_firstc[MB_LEN_MAX+1];
448 size_t ps4_firstc_len, ps4_len, ineed;
449 int old;
450 DECLARE_MBSTATE;
451
452 ps4 = get_string_value ("PS4");
453 if (indirection_string == 0)
454 indirection_string = xmalloc (indirection_stringsiz = 100);
455 indirection_string[0] = '\0';
456
457 if (ps4 == 0 || *ps4 == '\0')
458 return (indirection_string);
459
460 old = change_flag ('x', FLAG_OFF);
461 ps4 = decode_prompt_string (ps4);
462 if (old)
463 change_flag ('x', FLAG_ON);
464
465 if (ps4 == 0 || *ps4 == '\0')
466 {
467 FREE (ps4);
468 return (indirection_string);
469 }
470
471 #if defined (HANDLE_MULTIBYTE)
472 ps4_len = strnlen (ps4, MB_CUR_MAX);
473 ps4_firstc_len = MBRLEN (ps4, ps4_len, &state);
474 if (ps4_firstc_len == 1 || ps4_firstc_len == 0 || ps4_firstc_len < 0)
475 {
476 ps4_firstc[0] = ps4[0];
477 ps4_firstc[ps4_firstc_len = 1] = '\0';
478 }
479 else
480 memcpy (ps4_firstc, ps4, ps4_firstc_len);
481 #else
482 ps4_firstc[0] = ps4[0];
483 ps4_firstc[ps4_firstc_len = 1] = '\0';
484 #endif
485
486 /* Dynamically resize indirection_string so we have room for everything
487 and we don't have to truncate ps4 */
488 ineed = (ps4_firstc_len * indirection_level) + strlen (ps4);
489 if (ineed + 1 > indirection_stringsiz)
490 {
491 indirection_stringsiz = ineed + 1;
492 indirection_string = xrealloc (indirection_string, indirection_stringsiz);
493 }
494
495 for (i = j = 0; ps4_firstc[0] && j < indirection_level && i < indirection_stringsiz - 1; i += ps4_firstc_len, j++)
496 {
497 if (ps4_firstc_len == 1)
498 indirection_string[i] = ps4_firstc[0];
499 else
500 memcpy (indirection_string+i, ps4_firstc, ps4_firstc_len);
501 }
502
503 for (j = ps4_firstc_len; *ps4 && ps4[j] && i < indirection_stringsiz - 1; i++, j++)
504 indirection_string[i] = ps4[j];
505
506 indirection_string[i] = '\0';
507 free (ps4);
508 return (indirection_string);
509 }
510
511 void
512 xtrace_print_assignment (char *name, char *value, int assign_list, int xflags)
513 {
514 char *nval;
515
516 CHECK_XTRACE_FP;
517
518 if (xflags)
519 fprintf (xtrace_fp, "%s", indirection_level_string ());
520
521 /* VALUE should not be NULL when this is called. */
522 if (*value == '\0' || assign_list)
523 nval = value;
524 else if (ansic_shouldquote (value))
525 nval = ansic_quote (value, 0, (int *)0);
526 else if (sh_contains_shell_metas (value))
527 nval = sh_single_quote (value);
528 else
529 nval = value;
530
531 if (assign_list)
532 fprintf (xtrace_fp, "%s=(%s)\n", name, nval);
533 else
534 fprintf (xtrace_fp, "%s=%s\n", name, nval);
535
536 if (nval != value)
537 FREE (nval);
538
539 fflush (xtrace_fp);
540 }
541
542 /* A function to print the words of a simple command when set -x is on. Also used to
543 print the word list in a for or select command header; in that case, we suppress
544 quoting the words because they haven't been expanded yet. XTFLAGS&1 means to
545 print $PS4; XTFLAGS&2 means to suppress quoting the words in LIST. */
546 void
547 xtrace_print_word_list (WORD_LIST *list, int xtflags)
548 {
549 WORD_LIST *w;
550 char *t, *x;
551
552 CHECK_XTRACE_FP;
553
554 if (xtflags&1)
555 fprintf (xtrace_fp, "%s", indirection_level_string ());
556
557 for (w = list; w; w = w->next)
558 {
559 t = w->word->word;
560 if (t == 0 || *t == '\0')
561 fprintf (xtrace_fp, "''%s", w->next ? " " : "");
562 else if (xtflags & 2)
563 fprintf (xtrace_fp, "%s%s", t, w->next ? " " : "");
564 else if (ansic_shouldquote (t))
565 {
566 x = ansic_quote (t, 0, (int *)0);
567 fprintf (xtrace_fp, "%s%s", x, w->next ? " " : "");
568 free (x);
569 }
570 else if (sh_contains_shell_metas (t))
571 {
572 x = sh_single_quote (t);
573 fprintf (xtrace_fp, "%s%s", x, w->next ? " " : "");
574 free (x);
575 }
576 else
577 fprintf (xtrace_fp, "%s%s", t, w->next ? " " : "");
578 }
579 fprintf (xtrace_fp, "\n");
580 fflush (xtrace_fp);
581 }
582
583 static void
584 command_print_word_list (WORD_LIST *list, char *separator)
585 {
586 _print_word_list (list, separator, cprintf);
587 }
588
589 void
590 print_for_command_head (FOR_COM *for_command)
591 {
592 cprintf ("for %s in ", for_command->name->word);
593 command_print_word_list (for_command->map_list, " ");
594 }
595
596 void
597 xtrace_print_for_command_head (FOR_COM *for_command)
598 {
599 CHECK_XTRACE_FP;
600 fprintf (xtrace_fp, "%s", indirection_level_string ());
601 fprintf (xtrace_fp, "for %s in ", for_command->name->word);
602 xtrace_print_word_list (for_command->map_list, 2);
603 }
604
605 static void
606 print_for_command (FOR_COM *for_command)
607 {
608 print_for_command_head (for_command);
609 cprintf (";");
610 newline ("do\n");
611
612 indentation += indentation_amount;
613 make_command_string_internal (for_command->action);
614 PRINT_DEFERRED_HEREDOCS ("");
615 semicolon ();
616 indentation -= indentation_amount;
617
618 newline ("done");
619 }
620
621 #if defined (ARITH_FOR_COMMAND)
622 static void
623 print_arith_for_command (ARITH_FOR_COM *arith_for_command)
624 {
625 cprintf ("for ((");
626 command_print_word_list (arith_for_command->init, " ");
627 cprintf ("; ");
628 command_print_word_list (arith_for_command->test, " ");
629 cprintf ("; ");
630 command_print_word_list (arith_for_command->step, " ");
631 cprintf ("))");
632 newline ("do\n");
633 indentation += indentation_amount;
634 make_command_string_internal (arith_for_command->action);
635 PRINT_DEFERRED_HEREDOCS ("");
636 semicolon ();
637 indentation -= indentation_amount;
638 newline ("done");
639 }
640 #endif /* ARITH_FOR_COMMAND */
641
642 #if defined (SELECT_COMMAND)
643 void
644 print_select_command_head (SELECT_COM *select_command)
645 {
646 cprintf ("select %s in ", select_command->name->word);
647 command_print_word_list (select_command->map_list, " ");
648 }
649
650 void
651 xtrace_print_select_command_head (SELECT_COM *select_command)
652 {
653 CHECK_XTRACE_FP;
654 fprintf (xtrace_fp, "%s", indirection_level_string ());
655 fprintf (xtrace_fp, "select %s in ", select_command->name->word);
656 xtrace_print_word_list (select_command->map_list, 2);
657 }
658
659 static void
660 print_select_command (SELECT_COM *select_command)
661 {
662 print_select_command_head (select_command);
663
664 cprintf (";");
665 newline ("do\n");
666 indentation += indentation_amount;
667 make_command_string_internal (select_command->action);
668 PRINT_DEFERRED_HEREDOCS ("");
669 semicolon ();
670 indentation -= indentation_amount;
671 newline ("done");
672 }
673 #endif /* SELECT_COMMAND */
674
675 static void
676 print_group_command (GROUP_COM *group_command)
677 {
678 group_command_nesting++;
679 cprintf ("{ ");
680
681 if (inside_function_def == 0 /* && pretty_print_mode == 0 */)
682 skip_this_indent++;
683 else
684 {
685 /* This is a group command { ... } inside of a function
686 definition, and should be printed as a multiline group
687 command, using the current indentation. */
688 cprintf ("\n");
689 indentation += indentation_amount;
690 }
691
692 make_command_string_internal (group_command->command);
693 PRINT_DEFERRED_HEREDOCS ("");
694
695 if (inside_function_def /* || pretty_print_mode */)
696 {
697 cprintf ("\n");
698 indentation -= indentation_amount;
699 indent (indentation);
700 }
701 else
702 {
703 semicolon ();
704 cprintf (" ");
705 }
706
707 cprintf ("}");
708 was_heredoc = 0; /* last wasn't heredoc/newline */
709
710 group_command_nesting--;
711 }
712
713 void
714 print_case_command_head (CASE_COM *case_command)
715 {
716 cprintf ("case %s in ", case_command->word->word);
717 }
718
719 void
720 xtrace_print_case_command_head (CASE_COM *case_command)
721 {
722 CHECK_XTRACE_FP;
723 fprintf (xtrace_fp, "%s", indirection_level_string ());
724 fprintf (xtrace_fp, "case %s in\n", case_command->word->word);
725 }
726
727 static void
728 print_case_command (CASE_COM *case_command)
729 {
730 print_case_command_head (case_command);
731
732 if (case_command->clauses)
733 print_case_clauses (case_command->clauses);
734 newline ("esac");
735 }
736
737 static void
738 print_case_clauses (PATTERN_LIST *clauses)
739 {
740 indentation += indentation_amount;
741 while (clauses)
742 {
743 newline ("");
744 command_print_word_list (clauses->patterns, " | ");
745 cprintf (")\n");
746 indentation += indentation_amount;
747 make_command_string_internal (clauses->action);
748 indentation -= indentation_amount;
749 PRINT_DEFERRED_HEREDOCS ("");
750 if (clauses->flags & CASEPAT_FALLTHROUGH)
751 newline (";&");
752 else if (clauses->flags & CASEPAT_TESTNEXT)
753 newline (";;&");
754 else
755 newline (";;");
756 clauses = clauses->next;
757 }
758 indentation -= indentation_amount;
759 }
760
761 static void
762 print_while_command (WHILE_COM *while_command)
763 {
764 print_until_or_while (while_command, "while");
765 }
766
767 static void
768 print_until_command (WHILE_COM *while_command)
769 {
770 print_until_or_while (while_command, "until");
771 }
772
773 static void
774 print_until_or_while (WHILE_COM *while_command, char *which)
775 {
776 cprintf ("%s ", which);
777 skip_this_indent++;
778 make_command_string_internal (while_command->test);
779 PRINT_DEFERRED_HEREDOCS ("");
780 semicolon ();
781 if (was_heredoc)
782 {
783 indent (indentation);
784 cprintf ("do\n");
785 was_heredoc = 0;
786 }
787 else
788 cprintf (" do\n"); /* was newline ("do\n"); */
789 indentation += indentation_amount;
790 make_command_string_internal (while_command->action);
791 PRINT_DEFERRED_HEREDOCS ("");
792 indentation -= indentation_amount;
793 semicolon ();
794 newline ("done");
795 }
796
797 static void
798 print_if_command (IF_COM *if_command)
799 {
800 cprintf ("if ");
801 skip_this_indent++;
802 make_command_string_internal (if_command->test);
803 PRINT_DEFERRED_HEREDOCS ("");
804 semicolon ();
805 if (was_heredoc)
806 {
807 indent (indentation_amount);
808 cprintf ("then\n");
809 was_heredoc = 0;
810 }
811 else
812 cprintf (" then\n");
813 indentation += indentation_amount;
814 make_command_string_internal (if_command->true_case);
815 PRINT_DEFERRED_HEREDOCS ("");
816 indentation -= indentation_amount;
817
818 if (if_command->false_case)
819 {
820 semicolon ();
821 newline ("else\n");
822 indentation += indentation_amount;
823 make_command_string_internal (if_command->false_case);
824 PRINT_DEFERRED_HEREDOCS ("");
825 indentation -= indentation_amount;
826 }
827 semicolon ();
828 newline ("fi");
829 }
830
831 #if defined (DPAREN_ARITHMETIC) || defined (ARITH_FOR_COMMAND)
832 void
833 print_arith_command (WORD_LIST *arith_cmd_list)
834 {
835 cprintf ("((");
836 command_print_word_list (arith_cmd_list, " ");
837 cprintf ("))");
838 }
839 #endif
840
841 #if defined (COND_COMMAND)
842 static void
843 print_cond_node (COND_COM *cond)
844 {
845 if (cond->flags & CMD_INVERT_RETURN)
846 cprintf ("! ");
847
848 if (cond->type == COND_EXPR)
849 {
850 cprintf ("( ");
851 print_cond_node (cond->left);
852 cprintf (" )");
853 }
854 else if (cond->type == COND_AND)
855 {
856 print_cond_node (cond->left);
857 cprintf (" && ");
858 print_cond_node (cond->right);
859 }
860 else if (cond->type == COND_OR)
861 {
862 print_cond_node (cond->left);
863 cprintf (" || ");
864 print_cond_node (cond->right);
865 }
866 else if (cond->type == COND_UNARY)
867 {
868 cprintf ("%s", cond->op->word);
869 cprintf (" ");
870 print_cond_node (cond->left);
871 }
872 else if (cond->type == COND_BINARY)
873 {
874 print_cond_node (cond->left);
875 cprintf (" ");
876 cprintf ("%s", cond->op->word);
877 cprintf (" ");
878 print_cond_node (cond->right);
879 }
880 else if (cond->type == COND_TERM)
881 {
882 cprintf ("%s", cond->op->word); /* need to add quoting here */
883 }
884 }
885
886 void
887 print_cond_command (COND_COM *cond)
888 {
889 cprintf ("[[ ");
890 print_cond_node (cond);
891 cprintf (" ]]");
892 }
893
894 #ifdef DEBUG
895 void
896 debug_print_word_list (char *s, WORD_LIST *list, char *sep)
897 {
898 WORD_LIST *w;
899
900 if (s)
901 fprintf (stderr, "%s: ", s);
902 for (w = list; w; w = w->next)
903 fprintf (stderr, "%s%s", w->word->word, w->next ? sep : "");
904 fprintf (stderr, "\n");
905 }
906
907 void
908 debug_print_cond_command (COND_COM *cond)
909 {
910 fprintf (stderr, "DEBUG: ");
911 command_string_index = 0;
912 print_cond_command (cond);
913 fprintf (stderr, "%s\n", the_printed_command);
914 }
915 #endif
916
917 void
918 xtrace_print_cond_term (int type, int invert, WORD_DESC *op, char *arg1, char *arg2)
919 {
920 CHECK_XTRACE_FP;
921 command_string_index = 0;
922 fprintf (xtrace_fp, "%s", indirection_level_string ());
923 fprintf (xtrace_fp, "[[ ");
924 if (invert)
925 fprintf (xtrace_fp, "! ");
926
927 if (type == COND_UNARY)
928 {
929 fprintf (xtrace_fp, "%s ", op->word);
930 fprintf (xtrace_fp, "%s", (arg1 && *arg1) ? arg1 : "''");
931 }
932 else if (type == COND_BINARY)
933 {
934 fprintf (xtrace_fp, "%s", (arg1 && *arg1) ? arg1 : "''");
935 fprintf (xtrace_fp, " %s ", op->word);
936 fprintf (xtrace_fp, "%s", (arg2 && *arg2) ? arg2 : "''");
937 }
938
939 fprintf (xtrace_fp, " ]]\n");
940
941 fflush (xtrace_fp);
942 }
943 #endif /* COND_COMMAND */
944
945 #if defined (DPAREN_ARITHMETIC) || defined (ARITH_FOR_COMMAND)
946 /* A function to print the words of an arithmetic command when set -x is on. */
947 void
948 xtrace_print_arith_cmd (WORD_LIST *list)
949 {
950 WORD_LIST *w;
951
952 CHECK_XTRACE_FP;
953 fprintf (xtrace_fp, "%s", indirection_level_string ());
954 fprintf (xtrace_fp, "(( ");
955 for (w = list; w; w = w->next)
956 fprintf (xtrace_fp, "%s%s", w->word->word, w->next ? " " : "");
957 fprintf (xtrace_fp, " ))\n");
958
959 fflush (xtrace_fp);
960 }
961 #endif
962
963 void
964 print_simple_command (SIMPLE_COM *simple_command)
965 {
966 if (simple_command->words)
967 command_print_word_list (simple_command->words, " ");
968 else
969 cprintf ("");
970
971 if (simple_command->redirects)
972 {
973 if (simple_command->words)
974 cprintf (" ");
975 print_redirection_list (simple_command->redirects);
976 }
977 }
978
979 static void
980 print_heredocs (REDIRECT *heredocs)
981 {
982 REDIRECT *hdtail;
983
984 cprintf (" ");
985 for (hdtail = heredocs; hdtail; hdtail = hdtail->next)
986 {
987 print_redirection (hdtail);
988 cprintf ("\n");
989 }
990 was_heredoc = 1;
991 }
992
993 static void
994 print_heredoc_bodies (REDIRECT *heredocs)
995 {
996 REDIRECT *hdtail;
997
998 cprintf ("\n");
999 for (hdtail = heredocs; hdtail; hdtail = hdtail->next)
1000 {
1001 print_heredoc_body (hdtail);
1002 cprintf ("\n");
1003 }
1004 was_heredoc = 1;
1005 }
1006
1007 /* Print heredocs that are attached to the command before the connector
1008 represented by CSTRING. The parsing semantics require us to print the
1009 here-doc delimiters, then the connector (CSTRING), then the here-doc
1010 bodies. We print the here-doc delimiters in print_redirection_list
1011 and print the connector and the bodies here. We don't print the connector
1012 if it's a `;', but we use it to note not to print an extra space after the
1013 last heredoc body and newline. */
1014 static void
1015 print_deferred_heredocs (const char *cstring)
1016 {
1017 /* We now print the heredoc headers in print_redirection_list */
1018 if (cstring && cstring[0] && (cstring[0] != ';' || cstring[1]))
1019 cprintf ("%s", cstring);
1020 if (deferred_heredocs)
1021 {
1022 print_heredoc_bodies (deferred_heredocs);
1023 if (cstring && cstring[0] && (cstring[0] != ';' || cstring[1]))
1024 cprintf (" "); /* make sure there's at least one space */
1025 dispose_redirects (deferred_heredocs);
1026 was_heredoc = 1;
1027 }
1028 deferred_heredocs = (REDIRECT *)NULL;
1029 }
1030
1031 static void
1032 print_redirection_list (REDIRECT *redirects)
1033 {
1034 REDIRECT *heredocs, *hdtail, *newredir;
1035
1036 heredocs = (REDIRECT *)NULL;
1037 hdtail = heredocs;
1038
1039 was_heredoc = 0;
1040 while (redirects)
1041 {
1042 /* Defer printing the here document bodies until we've printed the rest of the
1043 redirections, but print the headers in the order they're given. */
1044 if (redirects->instruction == r_reading_until || redirects->instruction == r_deblank_reading_until)
1045 {
1046 newredir = copy_redirect (redirects);
1047 newredir->next = (REDIRECT *)NULL;
1048
1049 print_heredoc_header (newredir);
1050
1051 if (heredocs)
1052 {
1053 hdtail->next = newredir;
1054 hdtail = newredir;
1055 }
1056 else
1057 hdtail = heredocs = newredir;
1058 }
1059 else
1060 print_redirection (redirects);
1061
1062 redirects = redirects->next;
1063 if (redirects)
1064 cprintf (" ");
1065 }
1066
1067 /* Now that we've printed all the other redirections (on one line),
1068 print the here documents. If we're printing a connection, we wait until
1069 we print the connector symbol, then we print the here document bodies */
1070 if (heredocs && printing_connection)
1071 deferred_heredocs = heredocs;
1072 else if (heredocs)
1073 {
1074 print_heredoc_bodies (heredocs);
1075 dispose_redirects (heredocs);
1076 }
1077 }
1078
1079 static void
1080 print_heredoc_header (REDIRECT *redirect)
1081 {
1082 int kill_leading;
1083 char *x;
1084
1085 kill_leading = redirect->instruction == r_deblank_reading_until;
1086
1087 /* Here doc header */
1088 if (redirect->rflags & REDIR_VARASSIGN)
1089 cprintf ("{%s}", redirect->redirector.filename->word);
1090 else if (redirect->redirector.dest != 0)
1091 cprintf ("%d", redirect->redirector.dest);
1092
1093 /* If the here document delimiter is quoted, single-quote it. */
1094 if (redirect->redirectee.filename->flags & W_QUOTED)
1095 {
1096 x = sh_single_quote (redirect->here_doc_eof);
1097 cprintf ("<<%s%s", kill_leading ? "-" : "", x);
1098 free (x);
1099 }
1100 else
1101 cprintf ("<<%s%s", kill_leading ? "-" : "", redirect->here_doc_eof);
1102 }
1103
1104 static void
1105 print_heredoc_body (REDIRECT *redirect)
1106 {
1107 /* Here doc body */
1108 cprintf ("%s%s", redirect->redirectee.filename->word, redirect->here_doc_eof);
1109 }
1110
1111 static void
1112 print_redirection (REDIRECT *redirect)
1113 {
1114 int redirector, redir_fd;
1115 WORD_DESC *redirectee, *redir_word;
1116
1117 redirectee = redirect->redirectee.filename;
1118 redir_fd = redirect->redirectee.dest;
1119
1120 redir_word = redirect->redirector.filename;
1121 redirector = redirect->redirector.dest;
1122
1123 switch (redirect->instruction)
1124 {
1125 case r_input_direction:
1126 if (redirect->rflags & REDIR_VARASSIGN)
1127 cprintf ("{%s}", redir_word->word);
1128 else if (redirector != 0)
1129 cprintf ("%d", redirector);
1130 cprintf ("< %s", redirectee->word);
1131 break;
1132
1133 case r_output_direction:
1134 if (redirect->rflags & REDIR_VARASSIGN)
1135 cprintf ("{%s}", redir_word->word);
1136 else if (redirector != 1)
1137 cprintf ("%d", redirector);
1138 cprintf ("> %s", redirectee->word);
1139 break;
1140
1141 case r_inputa_direction: /* Redirection created by the shell. */
1142 cprintf ("&");
1143 break;
1144
1145 case r_output_force:
1146 if (redirect->rflags & REDIR_VARASSIGN)
1147 cprintf ("{%s}", redir_word->word);
1148 else if (redirector != 1)
1149 cprintf ("%d", redirector);
1150 cprintf (">| %s", redirectee->word);
1151 break;
1152
1153 case r_appending_to:
1154 if (redirect->rflags & REDIR_VARASSIGN)
1155 cprintf ("{%s}", redir_word->word);
1156 else if (redirector != 1)
1157 cprintf ("%d", redirector);
1158 cprintf (">> %s", redirectee->word);
1159 break;
1160
1161 case r_input_output:
1162 if (redirect->rflags & REDIR_VARASSIGN)
1163 cprintf ("{%s}", redir_word->word);
1164 else if (redirector != 1)
1165 cprintf ("%d", redirector);
1166 cprintf ("<> %s", redirectee->word);
1167 break;
1168
1169 case r_deblank_reading_until:
1170 case r_reading_until:
1171 print_heredoc_header (redirect);
1172 cprintf ("\n");
1173 print_heredoc_body (redirect);
1174 break;
1175
1176 case r_reading_string:
1177 if (redirect->rflags & REDIR_VARASSIGN)
1178 cprintf ("{%s}", redir_word->word);
1179 else if (redirector != 0)
1180 cprintf ("%d", redirector);
1181 #if 0
1182 /* Don't need to check whether or not to requote, since original quotes
1183 are still intact. The only thing that has happened is that $'...'
1184 has been replaced with 'expanded ...'. */
1185 if (ansic_shouldquote (redirect->redirectee.filename->word))
1186 {
1187 char *x;
1188 x = ansic_quote (redirect->redirectee.filename->word, 0, (int *)0);
1189 cprintf ("<<< %s", x);
1190 free (x);
1191 }
1192 else
1193 #endif
1194 cprintf ("<<< %s", redirect->redirectee.filename->word);
1195 break;
1196
1197 case r_duplicating_input:
1198 if (redirect->rflags & REDIR_VARASSIGN)
1199 cprintf ("{%s}<&%d", redir_word->word, redir_fd);
1200 else
1201 cprintf ("%d<&%d", redirector, redir_fd);
1202 break;
1203
1204 case r_duplicating_output:
1205 if (redirect->rflags & REDIR_VARASSIGN)
1206 cprintf ("{%s}>&%d", redir_word->word, redir_fd);
1207 else
1208 cprintf ("%d>&%d", redirector, redir_fd);
1209 break;
1210
1211 case r_duplicating_input_word:
1212 if (redirect->rflags & REDIR_VARASSIGN)
1213 cprintf ("{%s}<&%s", redir_word->word, redirectee->word);
1214 else if (redirector == 0)
1215 cprintf ("<&%s", redirectee->word);
1216 else
1217 cprintf ("%d<&%s", redirector, redirectee->word);
1218 break;
1219
1220 case r_duplicating_output_word:
1221 if (redirect->rflags & REDIR_VARASSIGN)
1222 cprintf ("{%s}>&%s", redir_word->word, redirectee->word);
1223 else if (redirector == 1)
1224 cprintf (">&%s", redirectee->word);
1225 else
1226 cprintf ("%d>&%s", redirector, redirectee->word);
1227 break;
1228
1229 case r_move_input:
1230 if (redirect->rflags & REDIR_VARASSIGN)
1231 cprintf ("{%s}<&%d-", redir_word->word, redir_fd);
1232 else
1233 cprintf ("%d<&%d-", redirector, redir_fd);
1234 break;
1235
1236 case r_move_output:
1237 if (redirect->rflags & REDIR_VARASSIGN)
1238 cprintf ("{%s}>&%d-", redir_word->word, redir_fd);
1239 else
1240 cprintf ("%d>&%d-", redirector, redir_fd);
1241 break;
1242
1243 case r_move_input_word:
1244 if (redirect->rflags & REDIR_VARASSIGN)
1245 cprintf ("{%s}<&%s-", redir_word->word, redirectee->word);
1246 else
1247 cprintf ("%d<&%s-", redirector, redirectee->word);
1248 break;
1249
1250 case r_move_output_word:
1251 if (redirect->rflags & REDIR_VARASSIGN)
1252 cprintf ("{%s}>&%s-", redir_word->word, redirectee->word);
1253 else
1254 cprintf ("%d>&%s-", redirector, redirectee->word);
1255 break;
1256
1257 case r_close_this:
1258 if (redirect->rflags & REDIR_VARASSIGN)
1259 cprintf ("{%s}>&-", redir_word->word);
1260 else
1261 cprintf ("%d>&-", redirector);
1262 break;
1263
1264 case r_err_and_out:
1265 cprintf ("&> %s", redirectee->word);
1266 break;
1267
1268 case r_append_err_and_out:
1269 cprintf ("&>> %s", redirectee->word);
1270 break;
1271 }
1272 }
1273
1274 static void
1275 uw_reset_locals (void *ignore)
1276 {
1277 inside_function_def = 0;
1278 indentation = 0;
1279 printing_connection = 0;
1280 deferred_heredocs = 0;
1281 printing_comsub = 0;
1282 }
1283
1284 static void
1285 print_function_def (FUNCTION_DEF *func)
1286 {
1287 COMMAND *cmdcopy;
1288 REDIRECT *func_redirects;
1289
1290 func_redirects = NULL;
1291 /* When in posix mode, print functions as posix specifies them, but prefix
1292 `function' to words that are not valid POSIX identifiers. */
1293 if (posixly_correct == 0)
1294 cprintf ("function %s () \n", func->name->word);
1295 else if (valid_function_name (func->name->word, posixly_correct) == 0)
1296 cprintf ("function %s () \n", func->name->word);
1297 else
1298 cprintf ("%s () \n", func->name->word);
1299
1300 begin_unwind_frame ("function-def");
1301 add_unwind_protect (uw_reset_locals, 0);
1302
1303 indent (indentation);
1304 cprintf ("{ \n"); /* } */
1305
1306 inside_function_def++;
1307 indentation += indentation_amount;
1308
1309 cmdcopy = func->command;
1310 unwind_protect_pointer (cmdcopy);
1311 if (cmdcopy->type == cm_group)
1312 {
1313 func_redirects = cmdcopy->redirects;
1314 cmdcopy->redirects = (REDIRECT *)NULL;
1315 }
1316 make_command_string_internal (cmdcopy->type == cm_group
1317 ? cmdcopy->value.Group->command
1318 : cmdcopy);
1319 PRINT_DEFERRED_HEREDOCS ("");
1320
1321 indentation -= indentation_amount;
1322 inside_function_def--;
1323
1324 if (func_redirects)
1325 { /* { */
1326 newline ("} ");
1327 print_redirection_list (func_redirects);
1328 cmdcopy->redirects = func_redirects;
1329 }
1330 else
1331 {
1332 /* { */
1333 newline ("}");
1334 was_heredoc = 0; /* not printing any here-documents now */
1335 }
1336
1337 discard_unwind_frame ("function-def");
1338 }
1339
1340 /* Return the string representation of the named function.
1341 NAME is the name of the function.
1342 COMMAND is the function body. It should be a GROUP_COM.
1343 flags&FUNC_MULTILINE is non-zero to pretty-print, or zero for all on one line.
1344 flags&FUNC_EXTERNAL means convert from internal to external form
1345 */
1346 char *
1347 named_function_string (char *name, COMMAND *command, int flags)
1348 {
1349 char *result;
1350 int old_indent, old_amount;
1351 COMMAND *cmdcopy;
1352 REDIRECT *func_redirects;
1353
1354 old_indent = indentation;
1355 old_amount = indentation_amount;
1356 command_string_index = was_heredoc = 0;
1357 deferred_heredocs = 0;
1358 printing_comsub = 0;
1359
1360 if (name && *name)
1361 {
1362 if (valid_function_name (name, posixly_correct) == 0)
1363 cprintf ("function ");
1364 cprintf ("%s ", name);
1365 }
1366
1367 cprintf ("() ");
1368
1369 if ((flags & FUNC_MULTILINE) == 0)
1370 {
1371 indentation = 1;
1372 indentation_amount = 0;
1373 }
1374 else
1375 {
1376 cprintf ("\n");
1377 indentation += indentation_amount;
1378 }
1379
1380 inside_function_def++;
1381
1382 cprintf ((flags & FUNC_MULTILINE) ? "{ \n" : "{ "); /* }} */
1383
1384 cmdcopy = command;
1385 unwind_protect_pointer (cmdcopy);
1386
1387 /* Take any redirections specified in the function definition (which should
1388 apply to the function as a whole) and save them for printing later. */
1389 func_redirects = (REDIRECT *)NULL;
1390 if (cmdcopy->type == cm_group)
1391 {
1392 func_redirects = cmdcopy->redirects;
1393 cmdcopy->redirects = (REDIRECT *)NULL;
1394 }
1395 make_command_string_internal (cmdcopy->type == cm_group
1396 ? cmdcopy->value.Group->command
1397 : cmdcopy);
1398 PRINT_DEFERRED_HEREDOCS ("");
1399
1400 indentation = old_indent;
1401 indentation_amount = old_amount;
1402 inside_function_def--;
1403
1404 if (func_redirects)
1405 { /* { */
1406 newline ("} ");
1407 print_redirection_list (func_redirects);
1408 cmdcopy->redirects = func_redirects;
1409 }
1410 else
1411 { /* { */
1412 newline ("}");
1413 was_heredoc = 0;
1414 }
1415
1416 remove_unwind_protect (); /* unwind_protect_pointer */
1417 result = the_printed_command;
1418
1419 if ((flags & FUNC_MULTILINE) == 0)
1420 {
1421 if (result[2] == '\n')
1422 memmove (result + 2, result + 3, strlen (result) - 2);
1423 }
1424
1425 if (flags & FUNC_EXTERNAL)
1426 result = remove_quoted_escapes (result);
1427
1428 return (result);
1429 }
1430
1431 static void
1432 newline (char *string)
1433 {
1434 cprintf ("\n");
1435 indent (indentation);
1436 if (string && *string)
1437 cprintf ("%s", string);
1438 }
1439
1440 static char *indentation_string;
1441 static size_t indentation_size;
1442
1443 static void
1444 indent (int amount)
1445 {
1446 register int i;
1447
1448 RESIZE_MALLOCED_BUFFER (indentation_string, 0, amount, indentation_size, 16);
1449
1450 for (i = 0; amount > 0; amount--)
1451 indentation_string[i++] = ' ';
1452 indentation_string[i] = '\0';
1453 cprintf ("%s", indentation_string);
1454 }
1455
1456 static void
1457 semicolon (void)
1458 {
1459 if ((command_string_index > 0 &&
1460 the_printed_command[command_string_index - 1] == '\n') ||
1461 (command_string_index > 1 &&
1462 the_printed_command[command_string_index - 1] == '&' &&
1463 the_printed_command[command_string_index - 2] == ' '))
1464 return;
1465 cprintf (";");
1466 }
1467
1468 /* How to make the string. */
1469 static void
1470 cprintf (const char *control, ...)
1471 {
1472 const char *s;
1473 char char_arg[2], *argp, intbuf[INT_STRLEN_BOUND (unsigned int) + 1];
1474 int digit_arg, c;
1475 size_t arg_len;
1476 va_list args;
1477
1478 va_start (args, control);
1479
1480 arg_len = strlen (control);
1481 the_printed_command_resize (arg_len + 1);
1482
1483 char_arg[1] = '\0';
1484 s = control;
1485 while (s && *s)
1486 {
1487 c = *s++;
1488 argp = (char *)NULL;
1489 if (c != '%' || !*s)
1490 {
1491 char_arg[0] = c;
1492 argp = char_arg;
1493 arg_len = 1;
1494 }
1495 else
1496 {
1497 c = *s++;
1498 switch (c)
1499 {
1500 case '%':
1501 char_arg[0] = c;
1502 argp = char_arg;
1503 arg_len = 1;
1504 break;
1505
1506 case 's':
1507 argp = va_arg (args, char *);
1508 arg_len = strlen (argp);
1509 break;
1510
1511 case 'd':
1512 /* Represent an out-of-range file descriptor with an out-of-range
1513 integer value. We can do this because the only use of `%d' in
1514 the calls to cprintf is to output a file descriptor number for
1515 a redirection. */
1516 digit_arg = va_arg (args, int);
1517 if (digit_arg < 0)
1518 {
1519 sprintf (intbuf, "%u", (unsigned int)-1);
1520 argp = intbuf;
1521 }
1522 else
1523 argp = inttostr (digit_arg, intbuf, sizeof (intbuf));
1524 arg_len = strlen (argp);
1525 break;
1526
1527 case 'c':
1528 char_arg[0] = va_arg (args, int);
1529 argp = char_arg;
1530 arg_len = 1;
1531 break;
1532
1533 default:
1534 programming_error (_("cprintf: `%c': invalid format character"), c);
1535 /*NOTREACHED*/
1536 }
1537 }
1538
1539 if (argp && arg_len)
1540 {
1541 the_printed_command_resize (arg_len + 1);
1542 FASTCOPY (argp, the_printed_command + command_string_index, arg_len);
1543 command_string_index += arg_len;
1544 }
1545 }
1546
1547 va_end (args);
1548
1549 the_printed_command[command_string_index] = '\0';
1550 }
1551
1552 /* Ensure that there is enough space to stuff LENGTH characters into
1553 THE_PRINTED_COMMAND. */
1554 static void
1555 the_printed_command_resize (size_t length)
1556 {
1557 if (the_printed_command == 0)
1558 {
1559 the_printed_command_size = (length + PRINTED_COMMAND_INITIAL_SIZE - 1) & ~(PRINTED_COMMAND_INITIAL_SIZE - 1);
1560 the_printed_command = (char *)xmalloc (the_printed_command_size);
1561 command_string_index = 0;
1562 }
1563 else if ((command_string_index + length) >= the_printed_command_size)
1564 {
1565 size_t new;
1566 new = command_string_index + length + 1;
1567
1568 /* Round up to the next multiple of PRINTED_COMMAND_GROW_SIZE. */
1569 new = (new + PRINTED_COMMAND_GROW_SIZE - 1) & ~(PRINTED_COMMAND_GROW_SIZE - 1);
1570 the_printed_command_size = new;
1571
1572 the_printed_command = (char *)xrealloc (the_printed_command, the_printed_command_size);
1573 }
1574 }
1575
1576 static void
1577 xprintf (const char *format, ...)
1578 {
1579 va_list args;
1580
1581 va_start (args, format);
1582
1583 vfprintf (stdout, format, args);
1584 va_end (args);
1585 }