1 /* print_command -- A way to make readable commands from a command tree. */
2 
3 /* Copyright (C) 1989-2020 Free Software Foundation, Inc.
4 
5    This file is part of GNU Bash, the Bourne Again SHell.
6 
7    Bash is free software: you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation, either version 3 of the License, or
10    (at your option) any later version.
11 
12    Bash is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16 
17    You should have received a copy of the GNU General Public License
18    along with Bash.  If not, see <http://www.gnu.org/licenses/>.
19 */
20 
21 #include "config.h"
22 
23 #include <stdio.h>
24 
25 #if defined (HAVE_UNISTD_H)
26 #  ifdef _MINIX
27 #    include <sys/types.h>
28 #  endif
29 #  include <unistd.h>
30 #endif
31 
32 #if defined (PREFER_STDARG)
33 #  include <stdarg.h>
34 #else
35 #  include <varargs.h>
36 #endif
37 
38 #include "bashansi.h"
39 #include "bashintl.h"
40 
41 #define NEED_XTRACE_SET_DECL
42 
43 #include "shell.h"
44 #include "flags.h"
45 #include <y.tab.h>	/* use <...> so we pick it up from the build directory */
46 #include "input.h"
47 
48 #include "shmbutil.h"
49 
50 #include "builtins/common.h"
51 
52 #if !HAVE_DECL_PRINTF
53 extern int printf PARAMS((const char *, ...));	/* Yuck.  Double yuck. */
54 #endif
55 
56 static int indentation;
57 static int indentation_amount = 4;
58 
59 #if defined (PREFER_STDARG)
60 typedef void PFUNC PARAMS((const char *, ...));
61 
62 static void cprintf PARAMS((const char *, ...))  __attribute__((__format__ (printf, 1, 2)));
63 static void xprintf PARAMS((const char *, ...))  __attribute__((__format__ (printf, 1, 2)));
64 #else
65 #define PFUNC VFunction
66 static void cprintf ();
67 static void xprintf ();
68 #endif
69 
70 static void reset_locals PARAMS((void));
71 static void newline PARAMS((char *));
72 static void indent PARAMS((int));
73 static void semicolon PARAMS((void));
74 static void the_printed_command_resize PARAMS((int));
75 
76 static void make_command_string_internal PARAMS((COMMAND *));
77 static void _print_word_list PARAMS((WORD_LIST *, char *, PFUNC *));
78 static void command_print_word_list PARAMS((WORD_LIST *, char *));
79 static void print_case_clauses PARAMS((PATTERN_LIST *));
80 static void print_redirection_list PARAMS((REDIRECT *));
81 static void print_redirection PARAMS((REDIRECT *));
82 static void print_heredoc_header PARAMS((REDIRECT *));
83 static void print_heredoc_body PARAMS((REDIRECT *));
84 static void print_heredocs PARAMS((REDIRECT *));
85 static void print_heredoc_bodies PARAMS((REDIRECT *));
86 static void print_deferred_heredocs PARAMS((const char *));
87 
88 static void print_for_command PARAMS((FOR_COM *));
89 #if defined (ARITH_FOR_COMMAND)
90 static void print_arith_for_command PARAMS((ARITH_FOR_COM *));
91 #endif
92 #if defined (SELECT_COMMAND)
93 static void print_select_command PARAMS((SELECT_COM *));
94 #endif
95 static void print_group_command PARAMS((GROUP_COM *));
96 static void print_case_command PARAMS((CASE_COM *));
97 static void print_while_command PARAMS((WHILE_COM *));
98 static void print_until_command PARAMS((WHILE_COM *));
99 static void print_until_or_while PARAMS((WHILE_COM *, char *));
100 static void print_if_command PARAMS((IF_COM *));
101 #if defined (COND_COMMAND)
102 static void print_cond_node PARAMS((COND_COM *));
103 #endif
104 static void print_function_def PARAMS((FUNCTION_DEF *));
105 
106 #define PRINTED_COMMAND_INITIAL_SIZE 64
107 #define PRINTED_COMMAND_GROW_SIZE 128
108 
109 char *the_printed_command = (char *)NULL;
110 int the_printed_command_size = 0;
111 int command_string_index = 0;
112 
113 int xtrace_fd = -1;
114 FILE *xtrace_fp = 0;
115 
116 #define CHECK_XTRACE_FP	xtrace_fp = (xtrace_fp ? xtrace_fp : stderr)
117 
118 /* shell expansion characters: used in print_redirection_list */
119 #define EXPCHAR(c) ((c) == '{' || (c) == '~' || (c) == '$' || (c) == '`')
120 
121 #define PRINT_DEFERRED_HEREDOCS(x) \
122   do { \
123     if (deferred_heredocs) \
124       print_deferred_heredocs (x); \
125   } while (0)
126 
127 /* Non-zero means the stuff being printed is inside of a function def. */
128 static int inside_function_def;
129 static int skip_this_indent;
130 static int was_heredoc;
131 static int printing_connection;
132 static REDIRECT *deferred_heredocs;
133 
134 /* The depth of the group commands that we are currently printing.  This
135    includes the group command that is a function body. */
136 static int group_command_nesting;
137 
138 /* A buffer to indicate the indirection level (PS4) when set -x is enabled. */
139 static char *indirection_string = 0;
140 static int indirection_stringsiz = 0;
141 
142 /* Print COMMAND (a command tree) on standard output. */
143 void
print_command(command)144 print_command (command)
145      COMMAND *command;
146 {
147   command_string_index = 0;
148   printf ("%s", make_command_string (command));
149 }
150 
151 /* Make a string which is the printed representation of the command
152    tree in COMMAND.  We return this string.  However, the string is
153    not consed, so you have to do that yourself if you want it to
154    remain around. */
155 char *
make_command_string(command)156 make_command_string (command)
157      COMMAND *command;
158 {
159   command_string_index = was_heredoc = 0;
160   deferred_heredocs = 0;
161   make_command_string_internal (command);
162   return (the_printed_command);
163 }
164 
165 /* The internal function.  This is the real workhorse. */
166 static void
make_command_string_internal(command)167 make_command_string_internal (command)
168      COMMAND *command;
169 {
170   char s[3];
171 
172   if (command == 0)
173     cprintf ("");
174   else
175     {
176       if (skip_this_indent)
177 	skip_this_indent--;
178       else
179 	indent (indentation);
180 
181       if (command->flags & CMD_TIME_PIPELINE)
182 	{
183 	  cprintf ("time ");
184 	  if (command->flags & CMD_TIME_POSIX)
185 	    cprintf ("-p ");
186 	}
187 
188       if (command->flags & CMD_INVERT_RETURN)
189 	cprintf ("! ");
190 
191       switch (command->type)
192 	{
193 	case cm_for:
194 	  print_for_command (command->value.For);
195 	  break;
196 
197 #if defined (ARITH_FOR_COMMAND)
198 	case cm_arith_for:
199 	  print_arith_for_command (command->value.ArithFor);
200 	  break;
201 #endif
202 
203 #if defined (SELECT_COMMAND)
204 	case cm_select:
205 	  print_select_command (command->value.Select);
206 	  break;
207 #endif
208 
209 	case cm_case:
210 	  print_case_command (command->value.Case);
211 	  break;
212 
213 	case cm_while:
214 	  print_while_command (command->value.While);
215 	  break;
216 
217 	case cm_until:
218 	  print_until_command (command->value.While);
219 	  break;
220 
221 	case cm_if:
222 	  print_if_command (command->value.If);
223 	  break;
224 
225 #if defined (DPAREN_ARITHMETIC)
226 	case cm_arith:
227 	  print_arith_command (command->value.Arith->exp);
228 	  break;
229 #endif
230 
231 #if defined (COND_COMMAND)
232 	case cm_cond:
233 	  print_cond_command (command->value.Cond);
234 	  break;
235 #endif
236 
237 	case cm_simple:
238 	  print_simple_command (command->value.Simple);
239 	  break;
240 
241 	case cm_connection:
242 
243 	  skip_this_indent++;
244 	  printing_connection++;
245 	  make_command_string_internal (command->value.Connection->first);
246 
247 	  switch (command->value.Connection->connector)
248 	    {
249 	    case '&':
250 	    case '|':
251 	      {
252 		char c = command->value.Connection->connector;
253 
254 		s[0] = ' ';
255 		s[1] = c;
256 		s[2] = '\0';
257 
258 		print_deferred_heredocs (s);
259 
260 		if (c != '&' || command->value.Connection->second)
261 		  {
262 		    cprintf (" ");
263 		    skip_this_indent++;
264 		  }
265 	      }
266 	      break;
267 
268 	    case AND_AND:
269 	      print_deferred_heredocs (" && ");
270 	      if (command->value.Connection->second)
271 		skip_this_indent++;
272 	      break;
273 
274 	    case OR_OR:
275 	      print_deferred_heredocs (" || ");
276 	      if (command->value.Connection->second)
277 		skip_this_indent++;
278 	      break;
279 
280 	    case ';':
281 	      if (deferred_heredocs == 0)
282 		{
283 		  if (was_heredoc == 0)
284 		    cprintf (";");
285 		  else
286 		    was_heredoc = 0;
287 		}
288 	      else
289 		print_deferred_heredocs (inside_function_def ? "" : ";");
290 
291 	      if (inside_function_def)
292 		cprintf ("\n");
293 	      else
294 		{
295 		  cprintf (" ");
296 		  if (command->value.Connection->second)
297 		    skip_this_indent++;
298 		}
299 	      break;
300 
301 	    default:
302 	      cprintf (_("print_command: bad connector `%d'"),
303 		       command->value.Connection->connector);
304 	      break;
305 	    }
306 
307 	  make_command_string_internal (command->value.Connection->second);
308 	  PRINT_DEFERRED_HEREDOCS ("");
309 	  printing_connection--;
310 	  break;
311 
312 	case cm_function_def:
313 	  print_function_def (command->value.Function_def);
314 	  break;
315 
316 	case cm_group:
317 	  print_group_command (command->value.Group);
318 	  break;
319 
320 	case cm_subshell:
321 	  cprintf ("( ");
322 	  skip_this_indent++;
323 	  make_command_string_internal (command->value.Subshell->command);
324 	  PRINT_DEFERRED_HEREDOCS ("");
325 	  cprintf (" )");
326 	  break;
327 
328 	case cm_coproc:
329 	  cprintf ("coproc %s ", command->value.Coproc->name);
330 	  skip_this_indent++;
331 	  make_command_string_internal (command->value.Coproc->command);
332 	  break;
333 
334 	default:
335 	  command_error ("print_command", CMDERR_BADTYPE, command->type, 0);
336 	  break;
337 	}
338 
339 
340       if (command->redirects)
341 	{
342 	  cprintf (" ");
343 	  print_redirection_list (command->redirects);
344 	}
345     }
346 }
347 
348 static void
_print_word_list(list,separator,pfunc)349 _print_word_list (list, separator, pfunc)
350      WORD_LIST *list;
351      char *separator;
352      PFUNC *pfunc;
353 {
354   WORD_LIST *w;
355 
356   for (w = list; w; w = w->next)
357     (*pfunc) ("%s%s", w->word->word, w->next ? separator : "");
358 }
359 
360 void
print_word_list(list,separator)361 print_word_list (list, separator)
362      WORD_LIST *list;
363      char *separator;
364 {
365   _print_word_list (list, separator, xprintf);
366 }
367 
368 void
xtrace_set(fd,fp)369 xtrace_set (fd, fp)
370      int fd;
371      FILE *fp;
372 {
373   if (fd >= 0 && sh_validfd (fd) == 0)
374     {
375       internal_error (_("xtrace_set: %d: invalid file descriptor"), fd);
376       return;
377     }
378   if (fp == 0)
379     {
380       internal_error (_("xtrace_set: NULL file pointer"));
381       return;
382     }
383   if (fd >= 0 && fileno (fp) != fd)
384     internal_warning (_("xtrace fd (%d) != fileno xtrace fp (%d)"), fd, fileno (fp));
385 
386   xtrace_fd = fd;
387   xtrace_fp = fp;
388 }
389 
390 void
xtrace_init()391 xtrace_init ()
392 {
393   xtrace_set (-1, stderr);
394 }
395 
396 void
xtrace_reset()397 xtrace_reset ()
398 {
399   if (xtrace_fd >= 0 && xtrace_fp)
400     {
401       fflush (xtrace_fp);
402       fclose (xtrace_fp);
403     }
404   else if (xtrace_fd >= 0)
405     close (xtrace_fd);
406 
407   xtrace_fd = -1;
408   xtrace_fp = stderr;
409 }
410 
411 void
xtrace_fdchk(fd)412 xtrace_fdchk (fd)
413      int fd;
414 {
415   if (fd == xtrace_fd)
416     xtrace_reset ();
417 }
418 
419 /* Return a string denoting what our indirection level is. */
420 
421 char *
indirection_level_string()422 indirection_level_string ()
423 {
424   register int i, j;
425   char *ps4;
426   char ps4_firstc[MB_LEN_MAX+1];
427   int ps4_firstc_len, ps4_len, ineed, old;
428 
429   ps4 = get_string_value ("PS4");
430   if (indirection_string == 0)
431     indirection_string = xmalloc (indirection_stringsiz = 100);
432   indirection_string[0] = '\0';
433 
434   if (ps4 == 0 || *ps4 == '\0')
435     return (indirection_string);
436 
437   old = change_flag ('x', FLAG_OFF);
438   ps4 = decode_prompt_string (ps4);
439   if (old)
440     change_flag ('x', FLAG_ON);
441 
442   if (ps4 == 0 || *ps4 == '\0')
443     return (indirection_string);
444 
445 #if defined (HANDLE_MULTIBYTE)
446   ps4_len = strnlen (ps4, MB_CUR_MAX);
447   ps4_firstc_len = MBLEN (ps4, ps4_len);
448   if (ps4_firstc_len == 1 || ps4_firstc_len == 0 || ps4_firstc_len < 0)
449     {
450       ps4_firstc[0] = ps4[0];
451       ps4_firstc[ps4_firstc_len = 1] = '\0';
452     }
453   else
454     memcpy (ps4_firstc, ps4, ps4_firstc_len);
455 #else
456   ps4_firstc[0] = ps4[0];
457   ps4_firstc[ps4_firstc_len = 1] = '\0';
458 #endif
459 
460   /* Dynamically resize indirection_string so we have room for everything
461      and we don't have to truncate ps4 */
462   ineed = (ps4_firstc_len * indirection_level) + strlen (ps4);
463   if (ineed > indirection_stringsiz - 1)
464     {
465       indirection_stringsiz = ineed + 1;
466       indirection_string = xrealloc (indirection_string, indirection_stringsiz);
467     }
468 
469   for (i = j = 0; ps4_firstc[0] && j < indirection_level && i < indirection_stringsiz - 1; i += ps4_firstc_len, j++)
470     {
471       if (ps4_firstc_len == 1)
472 	indirection_string[i] = ps4_firstc[0];
473       else
474 	memcpy (indirection_string+i, ps4_firstc, ps4_firstc_len);
475     }
476 
477   for (j = ps4_firstc_len; *ps4 && ps4[j] && i < indirection_stringsiz - 1; i++, j++)
478     indirection_string[i] = ps4[j];
479 
480   indirection_string[i] = '\0';
481   free (ps4);
482   return (indirection_string);
483 }
484 
485 void
xtrace_print_assignment(name,value,assign_list,xflags)486 xtrace_print_assignment (name, value, assign_list, xflags)
487      char *name, *value;
488      int assign_list, xflags;
489 {
490   char *nval;
491 
492   CHECK_XTRACE_FP;
493 
494   if (xflags)
495     fprintf (xtrace_fp, "%s", indirection_level_string ());
496 
497   /* VALUE should not be NULL when this is called. */
498   if (*value == '\0' || assign_list)
499     nval = value;
500   else if (sh_contains_shell_metas (value))
501     nval = sh_single_quote (value);
502   else if (ansic_shouldquote (value))
503     nval = ansic_quote (value, 0, (int *)0);
504   else
505     nval = value;
506 
507   if (assign_list)
508     fprintf (xtrace_fp, "%s=(%s)\n", name, nval);
509   else
510     fprintf (xtrace_fp, "%s=%s\n", name, nval);
511 
512   if (nval != value)
513     FREE (nval);
514 
515   fflush (xtrace_fp);
516 }
517 
518 /* A function to print the words of a simple command when set -x is on.  Also used to
519    print the word list in a for or select command header; in that case, we suppress
520    quoting the words because they haven't been expanded yet.  XTFLAGS&1 means to
521    print $PS4; XTFLAGS&2 means to suppress quoting the words in LIST. */
522 void
xtrace_print_word_list(list,xtflags)523 xtrace_print_word_list (list, xtflags)
524      WORD_LIST *list;
525      int xtflags;
526 {
527   WORD_LIST *w;
528   char *t, *x;
529 
530   CHECK_XTRACE_FP;
531 
532   if (xtflags&1)
533     fprintf (xtrace_fp, "%s", indirection_level_string ());
534 
535   for (w = list; w; w = w->next)
536     {
537       t = w->word->word;
538       if (t == 0 || *t == '\0')
539 	fprintf (xtrace_fp, "''%s", w->next ? " " : "");
540       else if (xtflags & 2)
541 	fprintf (xtrace_fp, "%s%s", t, w->next ? " " : "");
542       else if (sh_contains_shell_metas (t))
543 	{
544 	  x = sh_single_quote (t);
545 	  fprintf (xtrace_fp, "%s%s", x, w->next ? " " : "");
546 	  free (x);
547 	}
548       else if (ansic_shouldquote (t))
549 	{
550 	  x = ansic_quote (t, 0, (int *)0);
551 	  fprintf (xtrace_fp, "%s%s", x, w->next ? " " : "");
552 	  free (x);
553 	}
554       else
555 	fprintf (xtrace_fp, "%s%s", t, w->next ? " " : "");
556     }
557   fprintf (xtrace_fp, "\n");
558   fflush (xtrace_fp);
559 }
560 
561 static void
command_print_word_list(list,separator)562 command_print_word_list (list, separator)
563      WORD_LIST *list;
564      char *separator;
565 {
566   _print_word_list (list, separator, cprintf);
567 }
568 
569 void
print_for_command_head(for_command)570 print_for_command_head (for_command)
571      FOR_COM *for_command;
572 {
573   cprintf ("for %s in ", for_command->name->word);
574   command_print_word_list (for_command->map_list, " ");
575 }
576 
577 void
xtrace_print_for_command_head(for_command)578 xtrace_print_for_command_head (for_command)
579      FOR_COM *for_command;
580 {
581   CHECK_XTRACE_FP;
582   fprintf (xtrace_fp, "%s", indirection_level_string ());
583   fprintf (xtrace_fp, "for %s in ", for_command->name->word);
584   xtrace_print_word_list (for_command->map_list, 2);
585 }
586 
587 static void
print_for_command(for_command)588 print_for_command (for_command)
589      FOR_COM *for_command;
590 {
591   print_for_command_head (for_command);
592   cprintf (";");
593   newline ("do\n");
594 
595   indentation += indentation_amount;
596   make_command_string_internal (for_command->action);
597   PRINT_DEFERRED_HEREDOCS ("");
598   semicolon ();
599   indentation -= indentation_amount;
600 
601   newline ("done");
602 }
603 
604 #if defined (ARITH_FOR_COMMAND)
605 static void
print_arith_for_command(arith_for_command)606 print_arith_for_command (arith_for_command)
607      ARITH_FOR_COM *arith_for_command;
608 {
609   cprintf ("for ((");
610   command_print_word_list (arith_for_command->init, " ");
611   cprintf ("; ");
612   command_print_word_list (arith_for_command->test, " ");
613   cprintf ("; ");
614   command_print_word_list (arith_for_command->step, " ");
615   cprintf ("))");
616   newline ("do\n");
617   indentation += indentation_amount;
618   make_command_string_internal (arith_for_command->action);
619   PRINT_DEFERRED_HEREDOCS ("");
620   semicolon ();
621   indentation -= indentation_amount;
622   newline ("done");
623 }
624 #endif /* ARITH_FOR_COMMAND */
625 
626 #if defined (SELECT_COMMAND)
627 void
print_select_command_head(select_command)628 print_select_command_head (select_command)
629      SELECT_COM *select_command;
630 {
631   cprintf ("select %s in ", select_command->name->word);
632   command_print_word_list (select_command->map_list, " ");
633 }
634 
635 void
xtrace_print_select_command_head(select_command)636 xtrace_print_select_command_head (select_command)
637      SELECT_COM *select_command;
638 {
639   CHECK_XTRACE_FP;
640   fprintf (xtrace_fp, "%s", indirection_level_string ());
641   fprintf (xtrace_fp, "select %s in ", select_command->name->word);
642   xtrace_print_word_list (select_command->map_list, 2);
643 }
644 
645 static void
print_select_command(select_command)646 print_select_command (select_command)
647      SELECT_COM *select_command;
648 {
649   print_select_command_head (select_command);
650 
651   cprintf (";");
652   newline ("do\n");
653   indentation += indentation_amount;
654   make_command_string_internal (select_command->action);
655   PRINT_DEFERRED_HEREDOCS ("");
656   semicolon ();
657   indentation -= indentation_amount;
658   newline ("done");
659 }
660 #endif /* SELECT_COMMAND */
661 
662 static void
print_group_command(group_command)663 print_group_command (group_command)
664      GROUP_COM *group_command;
665 {
666   group_command_nesting++;
667   cprintf ("{ ");
668 
669   if (inside_function_def == 0)
670     skip_this_indent++;
671   else
672     {
673       /* This is a group command { ... } inside of a function
674 	 definition, and should be printed as a multiline group
675 	 command, using the current indentation. */
676       cprintf ("\n");
677       indentation += indentation_amount;
678     }
679 
680   make_command_string_internal (group_command->command);
681   PRINT_DEFERRED_HEREDOCS ("");
682 
683   if (inside_function_def)
684     {
685       cprintf ("\n");
686       indentation -= indentation_amount;
687       indent (indentation);
688     }
689   else
690     {
691       semicolon ();
692       cprintf (" ");
693     }
694 
695   cprintf ("}");
696 
697   group_command_nesting--;
698 }
699 
700 void
print_case_command_head(case_command)701 print_case_command_head (case_command)
702      CASE_COM *case_command;
703 {
704   cprintf ("case %s in ", case_command->word->word);
705 }
706 
707 void
xtrace_print_case_command_head(case_command)708 xtrace_print_case_command_head (case_command)
709      CASE_COM *case_command;
710 {
711   CHECK_XTRACE_FP;
712   fprintf (xtrace_fp, "%s", indirection_level_string ());
713   fprintf (xtrace_fp, "case %s in\n", case_command->word->word);
714 }
715 
716 static void
print_case_command(case_command)717 print_case_command (case_command)
718      CASE_COM *case_command;
719 {
720   print_case_command_head (case_command);
721 
722   if (case_command->clauses)
723     print_case_clauses (case_command->clauses);
724   newline ("esac");
725 }
726 
727 static void
print_case_clauses(clauses)728 print_case_clauses (clauses)
729      PATTERN_LIST *clauses;
730 {
731   indentation += indentation_amount;
732   while (clauses)
733     {
734       newline ("");
735       command_print_word_list (clauses->patterns, " | ");
736       cprintf (")\n");
737       indentation += indentation_amount;
738       make_command_string_internal (clauses->action);
739       indentation -= indentation_amount;
740       PRINT_DEFERRED_HEREDOCS ("");
741       if (clauses->flags & CASEPAT_FALLTHROUGH)
742 	newline (";&");
743       else if (clauses->flags & CASEPAT_TESTNEXT)
744 	newline (";;&");
745       else
746 	newline (";;");
747       clauses = clauses->next;
748     }
749   indentation -= indentation_amount;
750 }
751 
752 static void
print_while_command(while_command)753 print_while_command (while_command)
754      WHILE_COM *while_command;
755 {
756   print_until_or_while (while_command, "while");
757 }
758 
759 static void
print_until_command(while_command)760 print_until_command (while_command)
761      WHILE_COM *while_command;
762 {
763   print_until_or_while (while_command, "until");
764 }
765 
766 static void
print_until_or_while(while_command,which)767 print_until_or_while (while_command, which)
768      WHILE_COM *while_command;
769      char *which;
770 {
771   cprintf ("%s ", which);
772   skip_this_indent++;
773   make_command_string_internal (while_command->test);
774   PRINT_DEFERRED_HEREDOCS ("");
775   semicolon ();
776   cprintf (" do\n");	/* was newline ("do\n"); */
777   indentation += indentation_amount;
778   make_command_string_internal (while_command->action);
779   PRINT_DEFERRED_HEREDOCS ("");
780   indentation -= indentation_amount;
781   semicolon ();
782   newline ("done");
783 }
784 
785 static void
print_if_command(if_command)786 print_if_command (if_command)
787      IF_COM *if_command;
788 {
789   cprintf ("if ");
790   skip_this_indent++;
791   make_command_string_internal (if_command->test);
792   semicolon ();
793   cprintf (" then\n");
794   indentation += indentation_amount;
795   make_command_string_internal (if_command->true_case);
796   PRINT_DEFERRED_HEREDOCS ("");
797   indentation -= indentation_amount;
798 
799   if (if_command->false_case)
800     {
801       semicolon ();
802       newline ("else\n");
803       indentation += indentation_amount;
804       make_command_string_internal (if_command->false_case);
805       PRINT_DEFERRED_HEREDOCS ("");
806       indentation -= indentation_amount;
807     }
808   semicolon ();
809   newline ("fi");
810 }
811 
812 #if defined (DPAREN_ARITHMETIC) || defined (ARITH_FOR_COMMAND)
813 void
print_arith_command(arith_cmd_list)814 print_arith_command (arith_cmd_list)
815      WORD_LIST *arith_cmd_list;
816 {
817   cprintf ("((");
818   command_print_word_list (arith_cmd_list, " ");
819   cprintf ("))");
820 }
821 #endif
822 
823 #if defined (COND_COMMAND)
824 static void
print_cond_node(cond)825 print_cond_node (cond)
826      COND_COM *cond;
827 {
828   if (cond->flags & CMD_INVERT_RETURN)
829     cprintf ("! ");
830 
831   if (cond->type == COND_EXPR)
832     {
833       cprintf ("( ");
834       print_cond_node (cond->left);
835       cprintf (" )");
836     }
837   else if (cond->type == COND_AND)
838     {
839       print_cond_node (cond->left);
840       cprintf (" && ");
841       print_cond_node (cond->right);
842     }
843   else if (cond->type == COND_OR)
844     {
845       print_cond_node (cond->left);
846       cprintf (" || ");
847       print_cond_node (cond->right);
848     }
849   else if (cond->type == COND_UNARY)
850     {
851       cprintf ("%s", cond->op->word);
852       cprintf (" ");
853       print_cond_node (cond->left);
854     }
855   else if (cond->type == COND_BINARY)
856     {
857       print_cond_node (cond->left);
858       cprintf (" ");
859       cprintf ("%s", cond->op->word);
860       cprintf (" ");
861       print_cond_node (cond->right);
862     }
863   else if (cond->type == COND_TERM)
864     {
865       cprintf ("%s", cond->op->word);		/* need to add quoting here */
866     }
867 }
868 
869 void
print_cond_command(cond)870 print_cond_command (cond)
871      COND_COM *cond;
872 {
873   cprintf ("[[ ");
874   print_cond_node (cond);
875   cprintf (" ]]");
876 }
877 
878 #ifdef DEBUG
879 void
debug_print_word_list(s,list,sep)880 debug_print_word_list (s, list, sep)
881      char *s;
882      WORD_LIST *list;
883      char *sep;
884 {
885   WORD_LIST *w;
886 
887   if (s)
888     fprintf (stderr, "%s: ", s);
889   for (w = list; w; w = w->next)
890     fprintf (stderr, "%s%s", w->word->word, w->next ? sep : "");
891   fprintf (stderr, "\n");
892 }
893 
894 void
debug_print_cond_command(cond)895 debug_print_cond_command (cond)
896      COND_COM *cond;
897 {
898   fprintf (stderr, "DEBUG: ");
899   command_string_index = 0;
900   print_cond_command (cond);
901   fprintf (stderr, "%s\n", the_printed_command);
902 }
903 #endif
904 
905 void
xtrace_print_cond_term(type,invert,op,arg1,arg2)906 xtrace_print_cond_term (type, invert, op, arg1, arg2)
907      int type, invert;
908      WORD_DESC *op;
909      char *arg1, *arg2;
910 {
911   CHECK_XTRACE_FP;
912   command_string_index = 0;
913   fprintf (xtrace_fp, "%s", indirection_level_string ());
914   fprintf (xtrace_fp, "[[ ");
915   if (invert)
916     fprintf (xtrace_fp, "! ");
917 
918   if (type == COND_UNARY)
919     {
920       fprintf (xtrace_fp, "%s ", op->word);
921       fprintf (xtrace_fp, "%s", (arg1 && *arg1) ? arg1 : "''");
922     }
923   else if (type == COND_BINARY)
924     {
925       fprintf (xtrace_fp, "%s", (arg1 && *arg1) ? arg1 : "''");
926       fprintf (xtrace_fp, " %s ", op->word);
927       fprintf (xtrace_fp, "%s", (arg2 && *arg2) ? arg2 : "''");
928     }
929 
930   fprintf (xtrace_fp, " ]]\n");
931 
932   fflush (xtrace_fp);
933 }
934 #endif /* COND_COMMAND */
935 
936 #if defined (DPAREN_ARITHMETIC) || defined (ARITH_FOR_COMMAND)
937 /* A function to print the words of an arithmetic command when set -x is on. */
938 void
xtrace_print_arith_cmd(list)939 xtrace_print_arith_cmd (list)
940      WORD_LIST *list;
941 {
942   WORD_LIST *w;
943 
944   CHECK_XTRACE_FP;
945   fprintf (xtrace_fp, "%s", indirection_level_string ());
946   fprintf (xtrace_fp, "(( ");
947   for (w = list; w; w = w->next)
948     fprintf (xtrace_fp, "%s%s", w->word->word, w->next ? " " : "");
949   fprintf (xtrace_fp, " ))\n");
950 
951   fflush (xtrace_fp);
952 }
953 #endif
954 
955 void
print_simple_command(simple_command)956 print_simple_command (simple_command)
957      SIMPLE_COM *simple_command;
958 {
959   command_print_word_list (simple_command->words, " ");
960 
961   if (simple_command->redirects)
962     {
963       cprintf (" ");
964       print_redirection_list (simple_command->redirects);
965     }
966 }
967 
968 static void
print_heredocs(heredocs)969 print_heredocs (heredocs)
970      REDIRECT *heredocs;
971 {
972   REDIRECT *hdtail;
973 
974   cprintf (" ");
975   for (hdtail = heredocs; hdtail; hdtail = hdtail->next)
976     {
977       print_redirection (hdtail);
978       cprintf ("\n");
979     }
980   was_heredoc = 1;
981 }
982 
983 static void
print_heredoc_bodies(heredocs)984 print_heredoc_bodies (heredocs)
985      REDIRECT *heredocs;
986 {
987   REDIRECT *hdtail;
988 
989   cprintf ("\n");
990   for (hdtail = heredocs; hdtail; hdtail = hdtail->next)
991     {
992       print_heredoc_body (hdtail);
993       cprintf ("\n");
994     }
995   was_heredoc = 1;
996 }
997 
998 /* Print heredocs that are attached to the command before the connector
999    represented by CSTRING.  The parsing semantics require us to print the
1000    here-doc delimiters, then the connector (CSTRING), then the here-doc
1001    bodies.  We print the here-doc delimiters in print_redirection_list
1002    and print the connector and the bodies here. We don't print the connector
1003    if it's a `;', but we use it to note not to print an extra space after the
1004    last heredoc body and newline. */
1005 static void
print_deferred_heredocs(cstring)1006 print_deferred_heredocs (cstring)
1007      const char *cstring;
1008 {
1009   /* We now print the heredoc headers in print_redirection_list */
1010   if (cstring && cstring[0] && (cstring[0] != ';' || cstring[1]))
1011     cprintf ("%s", cstring);
1012   if (deferred_heredocs)
1013     {
1014       print_heredoc_bodies (deferred_heredocs);
1015       if (cstring && cstring[0] && (cstring[0] != ';' || cstring[1]))
1016 	cprintf (" ");	/* make sure there's at least one space */
1017       dispose_redirects (deferred_heredocs);
1018       was_heredoc = 1;
1019     }
1020   deferred_heredocs = (REDIRECT *)NULL;
1021 }
1022 
1023 static void
print_redirection_list(redirects)1024 print_redirection_list (redirects)
1025      REDIRECT *redirects;
1026 {
1027   REDIRECT *heredocs, *hdtail, *newredir;
1028   char *rw;
1029 
1030   heredocs = (REDIRECT *)NULL;
1031   hdtail = heredocs;
1032 
1033   was_heredoc = 0;
1034   while (redirects)
1035     {
1036       /* Defer printing the here document bodiess until we've printed the rest of the
1037          redirections, but print the headers in the order they're given.  */
1038       if (redirects->instruction == r_reading_until || redirects->instruction == r_deblank_reading_until)
1039 	{
1040 	  newredir = copy_redirect (redirects);
1041 	  newredir->next = (REDIRECT *)NULL;
1042 
1043 	  print_heredoc_header (newredir);
1044 
1045 	  if (heredocs)
1046 	    {
1047 	      hdtail->next = newredir;
1048 	      hdtail = newredir;
1049 	    }
1050 	  else
1051 	    hdtail = heredocs = newredir;
1052 	}
1053       else if (redirects->instruction == r_duplicating_output_word && (redirects->flags & REDIR_VARASSIGN) == 0 && redirects->redirector.dest == 1)
1054 	{
1055 	  /* Temporarily translate it as the execution code does. */
1056 	  rw = redirects->redirectee.filename->word;
1057 	  if (rw && *rw != '-' && DIGIT (*rw) == 0 && EXPCHAR (*rw) == 0)
1058 	    redirects->instruction = r_err_and_out;
1059 	  print_redirection (redirects);
1060 	  redirects->instruction = r_duplicating_output_word;
1061 	}
1062       else
1063 	print_redirection (redirects);
1064 
1065       redirects = redirects->next;
1066       if (redirects)
1067 	cprintf (" ");
1068     }
1069 
1070   /* Now that we've printed all the other redirections (on one line),
1071      print the here documents.  If we're printing a connection, we wait until
1072      we print the connector symbol, then we print the here document bodies */
1073   if (heredocs && printing_connection)
1074     deferred_heredocs = heredocs;
1075   else if (heredocs)
1076     {
1077       print_heredoc_bodies (heredocs);
1078       dispose_redirects (heredocs);
1079     }
1080 }
1081 
1082 static void
print_heredoc_header(redirect)1083 print_heredoc_header (redirect)
1084      REDIRECT *redirect;
1085 {
1086   int kill_leading;
1087   char *x;
1088 
1089   kill_leading = redirect->instruction == r_deblank_reading_until;
1090 
1091   /* Here doc header */
1092   if (redirect->rflags & REDIR_VARASSIGN)
1093     cprintf ("{%s}", redirect->redirector.filename->word);
1094   else if (redirect->redirector.dest != 0)
1095     cprintf ("%d", redirect->redirector.dest);
1096 
1097   /* If the here document delimiter is quoted, single-quote it. */
1098   if (redirect->redirectee.filename->flags & W_QUOTED)
1099     {
1100       x = sh_single_quote (redirect->here_doc_eof);
1101       cprintf ("<<%s%s", kill_leading ? "-" : "", x);
1102       free (x);
1103     }
1104   else
1105     cprintf ("<<%s%s", kill_leading ? "-" : "", redirect->here_doc_eof);
1106 }
1107 
1108 static void
print_heredoc_body(redirect)1109 print_heredoc_body (redirect)
1110      REDIRECT *redirect;
1111 {
1112   /* Here doc body */
1113   cprintf ("%s%s", redirect->redirectee.filename->word, redirect->here_doc_eof);
1114 }
1115 
1116 static void
print_redirection(redirect)1117 print_redirection (redirect)
1118      REDIRECT *redirect;
1119 {
1120   int redirector, redir_fd;
1121   WORD_DESC *redirectee, *redir_word;
1122 
1123   redirectee = redirect->redirectee.filename;
1124   redir_fd = redirect->redirectee.dest;
1125 
1126   redir_word = redirect->redirector.filename;
1127   redirector = redirect->redirector.dest;
1128 
1129   switch (redirect->instruction)
1130     {
1131     case r_input_direction:
1132       if (redirect->rflags & REDIR_VARASSIGN)
1133 	cprintf ("{%s}", redir_word->word);
1134       else if (redirector != 0)
1135 	cprintf ("%d", redirector);
1136       cprintf ("< %s", redirectee->word);
1137       break;
1138 
1139     case r_output_direction:
1140       if (redirect->rflags & REDIR_VARASSIGN)
1141 	cprintf ("{%s}", redir_word->word);
1142       else if (redirector != 1)
1143 	cprintf ("%d", redirector);
1144       cprintf ("> %s", redirectee->word);
1145       break;
1146 
1147     case r_inputa_direction:	/* Redirection created by the shell. */
1148       cprintf ("&");
1149       break;
1150 
1151     case r_output_force:
1152       if (redirect->rflags & REDIR_VARASSIGN)
1153 	cprintf ("{%s}", redir_word->word);
1154       else if (redirector != 1)
1155 	cprintf ("%d", redirector);
1156       cprintf (">| %s", redirectee->word);
1157       break;
1158 
1159     case r_appending_to:
1160       if (redirect->rflags & REDIR_VARASSIGN)
1161 	cprintf ("{%s}", redir_word->word);
1162       else if (redirector != 1)
1163 	cprintf ("%d", redirector);
1164       cprintf (">> %s", redirectee->word);
1165       break;
1166 
1167     case r_input_output:
1168       if (redirect->rflags & REDIR_VARASSIGN)
1169 	cprintf ("{%s}", redir_word->word);
1170       else if (redirector != 1)
1171 	cprintf ("%d", redirector);
1172       cprintf ("<> %s", redirectee->word);
1173       break;
1174 
1175     case r_deblank_reading_until:
1176     case r_reading_until:
1177       print_heredoc_header (redirect);
1178       cprintf ("\n");
1179       print_heredoc_body (redirect);
1180       break;
1181 
1182     case r_reading_string:
1183       if (redirect->rflags & REDIR_VARASSIGN)
1184 	cprintf ("{%s}", redir_word->word);
1185       else if (redirector != 0)
1186 	cprintf ("%d", redirector);
1187 #if 0
1188       /* Don't need to check whether or not to requote, since original quotes
1189          are still intact.  The only thing that has happened is that $'...'
1190          has been replaced with 'expanded ...'. */
1191       if (ansic_shouldquote (redirect->redirectee.filename->word))
1192 	{
1193 	  char *x;
1194 	  x = ansic_quote (redirect->redirectee.filename->word, 0, (int *)0);
1195 	  cprintf ("<<< %s", x);
1196 	  free (x);
1197 	}
1198       else
1199 #endif
1200 	cprintf ("<<< %s", redirect->redirectee.filename->word);
1201       break;
1202 
1203     case r_duplicating_input:
1204       if (redirect->rflags & REDIR_VARASSIGN)
1205 	cprintf ("{%s}<&%d", redir_word->word, redir_fd);
1206       else
1207 	cprintf ("%d<&%d", redirector, redir_fd);
1208       break;
1209 
1210     case r_duplicating_output:
1211       if (redirect->rflags & REDIR_VARASSIGN)
1212 	cprintf ("{%s}>&%d", redir_word->word, redir_fd);
1213       else
1214 	cprintf ("%d>&%d", redirector, redir_fd);
1215       break;
1216 
1217     case r_duplicating_input_word:
1218       if (redirect->rflags & REDIR_VARASSIGN)
1219 	cprintf ("{%s}<&%s", redir_word->word, redirectee->word);
1220       else
1221 	cprintf ("%d<&%s", redirector, redirectee->word);
1222       break;
1223 
1224     case r_duplicating_output_word:
1225       if (redirect->rflags & REDIR_VARASSIGN)
1226 	cprintf ("{%s}>&%s", redir_word->word, redirectee->word);
1227       else
1228 	cprintf ("%d>&%s", redirector, redirectee->word);
1229       break;
1230 
1231     case r_move_input:
1232       if (redirect->rflags & REDIR_VARASSIGN)
1233 	cprintf ("{%s}<&%d-", redir_word->word, redir_fd);
1234       else
1235 	cprintf ("%d<&%d-", redirector, redir_fd);
1236       break;
1237 
1238     case r_move_output:
1239       if (redirect->rflags & REDIR_VARASSIGN)
1240 	cprintf ("{%s}>&%d-", redir_word->word, redir_fd);
1241       else
1242 	cprintf ("%d>&%d-", redirector, redir_fd);
1243       break;
1244 
1245     case r_move_input_word:
1246       if (redirect->rflags & REDIR_VARASSIGN)
1247 	cprintf ("{%s}<&%s-", redir_word->word, redirectee->word);
1248       else
1249 	cprintf ("%d<&%s-", redirector, redirectee->word);
1250       break;
1251 
1252     case r_move_output_word:
1253       if (redirect->rflags & REDIR_VARASSIGN)
1254 	cprintf ("{%s}>&%s-", redir_word->word, redirectee->word);
1255       else
1256 	cprintf ("%d>&%s-", redirector, redirectee->word);
1257       break;
1258 
1259     case r_close_this:
1260       if (redirect->rflags & REDIR_VARASSIGN)
1261 	cprintf ("{%s}>&-", redir_word->word);
1262       else
1263 	cprintf ("%d>&-", redirector);
1264       break;
1265 
1266     case r_err_and_out:
1267       cprintf ("&> %s", redirectee->word);
1268       break;
1269 
1270     case r_append_err_and_out:
1271       cprintf ("&>> %s", redirectee->word);
1272       break;
1273     }
1274 }
1275 
1276 static void
reset_locals()1277 reset_locals ()
1278 {
1279   inside_function_def = 0;
1280   indentation = 0;
1281   printing_connection = 0;
1282   deferred_heredocs = 0;
1283 }
1284 
1285 static void
print_function_def(func)1286 print_function_def (func)
1287      FUNCTION_DEF *func;
1288 {
1289   COMMAND *cmdcopy;
1290   REDIRECT *func_redirects;
1291 
1292   func_redirects = NULL;
1293   /* When in posix mode, print functions as posix specifies them. */
1294   if (posixly_correct == 0)
1295     cprintf ("function %s () \n", func->name->word);
1296   else
1297     cprintf ("%s () \n", func->name->word);
1298   add_unwind_protect (reset_locals, 0);
1299 
1300   indent (indentation);
1301   cprintf ("{ \n");
1302 
1303   inside_function_def++;
1304   indentation += indentation_amount;
1305 
1306   cmdcopy = copy_command (func->command);
1307   if (cmdcopy->type == cm_group)
1308     {
1309       func_redirects = cmdcopy->redirects;
1310       cmdcopy->redirects = (REDIRECT *)NULL;
1311     }
1312   make_command_string_internal (cmdcopy->type == cm_group
1313 					? cmdcopy->value.Group->command
1314 					: cmdcopy);
1315   PRINT_DEFERRED_HEREDOCS ("");
1316 
1317   remove_unwind_protect ();
1318   indentation -= indentation_amount;
1319   inside_function_def--;
1320 
1321   if (func_redirects)
1322     { /* { */
1323       newline ("} ");
1324       print_redirection_list (func_redirects);
1325       cmdcopy->redirects = func_redirects;
1326     }
1327   else
1328     newline ("}");
1329 
1330   dispose_command (cmdcopy);
1331 }
1332 
1333 /* Return the string representation of the named function.
1334    NAME is the name of the function.
1335    COMMAND is the function body.  It should be a GROUP_COM.
1336    flags&FUNC_MULTILINE is non-zero to pretty-print, or zero for all on one line.
1337    flags&FUNC_EXTERNAL means convert from internal to external form
1338   */
1339 char *
named_function_string(name,command,flags)1340 named_function_string (name, command, flags)
1341      char *name;
1342      COMMAND *command;
1343      int flags;
1344 {
1345   char *result;
1346   int old_indent, old_amount;
1347   COMMAND *cmdcopy;
1348   REDIRECT *func_redirects;
1349 
1350   old_indent = indentation;
1351   old_amount = indentation_amount;
1352   command_string_index = was_heredoc = 0;
1353   deferred_heredocs = 0;
1354 
1355   if (name && *name)
1356     {
1357       if (find_reserved_word (name) >= 0)
1358 	cprintf ("function ");
1359       cprintf ("%s ", name);
1360     }
1361 
1362   cprintf ("() ");
1363 
1364   if ((flags & FUNC_MULTILINE) == 0)
1365     {
1366       indentation = 1;
1367       indentation_amount = 0;
1368     }
1369   else
1370     {
1371       cprintf ("\n");
1372       indentation += indentation_amount;
1373     }
1374 
1375   inside_function_def++;
1376 
1377   cprintf ((flags & FUNC_MULTILINE) ? "{ \n" : "{ ");
1378 
1379   cmdcopy = copy_command (command);
1380   /* Take any redirections specified in the function definition (which should
1381      apply to the function as a whole) and save them for printing later. */
1382   func_redirects = (REDIRECT *)NULL;
1383   if (cmdcopy->type == cm_group)
1384     {
1385       func_redirects = cmdcopy->redirects;
1386       cmdcopy->redirects = (REDIRECT *)NULL;
1387     }
1388   make_command_string_internal (cmdcopy->type == cm_group
1389 					? cmdcopy->value.Group->command
1390 					: cmdcopy);
1391   PRINT_DEFERRED_HEREDOCS ("");
1392 
1393   indentation = old_indent;
1394   indentation_amount = old_amount;
1395   inside_function_def--;
1396 
1397   if (func_redirects)
1398     { /* { */
1399       newline ("} ");
1400       print_redirection_list (func_redirects);
1401       cmdcopy->redirects = func_redirects;
1402     }
1403   else
1404     newline ("}");
1405 
1406   result = the_printed_command;
1407 
1408   if ((flags & FUNC_MULTILINE) == 0)
1409     {
1410 #if 0
1411       register int i;
1412       for (i = 0; result[i]; i++)
1413 	if (result[i] == '\n')
1414 	  {
1415 	    strcpy (result + i, result + i + 1);
1416 	    --i;
1417 	  }
1418 #else
1419       if (result[2] == '\n')	/* XXX -- experimental */
1420 	memmove (result + 2, result + 3, strlen (result) - 2);
1421 #endif
1422     }
1423 
1424   dispose_command (cmdcopy);
1425 
1426   if (flags & FUNC_EXTERNAL)
1427     result = remove_quoted_escapes (result);
1428 
1429   return (result);
1430 }
1431 
1432 static void
newline(string)1433 newline (string)
1434      char *string;
1435 {
1436   cprintf ("\n");
1437   indent (indentation);
1438   if (string && *string)
1439     cprintf ("%s", string);
1440 }
1441 
1442 static char *indentation_string;
1443 static int indentation_size;
1444 
1445 static void
indent(amount)1446 indent (amount)
1447      int amount;
1448 {
1449   register int i;
1450 
1451   RESIZE_MALLOCED_BUFFER (indentation_string, 0, amount, indentation_size, 16);
1452 
1453   for (i = 0; amount > 0; amount--)
1454     indentation_string[i++] = ' ';
1455   indentation_string[i] = '\0';
1456   cprintf ("%s", indentation_string);
1457 }
1458 
1459 static void
semicolon()1460 semicolon ()
1461 {
1462   if (command_string_index > 0 &&
1463        (the_printed_command[command_string_index - 1] == '&' ||
1464 	the_printed_command[command_string_index - 1] == '\n'))
1465     return;
1466   cprintf (";");
1467 }
1468 
1469 /* How to make the string. */
1470 static void
1471 #if defined (PREFER_STDARG)
cprintf(const char * control,...)1472 cprintf (const char *control, ...)
1473 #else
1474 cprintf (control, va_alist)
1475      const char *control;
1476      va_dcl
1477 #endif
1478 {
1479   register const char *s;
1480   char char_arg[2], *argp, intbuf[INT_STRLEN_BOUND (unsigned int) + 1];
1481   int digit_arg, arg_len, c;
1482   va_list args;
1483 
1484   SH_VA_START (args, control);
1485 
1486   arg_len = strlen (control);
1487   the_printed_command_resize (arg_len + 1);
1488 
1489   char_arg[1] = '\0';
1490   s = control;
1491   while (s && *s)
1492     {
1493       c = *s++;
1494       argp = (char *)NULL;
1495       if (c != '%' || !*s)
1496 	{
1497 	  char_arg[0] = c;
1498 	  argp = char_arg;
1499 	  arg_len = 1;
1500 	}
1501       else
1502 	{
1503 	  c = *s++;
1504 	  switch (c)
1505 	    {
1506 	    case '%':
1507 	      char_arg[0] = c;
1508 	      argp = char_arg;
1509 	      arg_len = 1;
1510 	      break;
1511 
1512 	    case 's':
1513 	      argp = va_arg (args, char *);
1514 	      arg_len = strlen (argp);
1515 	      break;
1516 
1517 	    case 'd':
1518 	      /* Represent an out-of-range file descriptor with an out-of-range
1519 		 integer value.  We can do this because the only use of `%d' in
1520 		 the calls to cprintf is to output a file descriptor number for
1521 		 a redirection. */
1522 	      digit_arg = va_arg (args, int);
1523 	      if (digit_arg < 0)
1524 		{
1525 		  sprintf (intbuf, "%u", (unsigned int)-1);
1526 		  argp = intbuf;
1527 		}
1528 	      else
1529 		argp = inttostr (digit_arg, intbuf, sizeof (intbuf));
1530 	      arg_len = strlen (argp);
1531 	      break;
1532 
1533 	    case 'c':
1534 	      char_arg[0] = va_arg (args, int);
1535 	      argp = char_arg;
1536 	      arg_len = 1;
1537 	      break;
1538 
1539 	    default:
1540 	      programming_error (_("cprintf: `%c': invalid format character"), c);
1541 	      /*NOTREACHED*/
1542 	    }
1543 	}
1544 
1545       if (argp && arg_len)
1546 	{
1547 	  the_printed_command_resize (arg_len + 1);
1548 	  FASTCOPY (argp, the_printed_command + command_string_index, arg_len);
1549 	  command_string_index += arg_len;
1550 	}
1551     }
1552 
1553   va_end (args);
1554 
1555   the_printed_command[command_string_index] = '\0';
1556 }
1557 
1558 /* Ensure that there is enough space to stuff LENGTH characters into
1559    THE_PRINTED_COMMAND. */
1560 static void
the_printed_command_resize(length)1561 the_printed_command_resize (length)
1562      int length;
1563 {
1564   if (the_printed_command == 0)
1565     {
1566       the_printed_command_size = (length + PRINTED_COMMAND_INITIAL_SIZE - 1) & ~(PRINTED_COMMAND_INITIAL_SIZE - 1);
1567       the_printed_command = (char *)xmalloc (the_printed_command_size);
1568       command_string_index = 0;
1569     }
1570   else if ((command_string_index + length) >= the_printed_command_size)
1571     {
1572       int new;
1573       new = command_string_index + length + 1;
1574 
1575       /* Round up to the next multiple of PRINTED_COMMAND_GROW_SIZE. */
1576       new = (new + PRINTED_COMMAND_GROW_SIZE - 1) & ~(PRINTED_COMMAND_GROW_SIZE - 1);
1577       the_printed_command_size = new;
1578 
1579       the_printed_command = (char *)xrealloc (the_printed_command, the_printed_command_size);
1580     }
1581 }
1582 
1583 #if defined (HAVE_VPRINTF)
1584 /* ``If vprintf is available, you may assume that vfprintf and vsprintf are
1585      also available.'' */
1586 
1587 static void
1588 #if defined (PREFER_STDARG)
xprintf(const char * format,...)1589 xprintf (const char *format, ...)
1590 #else
1591 xprintf (format, va_alist)
1592      const char *format;
1593      va_dcl
1594 #endif
1595 {
1596   va_list args;
1597 
1598   SH_VA_START (args, format);
1599 
1600   vfprintf (stdout, format, args);
1601   va_end (args);
1602 }
1603 
1604 #else
1605 
1606 static void
xprintf(format,arg1,arg2,arg3,arg4,arg5)1607 xprintf (format, arg1, arg2, arg3, arg4, arg5)
1608      const char *format;
1609 {
1610   printf (format, arg1, arg2, arg3, arg4, arg5);
1611 }
1612 
1613 #endif /* !HAVE_VPRINTF */
1614