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