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