blob: 642d3cd9d811d9990824727ad804e80e84197a6f [file] [log] [blame]
Jari Aalto726f6381996-08-26 18:22:31 +00001/* print_command -- A way to make readable commands from a command tree. */
2/* Copyright (C) 1989 Free Software Foundation, Inc.
3
4This file is part of GNU Bash, the Bourne Again SHell.
5
6Bash is free software; you can redistribute it and/or modify it under
7the terms of the GNU General Public License as published by the Free
8Software Foundation; either version 1, or (at your option) any later
9version.
10
11Bash is distributed in the hope that it will be useful, but WITHOUT ANY
12WARRANTY; without even the implied warranty of MERCHANTABILITY or
13FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14for more details.
15
16You should have received a copy of the GNU General Public License along
17with Bash; see the file COPYING. If not, write to the Free Software
18Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
Jari Aaltoccc6cda1996-12-23 17:02:34 +000020#include "config.h"
21
Jari Aalto726f6381996-08-26 18:22:31 +000022#include <stdio.h>
23
Jari Aaltoccc6cda1996-12-23 17:02:34 +000024#if defined (HAVE_UNISTD_H)
25# include <unistd.h>
Jari Aalto726f6381996-08-26 18:22:31 +000026#endif
27
Jari Aaltoccc6cda1996-12-23 17:02:34 +000028#if defined (PREFER_STDARG)
29# include <stdarg.h>
30#else
31# if defined (PREFER_VARARGS)
32# include <varargs.h>
33# endif
34#endif
35
36#include "bashansi.h"
Jari Aalto726f6381996-08-26 18:22:31 +000037
38#include "shell.h"
Jari Aaltod166f041997-06-05 14:59:13 +000039#include <y.tab.h> /* use <...> so we pick it up from the build directory */
Jari Aalto726f6381996-08-26 18:22:31 +000040#include "stdc.h"
41#include "builtins/common.h"
42
Jari Aaltoccc6cda1996-12-23 17:02:34 +000043#if !defined (PRINTF_DECLARED)
Jari Aalto726f6381996-08-26 18:22:31 +000044extern int printf __P((const char *, ...)); /* Yuck. Double yuck. */
45#endif
46
Jari Aaltoccc6cda1996-12-23 17:02:34 +000047static int indentation;
Jari Aalto726f6381996-08-26 18:22:31 +000048static int indentation_amount = 4;
49
Jari Aaltod166f041997-06-05 14:59:13 +000050#if defined (PREFER_STDARG)
Jari Aaltoccc6cda1996-12-23 17:02:34 +000051static void cprintf __P((char *, ...));
Jari Aaltod166f041997-06-05 14:59:13 +000052#else
53static void cprintf ();
54#endif
Jari Aaltoccc6cda1996-12-23 17:02:34 +000055
56static void newline (), indent (), the_printed_command_resize ();
Jari Aalto726f6381996-08-26 18:22:31 +000057static void semicolon ();
Jari Aaltoccc6cda1996-12-23 17:02:34 +000058static void xprintf ();
Jari Aalto726f6381996-08-26 18:22:31 +000059
60static void make_command_string_internal ();
61static void command_print_word_list ();
62static void print_case_clauses ();
63static void print_redirection_list ();
64static void print_redirection ();
65
66static void print_for_command ();
67#if defined (SELECT_COMMAND)
68static void print_select_command ();
69#endif
70static void print_group_command ();
71static void print_case_command ();
72static void print_while_command ();
73static void print_until_command ();
74static void print_until_or_while ();
75static void print_if_command ();
76static void print_function_def ();
77
Jari Aaltod166f041997-06-05 14:59:13 +000078#define PRINTED_COMMAND_INITIAL_SIZE 64
79#define PRINTED_COMMAND_GROW_SIZE 128
Jari Aalto726f6381996-08-26 18:22:31 +000080
81char *the_printed_command = (char *)NULL;
82int the_printed_command_size = 0;
83int command_string_index = 0;
84
85/* Non-zero means the stuff being printed is inside of a function def. */
Jari Aaltoccc6cda1996-12-23 17:02:34 +000086static int inside_function_def;
87static int skip_this_indent;
Jari Aaltod166f041997-06-05 14:59:13 +000088static int was_heredoc;
Jari Aalto726f6381996-08-26 18:22:31 +000089
90/* The depth of the group commands that we are currently printing. This
91 includes the group command that is a function body. */
Jari Aaltoccc6cda1996-12-23 17:02:34 +000092static int group_command_nesting;
Jari Aalto726f6381996-08-26 18:22:31 +000093
94/* Print COMMAND (a command tree) on standard output. */
95void
96print_command (command)
97 COMMAND *command;
98{
99 command_string_index = 0;
100 printf ("%s", make_command_string (command));
101}
102
103/* Make a string which is the printed representation of the command
104 tree in COMMAND. We return this string. However, the string is
105 not consed, so you have to do that yourself if you want it to
106 remain around. */
107char *
108make_command_string (command)
109 COMMAND *command;
110{
Jari Aaltod166f041997-06-05 14:59:13 +0000111 command_string_index = was_heredoc = 0;
Jari Aalto726f6381996-08-26 18:22:31 +0000112 make_command_string_internal (command);
113 return (the_printed_command);
114}
115
116/* The internal function. This is the real workhorse. */
117static void
118make_command_string_internal (command)
119 COMMAND *command;
120{
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000121 if (command == 0)
Jari Aalto726f6381996-08-26 18:22:31 +0000122 cprintf ("");
123 else
124 {
125 if (skip_this_indent)
126 skip_this_indent--;
127 else
128 indent (indentation);
129
130 if (command->flags & CMD_WANT_SUBSHELL)
131 cprintf ("( ");
132
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000133 if (command->flags & CMD_TIME_PIPELINE)
Jari Aaltod166f041997-06-05 14:59:13 +0000134 {
135 cprintf ("time ");
136 if (command->flags & CMD_TIME_POSIX)
137 cprintf ("-p ");
138 }
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000139
Jari Aalto726f6381996-08-26 18:22:31 +0000140 if (command->flags & CMD_INVERT_RETURN)
141 cprintf ("! ");
142
143 switch (command->type)
144 {
145 case cm_for:
146 print_for_command (command->value.For);
147 break;
148
149#if defined (SELECT_COMMAND)
150 case cm_select:
151 print_select_command (command->value.Select);
152 break;
153#endif
154
155 case cm_case:
156 print_case_command (command->value.Case);
157 break;
158
159 case cm_while:
160 print_while_command (command->value.While);
161 break;
162
163 case cm_until:
164 print_until_command (command->value.While);
165 break;
166
167 case cm_if:
168 print_if_command (command->value.If);
169 break;
170
171 case cm_simple:
172 print_simple_command (command->value.Simple);
173 break;
174
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000175 case cm_connection:
Jari Aalto726f6381996-08-26 18:22:31 +0000176
177 skip_this_indent++;
178 make_command_string_internal (command->value.Connection->first);
179
180 switch (command->value.Connection->connector)
181 {
182 case '&':
183 case '|':
184 {
185 char c = command->value.Connection->connector;
186 cprintf (" %c", c);
187 if (c != '&' || command->value.Connection->second)
188 {
189 cprintf (" ");
190 skip_this_indent++;
191 }
192 }
193 break;
194
195 case AND_AND:
196 cprintf (" && ");
197 if (command->value.Connection->second)
198 skip_this_indent++;
199 break;
200
201 case OR_OR:
202 cprintf (" || ");
203 if (command->value.Connection->second)
204 skip_this_indent++;
205 break;
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000206
Jari Aalto726f6381996-08-26 18:22:31 +0000207 case ';':
Jari Aaltod166f041997-06-05 14:59:13 +0000208 if (was_heredoc == 0)
209 cprintf (";");
210 else
211 was_heredoc = 0;
Jari Aalto726f6381996-08-26 18:22:31 +0000212
213 if (inside_function_def)
214 cprintf ("\n");
215 else
216 {
217 cprintf (" ");
218 if (command->value.Connection->second)
219 skip_this_indent++;
220 }
221 break;
222
223 default:
224 cprintf ("print_command: bad connector `%d'",
225 command->value.Connection->connector);
226 break;
227 }
228
229 make_command_string_internal (command->value.Connection->second);
230 break;
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000231
Jari Aalto726f6381996-08-26 18:22:31 +0000232 case cm_function_def:
233 print_function_def (command->value.Function_def);
234 break;
235
236 case cm_group:
237 print_group_command (command->value.Group);
238 break;
239
240 default:
241 programming_error ("print_command: bad command type `%d'", command->type);
242 break;
243 }
244
245 if (command->flags & CMD_WANT_SUBSHELL)
246 cprintf (" )");
247
248 if (command->redirects)
249 print_redirection_list (command->redirects);
250 }
251}
252
253static void
254_print_word_list (list, separator, pfunc)
255 WORD_LIST *list;
256 char *separator;
257 VFunction *pfunc;
258{
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000259 WORD_LIST *w;
260
261 for (w = list; w; w = w->next)
262 (*pfunc) ("%s%s", w->word->word, w->next ? separator : "");
Jari Aalto726f6381996-08-26 18:22:31 +0000263}
264
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000265void
266print_word_list (list, separator)
Jari Aalto726f6381996-08-26 18:22:31 +0000267 WORD_LIST *list;
268 char *separator;
269{
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000270 _print_word_list (list, separator, xprintf);
271}
272
273/* A function to print the words of a simple command when set -x is on. */
274void
275xtrace_print_word_list (list)
276 WORD_LIST *list;
277{
278 WORD_LIST *w;
279 char *t;
280
281 fprintf (stderr, "%s", indirection_level_string ());
282 for (w = list; w; w = w->next)
283 {
284 t = w->word->word;
285 if (t == 0 || *t == '\0')
286 fprintf (stderr, "''%s", w->next ? " " : "");
287 else if (contains_shell_metas (t))
288 fprintf (stderr, "'%s'%s", t, w->next ? " " : "");
289 else
290 fprintf (stderr, "%s%s", t, w->next ? " " : "");
291 }
292 fprintf (stderr, "\n");
Jari Aalto726f6381996-08-26 18:22:31 +0000293}
294
295static void
296command_print_word_list (list, separator)
297 WORD_LIST *list;
298 char *separator;
299{
300 _print_word_list (list, separator, cprintf);
301}
302
303static void
304print_for_command (for_command)
305 FOR_COM *for_command;
306{
307 cprintf ("for %s in ", for_command->name->word);
308 command_print_word_list (for_command->map_list, " ");
309 cprintf (";");
310 newline ("do\n");
311 indentation += indentation_amount;
312 make_command_string_internal (for_command->action);
313 semicolon ();
314 indentation -= indentation_amount;
315 newline ("done");
316}
317
318#if defined (SELECT_COMMAND)
319static void
320print_select_command (select_command)
321 SELECT_COM *select_command;
322{
323 cprintf ("select %s in ", select_command->name->word);
324 command_print_word_list (select_command->map_list, " ");
325 cprintf (";");
326 newline ("do\n");
327 indentation += indentation_amount;
328 make_command_string_internal (select_command->action);
329 semicolon ();
330 indentation -= indentation_amount;
331 newline ("done");
332}
333#endif /* SELECT_COMMAND */
334
335static void
336print_group_command (group_command)
337 GROUP_COM *group_command;
338{
339 group_command_nesting++;
340 cprintf ("{ ");
341
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000342 if (inside_function_def == 0)
Jari Aalto726f6381996-08-26 18:22:31 +0000343 skip_this_indent++;
344 else
345 {
346 /* This is a group command { ... } inside of a function
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000347 definition, and should be printed as a multiline group
Jari Aalto726f6381996-08-26 18:22:31 +0000348 command, using the current indentation. */
349 cprintf ("\n");
350 indentation += indentation_amount;
351 }
352
353 make_command_string_internal (group_command->command);
354
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000355 if (inside_function_def)
Jari Aalto726f6381996-08-26 18:22:31 +0000356 {
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000357 cprintf ("\n");
Jari Aalto726f6381996-08-26 18:22:31 +0000358 indentation -= indentation_amount;
359 indent (indentation);
Jari Aalto726f6381996-08-26 18:22:31 +0000360 }
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000361 else
362 {
363 semicolon ();
364 cprintf (" ");
365 }
366
Jari Aalto726f6381996-08-26 18:22:31 +0000367 cprintf ("}");
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000368
Jari Aalto726f6381996-08-26 18:22:31 +0000369 group_command_nesting--;
370}
371
372static void
373print_case_command (case_command)
374 CASE_COM *case_command;
375{
376 cprintf ("case %s in ", case_command->word->word);
377 if (case_command->clauses)
378 print_case_clauses (case_command->clauses);
379 newline ("esac");
380}
381
382static void
383print_case_clauses (clauses)
384 PATTERN_LIST *clauses;
385{
386 indentation += indentation_amount;
387 while (clauses)
388 {
389 newline ("");
390 command_print_word_list (clauses->patterns, " | ");
391 cprintf (")\n");
392 indentation += indentation_amount;
393 make_command_string_internal (clauses->action);
394 indentation -= indentation_amount;
395 newline (";;");
396 clauses = clauses->next;
397 }
398 indentation -= indentation_amount;
399}
400
401static void
402print_while_command (while_command)
403 WHILE_COM *while_command;
404{
405 print_until_or_while (while_command, "while");
406}
407
408static void
409print_until_command (while_command)
410 WHILE_COM *while_command;
411{
412 print_until_or_while (while_command, "until");
413}
414
415static void
416print_until_or_while (while_command, which)
417 WHILE_COM *while_command;
418 char *which;
419{
420 cprintf ("%s ", which);
421 skip_this_indent++;
422 make_command_string_internal (while_command->test);
423 semicolon ();
424 cprintf (" do\n"); /* was newline ("do\n"); */
425 indentation += indentation_amount;
426 make_command_string_internal (while_command->action);
427 indentation -= indentation_amount;
428 semicolon ();
429 newline ("done");
430}
431
432static void
433print_if_command (if_command)
434 IF_COM *if_command;
435{
436 cprintf ("if ");
437 skip_this_indent++;
438 make_command_string_internal (if_command->test);
439 semicolon ();
440 cprintf (" then\n");
441 indentation += indentation_amount;
442 make_command_string_internal (if_command->true_case);
443 indentation -= indentation_amount;
444
445 if (if_command->false_case)
446 {
447 semicolon ();
448 newline ("else\n");
449 indentation += indentation_amount;
450 make_command_string_internal (if_command->false_case);
451 indentation -= indentation_amount;
452 }
453 semicolon ();
454 newline ("fi");
455}
456
457void
458print_simple_command (simple_command)
459 SIMPLE_COM *simple_command;
460{
461 command_print_word_list (simple_command->words, " ");
462
463 if (simple_command->redirects)
464 {
465 cprintf (" ");
466 print_redirection_list (simple_command->redirects);
467 }
468}
469
470static void
471print_redirection_list (redirects)
472 REDIRECT *redirects;
473{
Jari Aaltod166f041997-06-05 14:59:13 +0000474 REDIRECT *heredocs, *hdtail, *newredir;
475
476 heredocs = (REDIRECT *)NULL;
477 hdtail = heredocs;
478
479 was_heredoc = 0;
Jari Aalto726f6381996-08-26 18:22:31 +0000480 while (redirects)
481 {
Jari Aaltod166f041997-06-05 14:59:13 +0000482 /* Defer printing the here documents until we've printed the
483 rest of the redirections. */
484 if (redirects->instruction == r_reading_until || redirects->instruction == r_deblank_reading_until)
485 {
486 newredir = copy_redirect (redirects);
487 newredir->next = (REDIRECT *)NULL;
488 if (heredocs)
489 {
490 hdtail->next = newredir;
491 hdtail = newredir;
492 }
493 else
494 hdtail = heredocs = newredir;
495 }
496 else
497 print_redirection (redirects);
498
Jari Aalto726f6381996-08-26 18:22:31 +0000499 redirects = redirects->next;
500 if (redirects)
501 cprintf (" ");
502 }
Jari Aaltod166f041997-06-05 14:59:13 +0000503
504 /* Now that we've printed all the other redirections (on one line),
505 print the here documents. */
506 if (heredocs)
507 {
508 cprintf (" ");
509 for (hdtail = heredocs; hdtail; hdtail = hdtail->next)
510 {
511 print_redirection (hdtail);
512 cprintf ("\n");
513 }
514 dispose_redirects (heredocs);
515 was_heredoc = 1;
516 }
Jari Aalto726f6381996-08-26 18:22:31 +0000517}
518
519static void
520print_redirection (redirect)
521 REDIRECT *redirect;
522{
Jari Aaltod166f041997-06-05 14:59:13 +0000523 int kill_leading, redirector, redir_fd;
524 WORD_DESC *redirectee;
525
526 kill_leading = 0;
527 redirectee = redirect->redirectee.filename;
528 redirector = redirect->redirector;
529 redir_fd = redirect->redirectee.dest;
Jari Aalto726f6381996-08-26 18:22:31 +0000530
531 switch (redirect->instruction)
532 {
533 case r_output_direction:
534 if (redirector != 1)
535 cprintf ("%d", redirector);
536 cprintf (">%s", redirectee->word);
537 break;
538
539 case r_input_direction:
540 if (redirector != 0)
541 cprintf ("%d", redirector);
542 cprintf ("<%s", redirectee->word);
543 break;
544
545 case r_inputa_direction: /* Redirection created by the shell. */
546 cprintf ("&");
547 break;
548
549 case r_appending_to:
550 if (redirector != 1)
551 cprintf ("%d", redirector);
552 cprintf (">>%s", redirectee->word);
553 break;
554
555 case r_deblank_reading_until:
556 kill_leading++;
557 /* ... */
558 case r_reading_until:
559 if (redirector != 0)
560 cprintf ("%d", redirector);
561 /* If the here document delimiter is quoted, single-quote it. */
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000562 if (redirect->redirectee.filename->flags & W_QUOTED)
Jari Aalto726f6381996-08-26 18:22:31 +0000563 {
564 char *x;
565 x = single_quote (redirect->here_doc_eof);
566 cprintf ("<<%s%s\n", kill_leading? "-" : "", x);
567 free (x);
568 }
569 else
570 cprintf ("<<%s%s\n", kill_leading? "-" : "", redirect->here_doc_eof);
571 cprintf ("%s%s",
572 redirect->redirectee.filename->word, redirect->here_doc_eof);
573 break;
574
575 case r_duplicating_input:
576 cprintf ("%d<&%d", redirector, redir_fd);
577 break;
578
579 case r_duplicating_output:
580 cprintf ("%d>&%d", redirector, redir_fd);
581 break;
582
583 case r_duplicating_input_word:
584 cprintf ("%d<&%s", redirector, redirectee->word);
585 break;
586
587 case r_duplicating_output_word:
588 cprintf ("%d>&%s", redirector, redirectee->word);
589 break;
590
591 case r_close_this:
592 cprintf ("%d>&-", redirector);
593 break;
594
595 case r_err_and_out:
596 cprintf (">&%s", redirectee->word);
597 break;
598
599 case r_input_output:
600 if (redirector != 1)
601 cprintf ("%d", redirector);
602 cprintf ("<>%s", redirectee->word);
603 break;
604
605 case r_output_force:
606 if (redirector != 1)
607 cprintf ("%d", redirector);
608 cprintf (">|%s", redirectee->word);
609 break;
610 }
611}
612
613static void
614reset_locals ()
615{
616 inside_function_def = 0;
617 indentation = 0;
618}
619
620static void
621print_function_def (func)
622 FUNCTION_DEF *func;
623{
624 cprintf ("function %s () \n", func->name->word);
625 add_unwind_protect (reset_locals, 0);
626
627 indent (indentation);
628 cprintf ("{ \n");
629
630 inside_function_def++;
631 indentation += indentation_amount;
632
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000633 make_command_string_internal (func->command->type == cm_group
634 ? func->command->value.Group->command
635 : func->command);
636
Jari Aalto726f6381996-08-26 18:22:31 +0000637 remove_unwind_protect ();
638 indentation -= indentation_amount;
639 inside_function_def--;
640
641 newline ("}");
642}
643
644/* Return the string representation of the named function.
645 NAME is the name of the function.
646 COMMAND is the function body. It should be a GROUP_COM.
647 MULTI_LINE is non-zero to pretty-print, or zero for all on one line.
648 */
649char *
650named_function_string (name, command, multi_line)
651 char *name;
652 COMMAND *command;
653 int multi_line;
654{
655 char *result;
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000656 int old_indent, old_amount;
Jari Aalto726f6381996-08-26 18:22:31 +0000657
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000658 old_indent = indentation;
659 old_amount = indentation_amount;
Jari Aaltod166f041997-06-05 14:59:13 +0000660 command_string_index = was_heredoc = 0;
Jari Aalto726f6381996-08-26 18:22:31 +0000661
662 if (name && *name)
663 cprintf ("%s ", name);
664
665 cprintf ("() ");
666
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000667 if (multi_line == 0)
Jari Aalto726f6381996-08-26 18:22:31 +0000668 {
669 indentation = 1;
670 indentation_amount = 0;
671 }
672 else
673 {
674 cprintf ("\n");
675 indentation += indentation_amount;
676 }
677
678 inside_function_def++;
679
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000680 cprintf (multi_line ? "{ \n" : "{ ");
Jari Aalto726f6381996-08-26 18:22:31 +0000681
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000682 make_command_string_internal (command->type == cm_group
683 ? command->value.Group->command
684 : command);
Jari Aalto726f6381996-08-26 18:22:31 +0000685
686 indentation = old_indent;
687 indentation_amount = old_amount;
688 inside_function_def--;
689
690 newline ("}");
691
692 result = the_printed_command;
693
694 if (!multi_line)
695 {
696#if 0
697 register int i;
698 for (i = 0; result[i]; i++)
699 if (result[i] == '\n')
700 {
701 strcpy (result + i, result + i + 1);
702 --i;
703 }
704#else
705 if (result[2] == '\n') /* XXX -- experimental */
706 strcpy (result + 2, result + 3);
707#endif
708 }
709
710 return (result);
711}
712
713static void
714newline (string)
715 char *string;
716{
717 cprintf ("\n");
718 indent (indentation);
719 if (string && *string)
720 cprintf ("%s", string);
721}
722
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000723static char *indentation_string;
724static int indentation_size;
725
Jari Aalto726f6381996-08-26 18:22:31 +0000726static void
727indent (amount)
728 int amount;
729{
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000730 register int i;
731
732 RESIZE_MALLOCED_BUFFER (indentation_string, 0, amount, indentation_size, 16);
733
734 for (i = 0; amount > 0; amount--)
735 indentation_string[i++] = ' ';
736 indentation_string[i] = '\0';
737 cprintf (indentation_string);
Jari Aalto726f6381996-08-26 18:22:31 +0000738}
739
740static void
741semicolon ()
742{
743 if (command_string_index > 0 && the_printed_command[command_string_index - 1] == '&')
744 return;
745 cprintf (";");
746}
747
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000748#if !defined (USE_VARARGS)
Jari Aalto726f6381996-08-26 18:22:31 +0000749/* How to make the string. */
750static void
751cprintf (format, arg1, arg2)
752 char *format, *arg1, *arg2;
753{
754 register char *s;
755 char char_arg[2], *argp, *args[2];
756 int arg_len, c, arg_index;
757
758 args[arg_index = 0] = arg1;
759 args[1] = arg2;
760
761 arg_len = strlen (format);
762 the_printed_command_resize (arg_len + 1);
763
764 char_arg[1] = '\0';
765 s = format;
766 while (s && *s)
767 {
768 int free_argp = 0;
769 c = *s++;
770 if (c != '%' || !*s)
771 {
772 argp = s;
773 arg_len = 1;
774 }
775 else
776 {
777 c = *s++;
778 switch (c)
779 {
780 case '%':
781 char_arg[0] = c;
782 argp = char_arg;
783 arg_len = 1;
784 break;
785
786 case 's':
787 argp = (char *)args[arg_index++];
788 arg_len = strlen (argp);
789 break;
790
791 case 'd':
792 argp = itos (pointer_to_int (args[arg_index]));
793 arg_index++;
794 arg_len = strlen (argp);
795 free_argp = 1;
796 break;
797
798 case 'c':
799 char_arg[0] = pointer_to_int (args[arg_index]);
800 arg_index++;
801 argp = char_arg;
802 arg_len = 1;
803 break;
804
805 default:
806 programming_error ("cprintf: bad `%%' argument (%c)", c);
807 }
808 }
809 if (argp)
810 {
811 the_printed_command_resize (arg_len + 1);
812 FASTCOPY (argp, the_printed_command + command_string_index, arg_len);
813 command_string_index += arg_len;
814 if (free_argp)
815 free (argp);
816 }
817 }
818
819 the_printed_command[command_string_index] = '\0';
820}
821
822#else /* We have support for varargs. */
823
824/* How to make the string. */
825static void
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000826#if defined (PREFER_STDARG)
827cprintf (char *control, ...)
828#else
829cprintf (control, va_alist)
830 char *control;
Jari Aalto726f6381996-08-26 18:22:31 +0000831 va_dcl
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000832#endif
Jari Aalto726f6381996-08-26 18:22:31 +0000833{
834 register char *s;
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000835 char char_arg[2], *argp;
Jari Aalto726f6381996-08-26 18:22:31 +0000836 int digit_arg, arg_len, c;
837 va_list args;
838
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000839#if defined (PREFER_STDARG)
840 va_start (args, control);
841#else
Jari Aalto726f6381996-08-26 18:22:31 +0000842 va_start (args);
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000843#endif
Jari Aalto726f6381996-08-26 18:22:31 +0000844
845 arg_len = strlen (control);
846 the_printed_command_resize (arg_len + 1);
847
848 char_arg[1] = '\0';
849 s = control;
850 while (s && *s)
851 {
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000852 int free_argp;
853 free_argp = 0;
Jari Aalto726f6381996-08-26 18:22:31 +0000854 c = *s++;
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000855 argp = (char *)NULL;
Jari Aalto726f6381996-08-26 18:22:31 +0000856 if (c != '%' || !*s)
857 {
858 argp = s - 1;
859 arg_len = 1;
860 }
861 else
862 {
863 c = *s++;
864 switch (c)
865 {
866 case '%':
867 char_arg[0] = c;
868 argp = char_arg;
869 arg_len = 1;
870 break;
871
872 case 's':
873 argp = va_arg (args, char *);
874 arg_len = strlen (argp);
875 break;
876
877 case 'd':
878 digit_arg = va_arg (args, int);
879 argp = itos (digit_arg);
880 arg_len = strlen (argp);
881 free_argp = 1;
882 break;
883
884 case 'c':
885 char_arg[0] = va_arg (args, int);
886 argp = char_arg;
887 arg_len = 1;
888 break;
889
890 default:
891 programming_error ("cprintf: bad `%%' argument (%c)", c);
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000892 /*NOTREACHED*/
Jari Aalto726f6381996-08-26 18:22:31 +0000893 }
894 }
895
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000896 if (argp && arg_len)
Jari Aalto726f6381996-08-26 18:22:31 +0000897 {
898 the_printed_command_resize (arg_len + 1);
899 FASTCOPY (argp, the_printed_command + command_string_index, arg_len);
900 command_string_index += arg_len;
901 if (free_argp)
902 free (argp);
903 }
904 }
905
906 the_printed_command[command_string_index] = '\0';
907}
908#endif /* HAVE_VARARGS_H */
909
910/* Ensure that there is enough space to stuff LENGTH characters into
911 THE_PRINTED_COMMAND. */
912static void
913the_printed_command_resize (length)
914 int length;
915{
Jari Aaltod166f041997-06-05 14:59:13 +0000916 if (the_printed_command == 0)
Jari Aalto726f6381996-08-26 18:22:31 +0000917 {
Jari Aaltod166f041997-06-05 14:59:13 +0000918 the_printed_command_size = (length + PRINTED_COMMAND_INITIAL_SIZE - 1) & ~(PRINTED_COMMAND_INITIAL_SIZE - 1);
Jari Aalto726f6381996-08-26 18:22:31 +0000919 the_printed_command = xmalloc (the_printed_command_size);
920 command_string_index = 0;
921 }
922 else if ((command_string_index + length) >= the_printed_command_size)
923 {
924 int new;
925 new = command_string_index + length + 1;
Jari Aaltod166f041997-06-05 14:59:13 +0000926#if 1
927 /* Round up to the next multiple of PRINTED_COMMAND_GROW_SIZE. */
928 new = (new + PRINTED_COMMAND_GROW_SIZE - 1) & ~(PRINTED_COMMAND_GROW_SIZE - 1);
929#else
Jari Aalto726f6381996-08-26 18:22:31 +0000930 new = new + 2 * PRINTED_COMMAND_GROW_SIZE - 1;
931 new -= new % PRINTED_COMMAND_GROW_SIZE;
Jari Aaltod166f041997-06-05 14:59:13 +0000932#endif
Jari Aalto726f6381996-08-26 18:22:31 +0000933 the_printed_command_size = new;
934 the_printed_command = xrealloc (the_printed_command, the_printed_command_size);
935 }
936}
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000937
938#if defined (HAVE_VFPRINTF)
939
940static void
Jari Aaltod166f041997-06-05 14:59:13 +0000941#if defined (PREFER_STDARG)
942xprintf (const char *format, ...)
943#else
944xprintf (format, va_alist)
945 const char *format;
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000946 va_dcl
Jari Aaltod166f041997-06-05 14:59:13 +0000947#endif
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000948{
949 va_list args;
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000950
Jari Aaltod166f041997-06-05 14:59:13 +0000951#if defined (PREFER_STDARG)
952 va_start (args, format);
953#else
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000954 va_start (args);
Jari Aaltod166f041997-06-05 14:59:13 +0000955#endif
956
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000957 vfprintf (stdout, format, args);
958 va_end (args);
959}
960
961#else
962
963static void
964xprintf (format, arg1, arg2, arg3, arg4, arg5)
965 char *format;
966{
967 printf (format, arg1, arg2, arg3, arg4, arg5);
968}
969
970#endif /* !HAVE_VFPRINTF */