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