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