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