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