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