]> git.ipfire.org Git - thirdparty/bash.git/blame - print_cmd.c
Imported from ../bash-2.05a.tar.gz.
[thirdparty/bash.git] / print_cmd.c
CommitLineData
726f6388
JA
1/* print_command -- A way to make readable commands from a command tree. */
2/* Copyright (C) 1989 Free Software Foundation, Inc.
3
4This file is part of GNU Bash, the Bourne Again SHell.
5
6Bash is free software; you can redistribute it and/or modify it under
7the terms of the GNU General Public License as published by the Free
bb70624e 8Software Foundation; either version 2, or (at your option) any later
726f6388
JA
9version.
10
11Bash is distributed in the hope that it will be useful, but WITHOUT ANY
12WARRANTY; without even the implied warranty of MERCHANTABILITY or
13FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14for more details.
15
16You should have received a copy of the GNU General Public License along
17with Bash; see the file COPYING. If not, write to the Free Software
bb70624e 18Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
726f6388 19
ccc6cda3
JA
20#include "config.h"
21
726f6388
JA
22#include <stdio.h>
23
ccc6cda3 24#if defined (HAVE_UNISTD_H)
cce855bc
JA
25# ifdef _MINIX
26# include <sys/types.h>
27# endif
ccc6cda3
JA
28# include <unistd.h>
29#endif
30
31#if defined (PREFER_STDARG)
32# include <stdarg.h>
33#else
34# if defined (PREFER_VARARGS)
35# include <varargs.h>
36# endif
726f6388
JA
37#endif
38
ccc6cda3 39#include "bashansi.h"
726f6388
JA
40
41#include "shell.h"
d166f048 42#include <y.tab.h> /* use <...> so we pick it up from the build directory */
726f6388
JA
43#include "stdc.h"
44#include "builtins/common.h"
45
f73dda09 46#if !HAVE_DECL_PRINTF
726f6388
JA
47extern int printf __P((const char *, ...)); /* Yuck. Double yuck. */
48#endif
49
ccc6cda3 50static int indentation;
726f6388
JA
51static int indentation_amount = 4;
52
d166f048 53#if defined (PREFER_STDARG)
f73dda09
JA
54typedef void PFUNC __P((const char *, ...));
55
56static void cprintf __P((const char *, ...)) __attribute__((__format__ (printf, 1, 2)));
57static void xprintf __P((const char *, ...)) __attribute__((__format__ (printf, 1, 2)));
d166f048 58#else
f73dda09 59#define PFUNC VFunction
d166f048 60static void cprintf ();
f73dda09 61static void xprintf ();
d166f048 62#endif
ccc6cda3 63
f73dda09
JA
64static void reset_locals __P((void));
65static void newline __P((char *));
66static void indent __P((int));
67static void semicolon __P((void));
68static void the_printed_command_resize __P((int));
726f6388 69
f73dda09
JA
70static void make_command_string_internal __P((COMMAND *));
71static void _print_word_list __P((WORD_LIST *, char *, PFUNC *));
72static void command_print_word_list __P((WORD_LIST *, char *));
73static void print_case_clauses __P((PATTERN_LIST *));
74static void print_redirection_list __P((REDIRECT *));
75static void print_redirection __P((REDIRECT *));
726f6388 76
f73dda09
JA
77static void print_for_command __P((FOR_COM *));
78#if defined (ARITH_FOR_COMMAND)
79static void print_arith_for_command __P((ARITH_FOR_COM *));
80#endif
726f6388 81#if defined (SELECT_COMMAND)
f73dda09 82static void print_select_command __P((SELECT_COM *));
726f6388 83#endif
f73dda09
JA
84static void print_group_command __P((GROUP_COM *));
85static void print_case_command __P((CASE_COM *));
86static void print_while_command __P((WHILE_COM *));
87static void print_until_command __P((WHILE_COM *));
88static void print_until_or_while __P((WHILE_COM *, char *));
89static void print_if_command __P((IF_COM *));
cce855bc 90#if defined (DPAREN_ARITHMETIC)
f73dda09 91static void print_arith_command __P((ARITH_COM *));
cce855bc
JA
92#endif
93#if defined (COND_COMMAND)
f73dda09
JA
94static void print_cond_node __P((COND_COM *));
95static void print_cond_command __P((COND_COM *));
bb70624e 96#endif
f73dda09 97static void print_function_def __P((FUNCTION_DEF *));
726f6388 98
d166f048
JA
99#define PRINTED_COMMAND_INITIAL_SIZE 64
100#define PRINTED_COMMAND_GROW_SIZE 128
726f6388
JA
101
102char *the_printed_command = (char *)NULL;
103int the_printed_command_size = 0;
104int command_string_index = 0;
105
106/* Non-zero means the stuff being printed is inside of a function def. */
ccc6cda3
JA
107static int inside_function_def;
108static int skip_this_indent;
d166f048 109static int was_heredoc;
726f6388
JA
110
111/* The depth of the group commands that we are currently printing. This
112 includes the group command that is a function body. */
ccc6cda3 113static int group_command_nesting;
726f6388
JA
114
115/* Print COMMAND (a command tree) on standard output. */
116void
117print_command (command)
118 COMMAND *command;
119{
120 command_string_index = 0;
121 printf ("%s", make_command_string (command));
122}
123
124/* Make a string which is the printed representation of the command
125 tree in COMMAND. We return this string. However, the string is
126 not consed, so you have to do that yourself if you want it to
127 remain around. */
128char *
129make_command_string (command)
130 COMMAND *command;
131{
d166f048 132 command_string_index = was_heredoc = 0;
726f6388
JA
133 make_command_string_internal (command);
134 return (the_printed_command);
135}
136
137/* The internal function. This is the real workhorse. */
138static void
139make_command_string_internal (command)
140 COMMAND *command;
141{
ccc6cda3 142 if (command == 0)
726f6388
JA
143 cprintf ("");
144 else
145 {
146 if (skip_this_indent)
147 skip_this_indent--;
148 else
149 indent (indentation);
150
ccc6cda3 151 if (command->flags & CMD_TIME_PIPELINE)
d166f048
JA
152 {
153 cprintf ("time ");
154 if (command->flags & CMD_TIME_POSIX)
155 cprintf ("-p ");
156 }
ccc6cda3 157
726f6388
JA
158 if (command->flags & CMD_INVERT_RETURN)
159 cprintf ("! ");
160
161 switch (command->type)
162 {
163 case cm_for:
164 print_for_command (command->value.For);
165 break;
166
bb70624e
JA
167#if defined (ARITH_FOR_COMMAND)
168 case cm_arith_for:
169 print_arith_for_command (command->value.ArithFor);
170 break;
171#endif
172
726f6388
JA
173#if defined (SELECT_COMMAND)
174 case cm_select:
175 print_select_command (command->value.Select);
176 break;
177#endif
178
179 case cm_case:
180 print_case_command (command->value.Case);
181 break;
182
183 case cm_while:
184 print_while_command (command->value.While);
185 break;
186
187 case cm_until:
188 print_until_command (command->value.While);
189 break;
190
191 case cm_if:
192 print_if_command (command->value.If);
193 break;
194
cce855bc
JA
195#if defined (DPAREN_ARITHMETIC)
196 case cm_arith:
197 print_arith_command (command->value.Arith);
198 break;
199#endif
200
201#if defined (COND_COMMAND)
202 case cm_cond:
203 print_cond_command (command->value.Cond);
204 break;
205#endif
206
726f6388
JA
207 case cm_simple:
208 print_simple_command (command->value.Simple);
209 break;
210
ccc6cda3 211 case cm_connection:
726f6388
JA
212
213 skip_this_indent++;
214 make_command_string_internal (command->value.Connection->first);
215
216 switch (command->value.Connection->connector)
217 {
218 case '&':
219 case '|':
220 {
221 char c = command->value.Connection->connector;
222 cprintf (" %c", c);
223 if (c != '&' || command->value.Connection->second)
224 {
225 cprintf (" ");
226 skip_this_indent++;
227 }
228 }
229 break;
230
231 case AND_AND:
232 cprintf (" && ");
233 if (command->value.Connection->second)
234 skip_this_indent++;
235 break;
236
237 case OR_OR:
238 cprintf (" || ");
239 if (command->value.Connection->second)
240 skip_this_indent++;
241 break;
ccc6cda3 242
726f6388 243 case ';':
d166f048
JA
244 if (was_heredoc == 0)
245 cprintf (";");
246 else
247 was_heredoc = 0;
726f6388
JA
248
249 if (inside_function_def)
250 cprintf ("\n");
251 else
252 {
253 cprintf (" ");
254 if (command->value.Connection->second)
255 skip_this_indent++;
256 }
257 break;
258
259 default:
260 cprintf ("print_command: bad connector `%d'",
261 command->value.Connection->connector);
262 break;
263 }
264
265 make_command_string_internal (command->value.Connection->second);
266 break;
ccc6cda3 267
726f6388
JA
268 case cm_function_def:
269 print_function_def (command->value.Function_def);
270 break;
271
272 case cm_group:
273 print_group_command (command->value.Group);
274 break;
275
bb70624e
JA
276 case cm_subshell:
277 cprintf ("( ");
278 skip_this_indent++;
279 make_command_string_internal (command->value.Subshell->command);
280 cprintf (" )");
281 break;
282
726f6388 283 default:
b72432fd 284 command_error ("print_command", CMDERR_BADTYPE, command->type, 0);
726f6388
JA
285 break;
286 }
287
726f6388
JA
288
289 if (command->redirects)
b72432fd
JA
290 {
291 cprintf (" ");
292 print_redirection_list (command->redirects);
293 }
726f6388
JA
294 }
295}
296
297static void
298_print_word_list (list, separator, pfunc)
299 WORD_LIST *list;
300 char *separator;
f73dda09 301 PFUNC *pfunc;
726f6388 302{
ccc6cda3
JA
303 WORD_LIST *w;
304
305 for (w = list; w; w = w->next)
306 (*pfunc) ("%s%s", w->word->word, w->next ? separator : "");
726f6388
JA
307}
308
ccc6cda3
JA
309void
310print_word_list (list, separator)
726f6388
JA
311 WORD_LIST *list;
312 char *separator;
313{
ccc6cda3
JA
314 _print_word_list (list, separator, xprintf);
315}
316
317/* A function to print the words of a simple command when set -x is on. */
318void
319xtrace_print_word_list (list)
320 WORD_LIST *list;
321{
322 WORD_LIST *w;
e8ce775d 323 char *t, *x;
ccc6cda3
JA
324
325 fprintf (stderr, "%s", indirection_level_string ());
326 for (w = list; w; w = w->next)
327 {
328 t = w->word->word;
329 if (t == 0 || *t == '\0')
e8ce775d 330 fprintf (stderr, "''%s", w->next ? " " : "");
28ef6c31 331 else if (sh_contains_shell_metas (t))
e8ce775d 332 {
28ef6c31 333 x = sh_single_quote (t);
e8ce775d
JA
334 fprintf (stderr, "%s%s", x, w->next ? " " : "");
335 free (x);
336 }
ccc6cda3 337 else
e8ce775d 338 fprintf (stderr, "%s%s", t, w->next ? " " : "");
ccc6cda3
JA
339 }
340 fprintf (stderr, "\n");
726f6388
JA
341}
342
343static void
344command_print_word_list (list, separator)
345 WORD_LIST *list;
346 char *separator;
347{
348 _print_word_list (list, separator, cprintf);
349}
350
351static void
352print_for_command (for_command)
353 FOR_COM *for_command;
354{
355 cprintf ("for %s in ", for_command->name->word);
356 command_print_word_list (for_command->map_list, " ");
357 cprintf (";");
358 newline ("do\n");
359 indentation += indentation_amount;
360 make_command_string_internal (for_command->action);
361 semicolon ();
362 indentation -= indentation_amount;
363 newline ("done");
364}
365
bb70624e
JA
366#if defined (ARITH_FOR_COMMAND)
367static void
368print_arith_for_command (arith_for_command)
369 ARITH_FOR_COM *arith_for_command;
370{
371 cprintf ("for (( ");
372 command_print_word_list (arith_for_command->init, " ");
373 cprintf (" ; ");
374 command_print_word_list (arith_for_command->test, " ");
375 cprintf (" ; ");
376 command_print_word_list (arith_for_command->step, " ");
377 cprintf (" ))");
378 newline ("do\n");
379 indentation += indentation_amount;
380 make_command_string_internal (arith_for_command->action);
381 semicolon ();
382 indentation -= indentation_amount;
383 newline ("done");
384}
385#endif /* ARITH_FOR_COMMAND */
386
726f6388
JA
387#if defined (SELECT_COMMAND)
388static void
389print_select_command (select_command)
390 SELECT_COM *select_command;
391{
392 cprintf ("select %s in ", select_command->name->word);
393 command_print_word_list (select_command->map_list, " ");
394 cprintf (";");
395 newline ("do\n");
396 indentation += indentation_amount;
397 make_command_string_internal (select_command->action);
398 semicolon ();
399 indentation -= indentation_amount;
400 newline ("done");
401}
402#endif /* SELECT_COMMAND */
403
404static void
405print_group_command (group_command)
406 GROUP_COM *group_command;
407{
408 group_command_nesting++;
409 cprintf ("{ ");
410
ccc6cda3 411 if (inside_function_def == 0)
726f6388
JA
412 skip_this_indent++;
413 else
414 {
415 /* This is a group command { ... } inside of a function
ccc6cda3 416 definition, and should be printed as a multiline group
726f6388
JA
417 command, using the current indentation. */
418 cprintf ("\n");
419 indentation += indentation_amount;
420 }
421
422 make_command_string_internal (group_command->command);
423
ccc6cda3 424 if (inside_function_def)
726f6388 425 {
ccc6cda3 426 cprintf ("\n");
726f6388
JA
427 indentation -= indentation_amount;
428 indent (indentation);
726f6388 429 }
ccc6cda3
JA
430 else
431 {
432 semicolon ();
433 cprintf (" ");
434 }
435
726f6388 436 cprintf ("}");
ccc6cda3 437
726f6388
JA
438 group_command_nesting--;
439}
440
441static void
442print_case_command (case_command)
443 CASE_COM *case_command;
444{
445 cprintf ("case %s in ", case_command->word->word);
446 if (case_command->clauses)
447 print_case_clauses (case_command->clauses);
448 newline ("esac");
449}
450
451static void
452print_case_clauses (clauses)
453 PATTERN_LIST *clauses;
454{
455 indentation += indentation_amount;
456 while (clauses)
457 {
458 newline ("");
459 command_print_word_list (clauses->patterns, " | ");
460 cprintf (")\n");
461 indentation += indentation_amount;
462 make_command_string_internal (clauses->action);
463 indentation -= indentation_amount;
464 newline (";;");
465 clauses = clauses->next;
466 }
467 indentation -= indentation_amount;
468}
469
470static void
471print_while_command (while_command)
472 WHILE_COM *while_command;
473{
474 print_until_or_while (while_command, "while");
475}
476
477static void
478print_until_command (while_command)
479 WHILE_COM *while_command;
480{
481 print_until_or_while (while_command, "until");
482}
483
484static void
485print_until_or_while (while_command, which)
486 WHILE_COM *while_command;
487 char *which;
488{
489 cprintf ("%s ", which);
490 skip_this_indent++;
491 make_command_string_internal (while_command->test);
492 semicolon ();
493 cprintf (" do\n"); /* was newline ("do\n"); */
494 indentation += indentation_amount;
495 make_command_string_internal (while_command->action);
496 indentation -= indentation_amount;
497 semicolon ();
498 newline ("done");
499}
500
501static void
502print_if_command (if_command)
503 IF_COM *if_command;
504{
505 cprintf ("if ");
506 skip_this_indent++;
507 make_command_string_internal (if_command->test);
508 semicolon ();
509 cprintf (" then\n");
510 indentation += indentation_amount;
511 make_command_string_internal (if_command->true_case);
512 indentation -= indentation_amount;
513
514 if (if_command->false_case)
515 {
516 semicolon ();
517 newline ("else\n");
518 indentation += indentation_amount;
519 make_command_string_internal (if_command->false_case);
520 indentation -= indentation_amount;
521 }
522 semicolon ();
523 newline ("fi");
524}
525
cce855bc
JA
526#if defined (DPAREN_ARITHMETIC)
527static void
528print_arith_command (arith_command)
529 ARITH_COM *arith_command;
530{
531 cprintf ("(( ");
532 command_print_word_list (arith_command->exp, " ");
533 cprintf (" ))");
534}
bb70624e 535#endif
cce855bc
JA
536
537#if defined (COND_COMMAND)
538static void
539print_cond_node (cond)
540 COND_COM *cond;
541{
542 if (cond->flags & CMD_INVERT_RETURN)
543 cprintf ("! ");
544
545 if (cond->type == COND_EXPR)
546 {
547 cprintf ("( ");
548 print_cond_node (cond->left);
549 cprintf (" )");
550 }
551 else if (cond->type == COND_AND)
552 {
553 print_cond_node (cond->left);
554 cprintf (" && ");
555 print_cond_node (cond->right);
556 }
557 else if (cond->type == COND_OR)
558 {
559 print_cond_node (cond->left);
560 cprintf (" || ");
561 print_cond_node (cond->right);
562 }
563 else if (cond->type == COND_UNARY)
564 {
b72432fd 565 cprintf ("%s", cond->op->word);
cce855bc
JA
566 cprintf (" ");
567 print_cond_node (cond->left);
568 }
569 else if (cond->type == COND_BINARY)
570 {
571 print_cond_node (cond->left);
572 cprintf (" ");
b72432fd 573 cprintf ("%s", cond->op->word);
cce855bc
JA
574 cprintf (" ");
575 print_cond_node (cond->right);
576 }
577 else if (cond->type == COND_TERM)
578 {
b72432fd 579 cprintf ("%s", cond->op->word); /* need to add quoting here */
cce855bc
JA
580 }
581}
582
583static void
584print_cond_command (cond)
585 COND_COM *cond;
586{
587 cprintf ("[[ ");
588 print_cond_node (cond);
589 cprintf (" ]]");
590}
591
28ef6c31 592#ifdef DEBUG
cce855bc
JA
593void
594debug_print_cond_command (cond)
595 COND_COM *cond;
596{
597 fprintf (stderr, "DEBUG: ");
598 command_string_index = 0;
599 print_cond_command (cond);
600 fprintf (stderr, "%s\n", the_printed_command);
601}
28ef6c31 602#endif
cce855bc
JA
603
604void
605xtrace_print_cond_term (type, invert, op, arg1, arg2)
606 int type, invert;
607 WORD_DESC *op;
608 char *arg1, *arg2;
609{
610 command_string_index = 0;
611 fprintf (stderr, "%s", indirection_level_string ());
612 fprintf (stderr, "[[ ");
613 if (invert)
614 fprintf (stderr, "! ");
615
616 if (type == COND_UNARY)
617 {
618 fprintf (stderr, "%s ", op->word);
619 fprintf (stderr, "%s", (arg1 && *arg1) ? arg1 : "''");
620 }
621 else if (type == COND_BINARY)
622 {
623 fprintf (stderr, "%s", (arg1 && *arg1) ? arg1 : "''");
624 fprintf (stderr, " %s ", op->word);
625 fprintf (stderr, "%s", (arg2 && *arg2) ? arg2 : "''");
626 }
627
628 fprintf (stderr, " ]]\n");
629}
630#endif /* COND_COMMAND */
631
bb70624e 632#if defined (DPAREN_ARITHMETIC) || defined (ARITH_FOR_COMMAND)
cce855bc
JA
633/* A function to print the words of an arithmetic command when set -x is on. */
634void
635xtrace_print_arith_cmd (list)
636 WORD_LIST *list;
637{
638 WORD_LIST *w;
639
640 fprintf (stderr, "%s", indirection_level_string ());
641 fprintf (stderr, "(( ");
642 for (w = list; w; w = w->next)
643 fprintf (stderr, "%s%s", w->word->word, w->next ? " " : "");
644 fprintf (stderr, " ))\n");
645}
646#endif
647
726f6388
JA
648void
649print_simple_command (simple_command)
650 SIMPLE_COM *simple_command;
651{
652 command_print_word_list (simple_command->words, " ");
653
654 if (simple_command->redirects)
655 {
656 cprintf (" ");
657 print_redirection_list (simple_command->redirects);
658 }
659}
660
661static void
662print_redirection_list (redirects)
663 REDIRECT *redirects;
664{
d166f048
JA
665 REDIRECT *heredocs, *hdtail, *newredir;
666
667 heredocs = (REDIRECT *)NULL;
668 hdtail = heredocs;
669
670 was_heredoc = 0;
726f6388
JA
671 while (redirects)
672 {
d166f048
JA
673 /* Defer printing the here documents until we've printed the
674 rest of the redirections. */
675 if (redirects->instruction == r_reading_until || redirects->instruction == r_deblank_reading_until)
676 {
677 newredir = copy_redirect (redirects);
678 newredir->next = (REDIRECT *)NULL;
679 if (heredocs)
680 {
681 hdtail->next = newredir;
682 hdtail = newredir;
683 }
684 else
685 hdtail = heredocs = newredir;
686 }
687 else
688 print_redirection (redirects);
689
726f6388
JA
690 redirects = redirects->next;
691 if (redirects)
692 cprintf (" ");
693 }
d166f048
JA
694
695 /* Now that we've printed all the other redirections (on one line),
696 print the here documents. */
697 if (heredocs)
698 {
699 cprintf (" ");
700 for (hdtail = heredocs; hdtail; hdtail = hdtail->next)
28ef6c31 701 {
d166f048
JA
702 print_redirection (hdtail);
703 cprintf ("\n");
28ef6c31 704 }
d166f048
JA
705 dispose_redirects (heredocs);
706 was_heredoc = 1;
707 }
726f6388
JA
708}
709
710static void
711print_redirection (redirect)
712 REDIRECT *redirect;
713{
d166f048
JA
714 int kill_leading, redirector, redir_fd;
715 WORD_DESC *redirectee;
716
717 kill_leading = 0;
718 redirectee = redirect->redirectee.filename;
719 redirector = redirect->redirector;
720 redir_fd = redirect->redirectee.dest;
726f6388
JA
721
722 switch (redirect->instruction)
723 {
724 case r_output_direction:
725 if (redirector != 1)
726 cprintf ("%d", redirector);
727 cprintf (">%s", redirectee->word);
728 break;
729
730 case r_input_direction:
731 if (redirector != 0)
732 cprintf ("%d", redirector);
733 cprintf ("<%s", redirectee->word);
734 break;
735
736 case r_inputa_direction: /* Redirection created by the shell. */
737 cprintf ("&");
738 break;
739
740 case r_appending_to:
741 if (redirector != 1)
742 cprintf ("%d", redirector);
743 cprintf (">>%s", redirectee->word);
744 break;
745
746 case r_deblank_reading_until:
747 kill_leading++;
748 /* ... */
749 case r_reading_until:
750 if (redirector != 0)
751 cprintf ("%d", redirector);
752 /* If the here document delimiter is quoted, single-quote it. */
ccc6cda3 753 if (redirect->redirectee.filename->flags & W_QUOTED)
28ef6c31
JA
754 {
755 char *x;
756 x = sh_single_quote (redirect->here_doc_eof);
726f6388 757 cprintf ("<<%s%s\n", kill_leading? "-" : "", x);
28ef6c31
JA
758 free (x);
759 }
726f6388
JA
760 else
761 cprintf ("<<%s%s\n", kill_leading? "-" : "", redirect->here_doc_eof);
762 cprintf ("%s%s",
763 redirect->redirectee.filename->word, redirect->here_doc_eof);
764 break;
765
766 case r_duplicating_input:
767 cprintf ("%d<&%d", redirector, redir_fd);
768 break;
769
770 case r_duplicating_output:
771 cprintf ("%d>&%d", redirector, redir_fd);
772 break;
773
774 case r_duplicating_input_word:
775 cprintf ("%d<&%s", redirector, redirectee->word);
776 break;
777
778 case r_duplicating_output_word:
779 cprintf ("%d>&%s", redirector, redirectee->word);
780 break;
781
782 case r_close_this:
783 cprintf ("%d>&-", redirector);
784 break;
785
786 case r_err_and_out:
787 cprintf (">&%s", redirectee->word);
788 break;
789
790 case r_input_output:
791 if (redirector != 1)
792 cprintf ("%d", redirector);
793 cprintf ("<>%s", redirectee->word);
794 break;
795
796 case r_output_force:
797 if (redirector != 1)
798 cprintf ("%d", redirector);
799 cprintf (">|%s", redirectee->word);
800 break;
801 }
802}
803
804static void
805reset_locals ()
806{
807 inside_function_def = 0;
808 indentation = 0;
809}
810
811static void
812print_function_def (func)
813 FUNCTION_DEF *func;
814{
bb70624e
JA
815 COMMAND *cmdcopy;
816 REDIRECT *func_redirects;
817
f73dda09 818 func_redirects = NULL;
726f6388
JA
819 cprintf ("function %s () \n", func->name->word);
820 add_unwind_protect (reset_locals, 0);
821
822 indent (indentation);
823 cprintf ("{ \n");
824
825 inside_function_def++;
826 indentation += indentation_amount;
827
bb70624e
JA
828 cmdcopy = copy_command (func->command);
829 if (cmdcopy->type == cm_group)
830 {
28ef6c31
JA
831 func_redirects = cmdcopy->redirects;
832 cmdcopy->redirects = (REDIRECT *)NULL;
bb70624e
JA
833 }
834 make_command_string_internal (cmdcopy->type == cm_group
835 ? cmdcopy->value.Group->command
836 : cmdcopy);
ccc6cda3 837
726f6388
JA
838 remove_unwind_protect ();
839 indentation -= indentation_amount;
840 inside_function_def--;
841
bb70624e
JA
842 if (func_redirects)
843 { /* { */
844 newline ("} ");
845 print_redirection_list (func_redirects);
28ef6c31 846 cmdcopy->redirects = func_redirects;
bb70624e
JA
847 }
848 else
849 newline ("}");
850
851 dispose_command (cmdcopy);
726f6388
JA
852}
853
854/* Return the string representation of the named function.
855 NAME is the name of the function.
856 COMMAND is the function body. It should be a GROUP_COM.
857 MULTI_LINE is non-zero to pretty-print, or zero for all on one line.
858 */
859char *
860named_function_string (name, command, multi_line)
861 char *name;
862 COMMAND *command;
863 int multi_line;
864{
865 char *result;
ccc6cda3 866 int old_indent, old_amount;
bb70624e
JA
867 COMMAND *cmdcopy;
868 REDIRECT *func_redirects;
726f6388 869
ccc6cda3
JA
870 old_indent = indentation;
871 old_amount = indentation_amount;
d166f048 872 command_string_index = was_heredoc = 0;
726f6388
JA
873
874 if (name && *name)
875 cprintf ("%s ", name);
876
877 cprintf ("() ");
878
ccc6cda3 879 if (multi_line == 0)
726f6388
JA
880 {
881 indentation = 1;
882 indentation_amount = 0;
883 }
884 else
885 {
886 cprintf ("\n");
887 indentation += indentation_amount;
888 }
889
890 inside_function_def++;
891
ccc6cda3 892 cprintf (multi_line ? "{ \n" : "{ ");
726f6388 893
bb70624e
JA
894 cmdcopy = copy_command (command);
895 /* Take any redirections specified in the function definition (which should
896 apply to the function as a whole) and save them for printing later. */
897 func_redirects = (REDIRECT *)NULL;
898 if (cmdcopy->type == cm_group)
899 {
28ef6c31
JA
900 func_redirects = cmdcopy->redirects;
901 cmdcopy->redirects = (REDIRECT *)NULL;
bb70624e
JA
902 }
903 make_command_string_internal (cmdcopy->type == cm_group
904 ? cmdcopy->value.Group->command
905 : cmdcopy);
726f6388
JA
906
907 indentation = old_indent;
908 indentation_amount = old_amount;
909 inside_function_def--;
910
bb70624e
JA
911 if (func_redirects)
912 { /* { */
913 newline ("} ");
914 print_redirection_list (func_redirects);
28ef6c31 915 cmdcopy->redirects = func_redirects;
bb70624e
JA
916 }
917 else
918 newline ("}");
726f6388
JA
919
920 result = the_printed_command;
921
922 if (!multi_line)
923 {
924#if 0
925 register int i;
926 for (i = 0; result[i]; i++)
927 if (result[i] == '\n')
928 {
929 strcpy (result + i, result + i + 1);
930 --i;
931 }
932#else
933 if (result[2] == '\n') /* XXX -- experimental */
28ef6c31 934 strcpy (result + 2, result + 3);
726f6388
JA
935#endif
936 }
937
bb70624e
JA
938 dispose_command (cmdcopy);
939
726f6388
JA
940 return (result);
941}
942
943static void
944newline (string)
945 char *string;
946{
947 cprintf ("\n");
948 indent (indentation);
949 if (string && *string)
950 cprintf ("%s", string);
951}
952
ccc6cda3
JA
953static char *indentation_string;
954static int indentation_size;
955
726f6388
JA
956static void
957indent (amount)
958 int amount;
959{
ccc6cda3
JA
960 register int i;
961
962 RESIZE_MALLOCED_BUFFER (indentation_string, 0, amount, indentation_size, 16);
963
964 for (i = 0; amount > 0; amount--)
965 indentation_string[i++] = ' ';
966 indentation_string[i] = '\0';
967 cprintf (indentation_string);
726f6388
JA
968}
969
970static void
971semicolon ()
972{
973 if (command_string_index > 0 && the_printed_command[command_string_index - 1] == '&')
974 return;
975 cprintf (";");
976}
977
ccc6cda3 978#if !defined (USE_VARARGS)
726f6388
JA
979/* How to make the string. */
980static void
981cprintf (format, arg1, arg2)
f73dda09
JA
982 const char *format;
983 char *arg1, *arg2;
726f6388 984{
f73dda09
JA
985 register const char *s;
986 char char_arg[2], *argp, *args[2], intbuf[INT_STRLEN_BOUND(int) + 1];
987 int arg_len, c, arg_index, digit_arg;
726f6388
JA
988
989 args[arg_index = 0] = arg1;
990 args[1] = arg2;
991
992 arg_len = strlen (format);
993 the_printed_command_resize (arg_len + 1);
994
995 char_arg[1] = '\0';
996 s = format;
997 while (s && *s)
998 {
999 int free_argp = 0;
1000 c = *s++;
1001 if (c != '%' || !*s)
1002 {
f73dda09
JA
1003 char_arg[0] = c;
1004 argp = char_arg;
726f6388
JA
1005 arg_len = 1;
1006 }
1007 else
1008 {
1009 c = *s++;
1010 switch (c)
1011 {
1012 case '%':
1013 char_arg[0] = c;
1014 argp = char_arg;
1015 arg_len = 1;
1016 break;
1017
1018 case 's':
1019 argp = (char *)args[arg_index++];
1020 arg_len = strlen (argp);
1021 break;
1022
1023 case 'd':
f73dda09
JA
1024 /* Represent an out-of-range file descriptor with an out-of-range
1025 integer value. We can do this because the only use of `%d' in
1026 the calls to cprintf is to output a file descriptor number for
1027 a redirection. */
1028 digit_arg = pointer_to_int (args[arg_index]);
1029 if (digit_arg < 0)
1030 {
1031 sprintf (intbuf, "%u", (unsigned)-1);
1032 argp = intbuf;
1033 }
1034 else
1035 argp = inttostr (digit_arg, intbuf, sizeof (intbuf));
726f6388
JA
1036 arg_index++;
1037 arg_len = strlen (argp);
726f6388
JA
1038 break;
1039
1040 case 'c':
1041 char_arg[0] = pointer_to_int (args[arg_index]);
1042 arg_index++;
1043 argp = char_arg;
1044 arg_len = 1;
1045 break;
1046
1047 default:
1048 programming_error ("cprintf: bad `%%' argument (%c)", c);
1049 }
1050 }
1051 if (argp)
1052 {
1053 the_printed_command_resize (arg_len + 1);
1054 FASTCOPY (argp, the_printed_command + command_string_index, arg_len);
1055 command_string_index += arg_len;
1056 if (free_argp)
1057 free (argp);
1058 }
1059 }
1060
1061 the_printed_command[command_string_index] = '\0';
1062}
1063
1064#else /* We have support for varargs. */
1065
1066/* How to make the string. */
1067static void
ccc6cda3 1068#if defined (PREFER_STDARG)
f73dda09 1069cprintf (const char *control, ...)
ccc6cda3
JA
1070#else
1071cprintf (control, va_alist)
f73dda09 1072 const char *control;
726f6388 1073 va_dcl
ccc6cda3 1074#endif
726f6388 1075{
f73dda09
JA
1076 register const char *s;
1077 char char_arg[2], *argp, intbuf[INT_STRLEN_BOUND (int) + 1];
726f6388
JA
1078 int digit_arg, arg_len, c;
1079 va_list args;
1080
ccc6cda3
JA
1081#if defined (PREFER_STDARG)
1082 va_start (args, control);
1083#else
726f6388 1084 va_start (args);
ccc6cda3 1085#endif
726f6388
JA
1086
1087 arg_len = strlen (control);
1088 the_printed_command_resize (arg_len + 1);
1089
1090 char_arg[1] = '\0';
1091 s = control;
1092 while (s && *s)
1093 {
ccc6cda3
JA
1094 int free_argp;
1095 free_argp = 0;
726f6388 1096 c = *s++;
ccc6cda3 1097 argp = (char *)NULL;
726f6388
JA
1098 if (c != '%' || !*s)
1099 {
f73dda09
JA
1100 char_arg[0] = c;
1101 argp = char_arg;
726f6388
JA
1102 arg_len = 1;
1103 }
1104 else
1105 {
1106 c = *s++;
1107 switch (c)
1108 {
1109 case '%':
1110 char_arg[0] = c;
1111 argp = char_arg;
1112 arg_len = 1;
1113 break;
1114
1115 case 's':
1116 argp = va_arg (args, char *);
1117 arg_len = strlen (argp);
1118 break;
1119
1120 case 'd':
f73dda09
JA
1121 /* Represent an out-of-range file descriptor with an out-of-range
1122 integer value. We can do this because the only use of `%d' in
1123 the calls to cprintf is to output a file descriptor number for
1124 a redirection. */
726f6388 1125 digit_arg = va_arg (args, int);
f73dda09
JA
1126 if (digit_arg < 0)
1127 {
1128 sprintf (intbuf, "%u", (unsigned)-1);
1129 argp = intbuf;
1130 }
1131 else
1132 argp = inttostr (digit_arg, intbuf, sizeof (intbuf));
726f6388 1133 arg_len = strlen (argp);
726f6388
JA
1134 break;
1135
1136 case 'c':
1137 char_arg[0] = va_arg (args, int);
1138 argp = char_arg;
1139 arg_len = 1;
1140 break;
1141
1142 default:
1143 programming_error ("cprintf: bad `%%' argument (%c)", c);
ccc6cda3 1144 /*NOTREACHED*/
726f6388
JA
1145 }
1146 }
1147
ccc6cda3 1148 if (argp && arg_len)
726f6388
JA
1149 {
1150 the_printed_command_resize (arg_len + 1);
1151 FASTCOPY (argp, the_printed_command + command_string_index, arg_len);
1152 command_string_index += arg_len;
1153 if (free_argp)
1154 free (argp);
1155 }
1156 }
1157
1158 the_printed_command[command_string_index] = '\0';
1159}
1160#endif /* HAVE_VARARGS_H */
1161
1162/* Ensure that there is enough space to stuff LENGTH characters into
1163 THE_PRINTED_COMMAND. */
1164static void
1165the_printed_command_resize (length)
1166 int length;
1167{
d166f048 1168 if (the_printed_command == 0)
726f6388 1169 {
d166f048 1170 the_printed_command_size = (length + PRINTED_COMMAND_INITIAL_SIZE - 1) & ~(PRINTED_COMMAND_INITIAL_SIZE - 1);
f73dda09 1171 the_printed_command = (char *)xmalloc (the_printed_command_size);
726f6388
JA
1172 command_string_index = 0;
1173 }
1174 else if ((command_string_index + length) >= the_printed_command_size)
1175 {
1176 int new;
1177 new = command_string_index + length + 1;
bb70624e 1178
d166f048
JA
1179 /* Round up to the next multiple of PRINTED_COMMAND_GROW_SIZE. */
1180 new = (new + PRINTED_COMMAND_GROW_SIZE - 1) & ~(PRINTED_COMMAND_GROW_SIZE - 1);
726f6388 1181 the_printed_command_size = new;
bb70624e 1182
f73dda09 1183 the_printed_command = (char *)xrealloc (the_printed_command, the_printed_command_size);
726f6388
JA
1184 }
1185}
ccc6cda3 1186
f73dda09
JA
1187#if defined (HAVE_VPRINTF)
1188/* ``If vprintf is available, you may assume that vfprintf and vsprintf are
1189 also available.'' */
ccc6cda3
JA
1190
1191static void
d166f048
JA
1192#if defined (PREFER_STDARG)
1193xprintf (const char *format, ...)
1194#else
1195xprintf (format, va_alist)
1196 const char *format;
ccc6cda3 1197 va_dcl
d166f048 1198#endif
ccc6cda3
JA
1199{
1200 va_list args;
ccc6cda3 1201
d166f048
JA
1202#if defined (PREFER_STDARG)
1203 va_start (args, format);
1204#else
ccc6cda3 1205 va_start (args);
d166f048
JA
1206#endif
1207
ccc6cda3
JA
1208 vfprintf (stdout, format, args);
1209 va_end (args);
1210}
1211
1212#else
1213
1214static void
1215xprintf (format, arg1, arg2, arg3, arg4, arg5)
f73dda09 1216 const char *format;
ccc6cda3
JA
1217{
1218 printf (format, arg1, arg2, arg3, arg4, arg5);
1219}
1220
f73dda09 1221#endif /* !HAVE_VPRINTF */