]> git.ipfire.org Git - thirdparty/bash.git/blame - print_cmd.c
Imported from ../bash-2.0.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
8Software Foundation; either version 1, or (at your option) any later
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
18Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
ccc6cda3
JA
20#include "config.h"
21
726f6388
JA
22#include <stdio.h>
23
ccc6cda3
JA
24#if defined (HAVE_UNISTD_H)
25# include <unistd.h>
26#endif
27
28#if defined (PREFER_STDARG)
29# include <stdarg.h>
30#else
31# if defined (PREFER_VARARGS)
32# include <varargs.h>
33# endif
726f6388
JA
34#endif
35
ccc6cda3 36#include "bashansi.h"
726f6388
JA
37
38#include "shell.h"
39#include "y.tab.h"
40#include "stdc.h"
41#include "builtins/common.h"
42
ccc6cda3 43#if !defined (PRINTF_DECLARED)
726f6388
JA
44extern int printf __P((const char *, ...)); /* Yuck. Double yuck. */
45#endif
46
ccc6cda3 47static int indentation;
726f6388
JA
48static int indentation_amount = 4;
49
ccc6cda3
JA
50static void cprintf __P((char *, ...));
51
52static void newline (), indent (), the_printed_command_resize ();
726f6388 53static void semicolon ();
ccc6cda3 54static void xprintf ();
726f6388
JA
55
56static void make_command_string_internal ();
57static void command_print_word_list ();
58static void print_case_clauses ();
59static void print_redirection_list ();
60static void print_redirection ();
61
62static void print_for_command ();
63#if defined (SELECT_COMMAND)
64static void print_select_command ();
65#endif
66static void print_group_command ();
67static void print_case_command ();
68static void print_while_command ();
69static void print_until_command ();
70static void print_until_or_while ();
71static void print_if_command ();
72static void print_function_def ();
73
74#define PRINTED_COMMAND_GROW_SIZE 1024
75
76char *the_printed_command = (char *)NULL;
77int the_printed_command_size = 0;
78int command_string_index = 0;
79
80/* Non-zero means the stuff being printed is inside of a function def. */
ccc6cda3
JA
81static int inside_function_def;
82static int skip_this_indent;
726f6388
JA
83
84/* The depth of the group commands that we are currently printing. This
85 includes the group command that is a function body. */
ccc6cda3 86static int group_command_nesting;
726f6388
JA
87
88/* Print COMMAND (a command tree) on standard output. */
89void
90print_command (command)
91 COMMAND *command;
92{
93 command_string_index = 0;
94 printf ("%s", make_command_string (command));
95}
96
97/* Make a string which is the printed representation of the command
98 tree in COMMAND. We return this string. However, the string is
99 not consed, so you have to do that yourself if you want it to
100 remain around. */
101char *
102make_command_string (command)
103 COMMAND *command;
104{
105 command_string_index = 0;
106 make_command_string_internal (command);
107 return (the_printed_command);
108}
109
110/* The internal function. This is the real workhorse. */
111static void
112make_command_string_internal (command)
113 COMMAND *command;
114{
ccc6cda3 115 if (command == 0)
726f6388
JA
116 cprintf ("");
117 else
118 {
119 if (skip_this_indent)
120 skip_this_indent--;
121 else
122 indent (indentation);
123
124 if (command->flags & CMD_WANT_SUBSHELL)
125 cprintf ("( ");
126
ccc6cda3
JA
127 if (command->flags & CMD_TIME_PIPELINE)
128 cprintf ("time ");
129
726f6388
JA
130 if (command->flags & CMD_INVERT_RETURN)
131 cprintf ("! ");
132
133 switch (command->type)
134 {
135 case cm_for:
136 print_for_command (command->value.For);
137 break;
138
139#if defined (SELECT_COMMAND)
140 case cm_select:
141 print_select_command (command->value.Select);
142 break;
143#endif
144
145 case cm_case:
146 print_case_command (command->value.Case);
147 break;
148
149 case cm_while:
150 print_while_command (command->value.While);
151 break;
152
153 case cm_until:
154 print_until_command (command->value.While);
155 break;
156
157 case cm_if:
158 print_if_command (command->value.If);
159 break;
160
161 case cm_simple:
162 print_simple_command (command->value.Simple);
163 break;
164
ccc6cda3 165 case cm_connection:
726f6388
JA
166
167 skip_this_indent++;
168 make_command_string_internal (command->value.Connection->first);
169
170 switch (command->value.Connection->connector)
171 {
172 case '&':
173 case '|':
174 {
175 char c = command->value.Connection->connector;
176 cprintf (" %c", c);
177 if (c != '&' || command->value.Connection->second)
178 {
179 cprintf (" ");
180 skip_this_indent++;
181 }
182 }
183 break;
184
185 case AND_AND:
186 cprintf (" && ");
187 if (command->value.Connection->second)
188 skip_this_indent++;
189 break;
190
191 case OR_OR:
192 cprintf (" || ");
193 if (command->value.Connection->second)
194 skip_this_indent++;
195 break;
ccc6cda3 196
726f6388
JA
197 case ';':
198 cprintf (";");
199
200 if (inside_function_def)
201 cprintf ("\n");
202 else
203 {
204 cprintf (" ");
205 if (command->value.Connection->second)
206 skip_this_indent++;
207 }
208 break;
209
210 default:
211 cprintf ("print_command: bad connector `%d'",
212 command->value.Connection->connector);
213 break;
214 }
215
216 make_command_string_internal (command->value.Connection->second);
217 break;
ccc6cda3 218
726f6388
JA
219 case cm_function_def:
220 print_function_def (command->value.Function_def);
221 break;
222
223 case cm_group:
224 print_group_command (command->value.Group);
225 break;
226
227 default:
228 programming_error ("print_command: bad command type `%d'", command->type);
229 break;
230 }
231
232 if (command->flags & CMD_WANT_SUBSHELL)
233 cprintf (" )");
234
235 if (command->redirects)
236 print_redirection_list (command->redirects);
237 }
238}
239
240static void
241_print_word_list (list, separator, pfunc)
242 WORD_LIST *list;
243 char *separator;
244 VFunction *pfunc;
245{
ccc6cda3
JA
246 WORD_LIST *w;
247
248 for (w = list; w; w = w->next)
249 (*pfunc) ("%s%s", w->word->word, w->next ? separator : "");
726f6388
JA
250}
251
ccc6cda3
JA
252void
253print_word_list (list, separator)
726f6388
JA
254 WORD_LIST *list;
255 char *separator;
256{
ccc6cda3
JA
257 _print_word_list (list, separator, xprintf);
258}
259
260/* A function to print the words of a simple command when set -x is on. */
261void
262xtrace_print_word_list (list)
263 WORD_LIST *list;
264{
265 WORD_LIST *w;
266 char *t;
267
268 fprintf (stderr, "%s", indirection_level_string ());
269 for (w = list; w; w = w->next)
270 {
271 t = w->word->word;
272 if (t == 0 || *t == '\0')
273 fprintf (stderr, "''%s", w->next ? " " : "");
274 else if (contains_shell_metas (t))
275 fprintf (stderr, "'%s'%s", t, w->next ? " " : "");
276 else
277 fprintf (stderr, "%s%s", t, w->next ? " " : "");
278 }
279 fprintf (stderr, "\n");
726f6388
JA
280}
281
282static void
283command_print_word_list (list, separator)
284 WORD_LIST *list;
285 char *separator;
286{
287 _print_word_list (list, separator, cprintf);
288}
289
290static void
291print_for_command (for_command)
292 FOR_COM *for_command;
293{
294 cprintf ("for %s in ", for_command->name->word);
295 command_print_word_list (for_command->map_list, " ");
296 cprintf (";");
297 newline ("do\n");
298 indentation += indentation_amount;
299 make_command_string_internal (for_command->action);
300 semicolon ();
301 indentation -= indentation_amount;
302 newline ("done");
303}
304
305#if defined (SELECT_COMMAND)
306static void
307print_select_command (select_command)
308 SELECT_COM *select_command;
309{
310 cprintf ("select %s in ", select_command->name->word);
311 command_print_word_list (select_command->map_list, " ");
312 cprintf (";");
313 newline ("do\n");
314 indentation += indentation_amount;
315 make_command_string_internal (select_command->action);
316 semicolon ();
317 indentation -= indentation_amount;
318 newline ("done");
319}
320#endif /* SELECT_COMMAND */
321
322static void
323print_group_command (group_command)
324 GROUP_COM *group_command;
325{
326 group_command_nesting++;
327 cprintf ("{ ");
328
ccc6cda3 329 if (inside_function_def == 0)
726f6388
JA
330 skip_this_indent++;
331 else
332 {
333 /* This is a group command { ... } inside of a function
ccc6cda3 334 definition, and should be printed as a multiline group
726f6388
JA
335 command, using the current indentation. */
336 cprintf ("\n");
337 indentation += indentation_amount;
338 }
339
340 make_command_string_internal (group_command->command);
341
ccc6cda3 342 if (inside_function_def)
726f6388 343 {
ccc6cda3 344 cprintf ("\n");
726f6388
JA
345 indentation -= indentation_amount;
346 indent (indentation);
726f6388 347 }
ccc6cda3
JA
348 else
349 {
350 semicolon ();
351 cprintf (" ");
352 }
353
726f6388 354 cprintf ("}");
ccc6cda3 355
726f6388
JA
356 group_command_nesting--;
357}
358
359static void
360print_case_command (case_command)
361 CASE_COM *case_command;
362{
363 cprintf ("case %s in ", case_command->word->word);
364 if (case_command->clauses)
365 print_case_clauses (case_command->clauses);
366 newline ("esac");
367}
368
369static void
370print_case_clauses (clauses)
371 PATTERN_LIST *clauses;
372{
373 indentation += indentation_amount;
374 while (clauses)
375 {
376 newline ("");
377 command_print_word_list (clauses->patterns, " | ");
378 cprintf (")\n");
379 indentation += indentation_amount;
380 make_command_string_internal (clauses->action);
381 indentation -= indentation_amount;
382 newline (";;");
383 clauses = clauses->next;
384 }
385 indentation -= indentation_amount;
386}
387
388static void
389print_while_command (while_command)
390 WHILE_COM *while_command;
391{
392 print_until_or_while (while_command, "while");
393}
394
395static void
396print_until_command (while_command)
397 WHILE_COM *while_command;
398{
399 print_until_or_while (while_command, "until");
400}
401
402static void
403print_until_or_while (while_command, which)
404 WHILE_COM *while_command;
405 char *which;
406{
407 cprintf ("%s ", which);
408 skip_this_indent++;
409 make_command_string_internal (while_command->test);
410 semicolon ();
411 cprintf (" do\n"); /* was newline ("do\n"); */
412 indentation += indentation_amount;
413 make_command_string_internal (while_command->action);
414 indentation -= indentation_amount;
415 semicolon ();
416 newline ("done");
417}
418
419static void
420print_if_command (if_command)
421 IF_COM *if_command;
422{
423 cprintf ("if ");
424 skip_this_indent++;
425 make_command_string_internal (if_command->test);
426 semicolon ();
427 cprintf (" then\n");
428 indentation += indentation_amount;
429 make_command_string_internal (if_command->true_case);
430 indentation -= indentation_amount;
431
432 if (if_command->false_case)
433 {
434 semicolon ();
435 newline ("else\n");
436 indentation += indentation_amount;
437 make_command_string_internal (if_command->false_case);
438 indentation -= indentation_amount;
439 }
440 semicolon ();
441 newline ("fi");
442}
443
444void
445print_simple_command (simple_command)
446 SIMPLE_COM *simple_command;
447{
448 command_print_word_list (simple_command->words, " ");
449
450 if (simple_command->redirects)
451 {
452 cprintf (" ");
453 print_redirection_list (simple_command->redirects);
454 }
455}
456
457static void
458print_redirection_list (redirects)
459 REDIRECT *redirects;
460{
461 while (redirects)
462 {
463 print_redirection (redirects);
464 redirects = redirects->next;
465 if (redirects)
466 cprintf (" ");
467 }
468}
469
470static void
471print_redirection (redirect)
472 REDIRECT *redirect;
473{
474 int kill_leading = 0;
475 int redirector = redirect->redirector;
476 WORD_DESC *redirectee = redirect->redirectee.filename;
477 int redir_fd = redirect->redirectee.dest;
478
479 switch (redirect->instruction)
480 {
481 case r_output_direction:
482 if (redirector != 1)
483 cprintf ("%d", redirector);
484 cprintf (">%s", redirectee->word);
485 break;
486
487 case r_input_direction:
488 if (redirector != 0)
489 cprintf ("%d", redirector);
490 cprintf ("<%s", redirectee->word);
491 break;
492
493 case r_inputa_direction: /* Redirection created by the shell. */
494 cprintf ("&");
495 break;
496
497 case r_appending_to:
498 if (redirector != 1)
499 cprintf ("%d", redirector);
500 cprintf (">>%s", redirectee->word);
501 break;
502
503 case r_deblank_reading_until:
504 kill_leading++;
505 /* ... */
506 case r_reading_until:
507 if (redirector != 0)
508 cprintf ("%d", redirector);
509 /* If the here document delimiter is quoted, single-quote it. */
ccc6cda3 510 if (redirect->redirectee.filename->flags & W_QUOTED)
726f6388
JA
511 {
512 char *x;
513 x = single_quote (redirect->here_doc_eof);
514 cprintf ("<<%s%s\n", kill_leading? "-" : "", x);
515 free (x);
516 }
517 else
518 cprintf ("<<%s%s\n", kill_leading? "-" : "", redirect->here_doc_eof);
519 cprintf ("%s%s",
520 redirect->redirectee.filename->word, redirect->here_doc_eof);
521 break;
522
523 case r_duplicating_input:
524 cprintf ("%d<&%d", redirector, redir_fd);
525 break;
526
527 case r_duplicating_output:
528 cprintf ("%d>&%d", redirector, redir_fd);
529 break;
530
531 case r_duplicating_input_word:
532 cprintf ("%d<&%s", redirector, redirectee->word);
533 break;
534
535 case r_duplicating_output_word:
536 cprintf ("%d>&%s", redirector, redirectee->word);
537 break;
538
539 case r_close_this:
540 cprintf ("%d>&-", redirector);
541 break;
542
543 case r_err_and_out:
544 cprintf (">&%s", redirectee->word);
545 break;
546
547 case r_input_output:
548 if (redirector != 1)
549 cprintf ("%d", redirector);
550 cprintf ("<>%s", redirectee->word);
551 break;
552
553 case r_output_force:
554 if (redirector != 1)
555 cprintf ("%d", redirector);
556 cprintf (">|%s", redirectee->word);
557 break;
558 }
559}
560
561static void
562reset_locals ()
563{
564 inside_function_def = 0;
565 indentation = 0;
566}
567
568static void
569print_function_def (func)
570 FUNCTION_DEF *func;
571{
572 cprintf ("function %s () \n", func->name->word);
573 add_unwind_protect (reset_locals, 0);
574
575 indent (indentation);
576 cprintf ("{ \n");
577
578 inside_function_def++;
579 indentation += indentation_amount;
580
ccc6cda3
JA
581 make_command_string_internal (func->command->type == cm_group
582 ? func->command->value.Group->command
583 : func->command);
584
726f6388
JA
585 remove_unwind_protect ();
586 indentation -= indentation_amount;
587 inside_function_def--;
588
589 newline ("}");
590}
591
592/* Return the string representation of the named function.
593 NAME is the name of the function.
594 COMMAND is the function body. It should be a GROUP_COM.
595 MULTI_LINE is non-zero to pretty-print, or zero for all on one line.
596 */
597char *
598named_function_string (name, command, multi_line)
599 char *name;
600 COMMAND *command;
601 int multi_line;
602{
603 char *result;
ccc6cda3 604 int old_indent, old_amount;
726f6388 605
ccc6cda3
JA
606 old_indent = indentation;
607 old_amount = indentation_amount;
726f6388
JA
608 command_string_index = 0;
609
610 if (name && *name)
611 cprintf ("%s ", name);
612
613 cprintf ("() ");
614
ccc6cda3 615 if (multi_line == 0)
726f6388
JA
616 {
617 indentation = 1;
618 indentation_amount = 0;
619 }
620 else
621 {
622 cprintf ("\n");
623 indentation += indentation_amount;
624 }
625
626 inside_function_def++;
627
ccc6cda3 628 cprintf (multi_line ? "{ \n" : "{ ");
726f6388 629
ccc6cda3
JA
630 make_command_string_internal (command->type == cm_group
631 ? command->value.Group->command
632 : command);
726f6388
JA
633
634 indentation = old_indent;
635 indentation_amount = old_amount;
636 inside_function_def--;
637
638 newline ("}");
639
640 result = the_printed_command;
641
642 if (!multi_line)
643 {
644#if 0
645 register int i;
646 for (i = 0; result[i]; i++)
647 if (result[i] == '\n')
648 {
649 strcpy (result + i, result + i + 1);
650 --i;
651 }
652#else
653 if (result[2] == '\n') /* XXX -- experimental */
654 strcpy (result + 2, result + 3);
655#endif
656 }
657
658 return (result);
659}
660
661static void
662newline (string)
663 char *string;
664{
665 cprintf ("\n");
666 indent (indentation);
667 if (string && *string)
668 cprintf ("%s", string);
669}
670
ccc6cda3
JA
671static char *indentation_string;
672static int indentation_size;
673
726f6388
JA
674static void
675indent (amount)
676 int amount;
677{
ccc6cda3
JA
678 register int i;
679
680 RESIZE_MALLOCED_BUFFER (indentation_string, 0, amount, indentation_size, 16);
681
682 for (i = 0; amount > 0; amount--)
683 indentation_string[i++] = ' ';
684 indentation_string[i] = '\0';
685 cprintf (indentation_string);
726f6388
JA
686}
687
688static void
689semicolon ()
690{
691 if (command_string_index > 0 && the_printed_command[command_string_index - 1] == '&')
692 return;
693 cprintf (";");
694}
695
ccc6cda3 696#if !defined (USE_VARARGS)
726f6388
JA
697/* How to make the string. */
698static void
699cprintf (format, arg1, arg2)
700 char *format, *arg1, *arg2;
701{
702 register char *s;
703 char char_arg[2], *argp, *args[2];
704 int arg_len, c, arg_index;
705
706 args[arg_index = 0] = arg1;
707 args[1] = arg2;
708
709 arg_len = strlen (format);
710 the_printed_command_resize (arg_len + 1);
711
712 char_arg[1] = '\0';
713 s = format;
714 while (s && *s)
715 {
716 int free_argp = 0;
717 c = *s++;
718 if (c != '%' || !*s)
719 {
720 argp = s;
721 arg_len = 1;
722 }
723 else
724 {
725 c = *s++;
726 switch (c)
727 {
728 case '%':
729 char_arg[0] = c;
730 argp = char_arg;
731 arg_len = 1;
732 break;
733
734 case 's':
735 argp = (char *)args[arg_index++];
736 arg_len = strlen (argp);
737 break;
738
739 case 'd':
740 argp = itos (pointer_to_int (args[arg_index]));
741 arg_index++;
742 arg_len = strlen (argp);
743 free_argp = 1;
744 break;
745
746 case 'c':
747 char_arg[0] = pointer_to_int (args[arg_index]);
748 arg_index++;
749 argp = char_arg;
750 arg_len = 1;
751 break;
752
753 default:
754 programming_error ("cprintf: bad `%%' argument (%c)", c);
755 }
756 }
757 if (argp)
758 {
759 the_printed_command_resize (arg_len + 1);
760 FASTCOPY (argp, the_printed_command + command_string_index, arg_len);
761 command_string_index += arg_len;
762 if (free_argp)
763 free (argp);
764 }
765 }
766
767 the_printed_command[command_string_index] = '\0';
768}
769
770#else /* We have support for varargs. */
771
772/* How to make the string. */
773static void
ccc6cda3
JA
774#if defined (PREFER_STDARG)
775cprintf (char *control, ...)
776#else
777cprintf (control, va_alist)
778 char *control;
726f6388 779 va_dcl
ccc6cda3 780#endif
726f6388
JA
781{
782 register char *s;
ccc6cda3 783 char char_arg[2], *argp;
726f6388
JA
784 int digit_arg, arg_len, c;
785 va_list args;
786
ccc6cda3
JA
787#if defined (PREFER_STDARG)
788 va_start (args, control);
789#else
726f6388 790 va_start (args);
ccc6cda3 791#endif
726f6388
JA
792
793 arg_len = strlen (control);
794 the_printed_command_resize (arg_len + 1);
795
796 char_arg[1] = '\0';
797 s = control;
798 while (s && *s)
799 {
ccc6cda3
JA
800 int free_argp;
801 free_argp = 0;
726f6388 802 c = *s++;
ccc6cda3 803 argp = (char *)NULL;
726f6388
JA
804 if (c != '%' || !*s)
805 {
806 argp = s - 1;
807 arg_len = 1;
808 }
809 else
810 {
811 c = *s++;
812 switch (c)
813 {
814 case '%':
815 char_arg[0] = c;
816 argp = char_arg;
817 arg_len = 1;
818 break;
819
820 case 's':
821 argp = va_arg (args, char *);
822 arg_len = strlen (argp);
823 break;
824
825 case 'd':
826 digit_arg = va_arg (args, int);
827 argp = itos (digit_arg);
828 arg_len = strlen (argp);
829 free_argp = 1;
830 break;
831
832 case 'c':
833 char_arg[0] = va_arg (args, int);
834 argp = char_arg;
835 arg_len = 1;
836 break;
837
838 default:
839 programming_error ("cprintf: bad `%%' argument (%c)", c);
ccc6cda3 840 /*NOTREACHED*/
726f6388
JA
841 }
842 }
843
ccc6cda3 844 if (argp && arg_len)
726f6388
JA
845 {
846 the_printed_command_resize (arg_len + 1);
847 FASTCOPY (argp, the_printed_command + command_string_index, arg_len);
848 command_string_index += arg_len;
849 if (free_argp)
850 free (argp);
851 }
852 }
853
854 the_printed_command[command_string_index] = '\0';
855}
856#endif /* HAVE_VARARGS_H */
857
858/* Ensure that there is enough space to stuff LENGTH characters into
859 THE_PRINTED_COMMAND. */
860static void
861the_printed_command_resize (length)
862 int length;
863{
864 if (!the_printed_command)
865 {
866 the_printed_command_size = length + 1;
867 the_printed_command = xmalloc (the_printed_command_size);
868 command_string_index = 0;
869 }
870 else if ((command_string_index + length) >= the_printed_command_size)
871 {
872 int new;
873 new = command_string_index + length + 1;
874 new = new + 2 * PRINTED_COMMAND_GROW_SIZE - 1;
875 new -= new % PRINTED_COMMAND_GROW_SIZE;
876 the_printed_command_size = new;
877 the_printed_command = xrealloc (the_printed_command, the_printed_command_size);
878 }
879}
ccc6cda3
JA
880
881#if defined (HAVE_VFPRINTF)
882
883static void
884xprintf (va_alist)
885 va_dcl
886{
887 va_list args;
888 char *format;
889
890 va_start (args);
891 format = va_arg (args, char *);
892 vfprintf (stdout, format, args);
893 va_end (args);
894}
895
896#else
897
898static void
899xprintf (format, arg1, arg2, arg3, arg4, arg5)
900 char *format;
901{
902 printf (format, arg1, arg2, arg3, arg4, arg5);
903}
904
905#endif /* !HAVE_VFPRINTF */