Update spec to require automake >= 1.13
[platform/upstream/gawk.git] / profile.c
1 /*
2  * profile.c - gawk bytecode pretty-printer with counts
3  */
4
5 /* 
6  * Copyright (C) 1999-2013 the Free Software Foundation, Inc.
7  * 
8  * This file is part of GAWK, the GNU implementation of the
9  * AWK Programming Language.
10  * 
11  * GAWK is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 3 of the License, or
14  * (at your option) any later version.
15  * 
16  * GAWK is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  * 
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
24  */
25
26 #include "awk.h"
27
28 static void pprint(INSTRUCTION *startp, INSTRUCTION *endp, bool in_for_header);
29 static void pp_parenthesize(NODE *n);
30 static void parenthesize(int type, NODE *left, NODE *right);
31 static char *pp_list(int nargs, const char *paren, const char *delim);
32 static char *pp_group3(const char *s1, const char *s2, const char *s3);
33 static char *pp_concat(int nargs);
34 static bool is_binary(int type);
35 static bool is_scalar(int type);
36 static int prec_level(int type);
37 static void pp_push(int type, char *s, int flag);
38 static NODE *pp_pop(void);
39 static void pp_free(NODE *n);
40 const char *redir2str(int redirtype);
41
42 #define pp_str  vname
43 #define pp_len  sub.nodep.reserved
44 #define pp_next rnode
45
46 #define DONT_FREE 1
47 #define CAN_FREE  2
48
49 static RETSIGTYPE dump_and_exit(int signum) ATTRIBUTE_NORETURN;
50 static RETSIGTYPE just_dump(int signum);
51
52 /* pretty printing related functions and variables */
53
54 static NODE *pp_stack = NULL;
55 static NODE *func_params;       /* function parameters */
56 static FILE *prof_fp;   /* where to send the profile */
57
58 static long indent_level = 0;
59
60
61 #define SPACEOVER       0
62
63 /* set_prof_file --- set the output file for profiling or pretty-printing */
64
65 void
66 set_prof_file(const char *file)
67 {
68         assert(file != NULL);
69         prof_fp = fopen(file, "w");
70         if (prof_fp == NULL) {
71                 warning(_("could not open `%s' for writing: %s"),
72                                 file, strerror(errno));
73                 warning(_("sending profile to standard error"));
74                 prof_fp = stderr;
75         }
76 }
77
78 /* init_profiling_signals --- set up signal handling for gawk --profile */
79
80 void
81 init_profiling_signals()
82 {
83 #ifdef __DJGPP__
84         signal(SIGINT, dump_and_exit);
85         signal(SIGQUIT, just_dump);
86 #else  /* !__DJGPP__ */
87 #ifdef SIGHUP
88         signal(SIGHUP, dump_and_exit);
89 #endif
90 #ifdef SIGUSR1
91         signal(SIGUSR1, just_dump);
92 #endif
93 #endif /* !__DJGPP__ */
94 }
95
96 /* indent --- print out enough tabs */
97
98 static void
99 indent(long count)
100 {
101         int i;
102
103         if (count == 0)
104                 fprintf(prof_fp, "\t");
105         else
106                 fprintf(prof_fp, "%6ld  ", count);
107
108         assert(indent_level >= 0);
109         for (i = 0; i < indent_level; i++)
110                 fprintf(prof_fp, "\t");
111 }
112
113 /* indent_in --- increase the level, with error checking */
114
115 static void
116 indent_in(void)
117 {
118         assert(indent_level >= 0);
119         indent_level++;
120 }
121
122 /* indent_out --- decrease the level, with error checking */
123
124 static void
125 indent_out(void)
126 {
127         indent_level--;
128         assert(indent_level >= 0);
129 }
130
131 /* pp_push --- push a pretty printed string onto the stack */
132
133 static void
134 pp_push(int type, char *s, int flag)
135 {
136         NODE *n;
137         getnode(n);
138         n->pp_str = s;
139         n->pp_len = strlen(s);
140         n->flags = flag;
141         n->type = type;
142         n->pp_next = pp_stack;
143         pp_stack = n;
144 }
145
146 /* pp_pop --- pop a pretty printed string off the stack */
147
148 static NODE *
149 pp_pop()
150 {
151         NODE *n;
152         n = pp_stack;
153         pp_stack = n->pp_next;
154         return n;
155 }
156
157 /* pp_free --- release a pretty printed node */
158
159 static void
160 pp_free(NODE *n)
161 {
162         if ((n->flags & CAN_FREE) != 0)
163                 efree(n->pp_str);
164         freenode(n);
165 }
166
167 /* pprint --- pretty print a program segment */
168
169 static void
170 pprint(INSTRUCTION *startp, INSTRUCTION *endp, bool in_for_header)
171 {
172         INSTRUCTION *pc;
173         NODE *t1;
174         char *str;
175         NODE *t2;
176         INSTRUCTION *ip;
177         NODE *m;
178         char *tmp;
179         int rule;
180         static int rule_count[MAXRULE];
181
182         for (pc = startp; pc != endp; pc = pc->nexti) {
183                 if (pc->source_line > 0)
184                         sourceline = pc->source_line;
185
186                 switch (pc->opcode) {
187                 case Op_rule:
188                         source = pc->source_file;
189                         rule = pc->in_rule;
190
191                         if (rule != Rule) {
192                                 if (! rule_count[rule]++)
193                                         fprintf(prof_fp, _("\t# %s block(s)\n\n"), ruletab[rule]);
194                                 fprintf(prof_fp, "\t%s {\n", ruletab[rule]);
195                                 ip = (pc + 1)->firsti;
196                         } else {
197                                 if (! rule_count[rule]++)
198                                         fprintf(prof_fp, _("\t# Rule(s)\n\n"));
199                                 ip = pc->nexti;
200                                 indent(ip->exec_count);
201                                 if (ip != (pc + 1)->firsti) {           /* non-empty pattern */
202                                         pprint(ip->nexti, (pc + 1)->firsti, false);
203                                         t1 = pp_pop();
204                                         fprintf(prof_fp, "%s {", t1->pp_str);
205                                         pp_free(t1);
206                                         ip = (pc + 1)->firsti;
207
208                                         if (do_profile && ip->exec_count > 0)
209                                                 fprintf(prof_fp, " # %ld", ip->exec_count);
210
211                                         fprintf(prof_fp, "\n");
212                                 } else {
213                                         fprintf(prof_fp, "{\n");
214                                         ip = (pc + 1)->firsti;
215                                 }
216                                 ip = ip->nexti;
217                         }
218                         indent_in();
219                         pprint(ip, (pc + 1)->lasti, false);
220                         indent_out();
221                         fprintf(prof_fp, "\t}\n\n");
222                         pc = (pc + 1)->lasti;
223                         break;
224
225                 case Op_atexit:
226                         break;
227
228                 case Op_stop:
229                         memset(rule_count, 0, MAXRULE * sizeof(int));
230                         break;
231
232                 case Op_push_i:
233                         m = pc->memory;
234                         if (m == Nnull_string)  /* optional return or exit value; don't print 0 or "" */
235                                 pp_push(pc->opcode, m->stptr, DONT_FREE);
236                         else if ((m->flags & NUMBER) != 0)
237                                 pp_push(pc->opcode, pp_number(m), CAN_FREE);
238                         else {
239                                 str = pp_string(m->stptr, m->stlen, '"');
240                                 if ((m->flags & INTLSTR) != 0) {
241                                         char *tmp = str;
242                                         str = pp_group3("_", tmp, "");
243                                         efree(tmp);
244                                 }
245                                 pp_push(pc->opcode, str, CAN_FREE);
246                         }
247                         break;
248
249                 case Op_store_var:
250                         if (pc->initval != NULL)
251                                 pp_push(Op_push_i, pp_node(pc->initval), CAN_FREE);
252                         /* fall through */
253                 case Op_store_sub:
254                 case Op_assign_concat:
255                 case Op_push_lhs:
256                 case Op_push_param:
257                 case Op_push_array:
258                 case Op_push:
259                 case Op_push_arg:
260                         m = pc->memory;
261                         switch (m->type) {
262                         case Node_param_list:
263                                 pp_push(pc->opcode, func_params[m->param_cnt].param, DONT_FREE);
264                                 break;
265
266                         case Node_var:
267                         case Node_var_new:
268                         case Node_var_array:
269                                 if (m->vname != NULL)
270                                         pp_push(pc->opcode, m->vname, DONT_FREE);
271                                 else
272                                         fatal(_("internal error: %s with null vname"),
273                                                         nodetype2str(m->type));
274                                 break;
275
276                         default:
277                                 cant_happen();
278                         }
279
280                         switch (pc->opcode) {           
281                         case Op_store_var:
282                                 t2 = pp_pop(); /* l.h.s. */
283                                 t1 = pp_pop(); /* r.h.s. */
284                                 fprintf(prof_fp, "%s%s%s", t2->pp_str, op2str(pc->opcode), t1->pp_str);
285                                 goto cleanup;
286
287                         case Op_store_sub:
288                                 t1 = pp_pop();  /* array */
289                                 tmp = pp_list(pc->expr_count, op2str(Op_subscript), ", "); /*subscript*/
290                                 t2 = pp_pop(); /* r.h.s. */
291                                 fprintf(prof_fp, "%s%s%s%s", t1->pp_str, tmp,
292                                                                         op2str(pc->opcode), t2->pp_str);
293                                 efree(tmp);
294                                 goto cleanup;
295
296                         case Op_assign_concat:
297                                 t2 = pp_pop(); /* l.h.s. */
298                                 t1 = pp_pop();
299                                 tmp = pp_group3(t2->pp_str, op2str(Op_concat), t1->pp_str);
300                                 fprintf(prof_fp, "%s%s%s", t2->pp_str, op2str(Op_assign), tmp);
301                                 efree(tmp);
302 cleanup:
303                                 pp_free(t2);
304                                 pp_free(t1);
305                                 if (! in_for_header)
306                                         fprintf(prof_fp, "\n");
307                                 break;
308
309                         default:
310                                 break;
311                         }
312                         break;
313
314                 case Op_sub_array:
315                 case Op_subscript_lhs:
316                 case Op_subscript:
317                         tmp = pp_list(pc->sub_count, op2str(pc->opcode), ", ");
318                         t1 = pp_pop();
319                         str = pp_group3(t1->pp_str, tmp, "");
320                         efree(tmp);
321                         pp_free(t1);
322                         pp_push(pc->opcode, str, CAN_FREE);
323                         break;  
324
325                 case Op_and:
326                 case Op_or:
327                         pprint(pc->nexti, pc->target_jmp, in_for_header);
328                         t2 = pp_pop();
329                         t1 = pp_pop();
330                         parenthesize(pc->opcode, t1, t2);
331                         str = pp_group3(t1->pp_str, op2str(pc->opcode), t2->pp_str);
332                         pp_free(t1);
333                         pp_free(t2);
334                         pp_push(pc->opcode, str, CAN_FREE);
335                         pc = pc->target_jmp;
336                         break;
337
338                 case Op_plus_i:
339                 case Op_minus_i:
340                 case Op_times_i:
341                 case Op_exp_i:
342                 case Op_quotient_i:
343                 case Op_mod_i:
344                         m = pc->memory;
345                         t1 = pp_pop();
346                         if (prec_level(pc->opcode) > prec_level(t1->type)
347                                         && is_binary(t1->type))  /* (a - b) * 1 */
348                                 pp_parenthesize(t1);
349                         if ((m->flags & NUMBER) != 0)
350                                 tmp = pp_number(m);
351                         else
352                                 tmp = pp_string(m->stptr, m->stlen, '"');
353                         str = pp_group3(t1->pp_str, op2str(pc->opcode), tmp);
354                         efree(tmp);
355                         pp_free(t1);
356                         pp_push(pc->opcode, str, CAN_FREE);
357                         break;
358
359                 case Op_plus:
360                 case Op_minus:
361                 case Op_times:
362                 case Op_exp:
363                 case Op_quotient:
364                 case Op_mod:
365                 case Op_equal:
366                 case Op_notequal:
367                 case Op_less:
368                 case Op_greater:
369                 case Op_leq:
370                 case Op_geq:
371                         t2 = pp_pop();
372                         t1 = pp_pop();
373                         parenthesize(pc->opcode, t1, t2);
374                         str = pp_group3(t1->pp_str, op2str(pc->opcode), t2->pp_str);
375                         pp_free(t1);
376                         pp_free(t2);
377                         pp_push(pc->opcode, str, CAN_FREE);
378                         break;
379
380                 case Op_preincrement:
381                 case Op_predecrement:
382                 case Op_postincrement:
383                 case Op_postdecrement:
384                         t1 = pp_pop();
385                         if (pc->opcode == Op_preincrement || pc->opcode == Op_predecrement)
386                                 str = pp_group3(op2str(pc->opcode), t1->pp_str, "");
387                         else
388                                 str = pp_group3(t1->pp_str, op2str(pc->opcode), "");
389                         pp_free(t1);
390                         pp_push(pc->opcode, str, CAN_FREE);
391                         break;
392
393                 case Op_field_spec:
394                 case Op_field_spec_lhs:
395                 case Op_unary_minus:
396                 case Op_not:
397                         t1 = pp_pop();
398                         if (is_binary(t1->type))
399                                 pp_parenthesize(t1);
400
401                         /* optypes table (eval.c) includes space after ! */
402                         str = pp_group3(op2str(pc->opcode), t1->pp_str, "");
403                         pp_free(t1);
404                         pp_push(pc->opcode, str, CAN_FREE);
405                         break;
406
407                 case Op_assign:
408                 case Op_assign_plus:
409                 case Op_assign_minus:
410                 case Op_assign_times:
411                 case Op_assign_quotient:
412                 case Op_assign_mod:
413                 case Op_assign_exp:
414                         t2 = pp_pop(); /* l.h.s. */
415                         t1 = pp_pop();
416                         str = pp_group3(t2->pp_str, op2str(pc->opcode), t1->pp_str);
417                         pp_free(t2);
418                         pp_free(t1);
419                         pp_push(pc->opcode, str, CAN_FREE);
420                         break;
421
422                 case Op_store_field:
423                         t1 = pp_pop(); /* field num */
424                         if (is_binary(t1->type))
425                                 pp_parenthesize(t1);
426                         t2 = pp_pop(); /* r.h.s. */
427                         fprintf(prof_fp, "$%s%s%s", t1->pp_str, op2str(pc->opcode), t2->pp_str);
428                         pp_free(t2);
429                         pp_free(t1);
430                         if (! in_for_header)
431                                 fprintf(prof_fp, "\n");
432                         break; 
433
434                 case Op_concat:
435                         str = pp_concat(pc->expr_count);
436                         pp_push(Op_concat, str, CAN_FREE);
437                         break;
438
439                 case Op_K_delete:
440                 {
441                         char *array;
442                         t1 = pp_pop();
443                         array = t1->pp_str;
444                         if (pc->expr_count > 0) {
445                                 char *sub;
446                                 sub = pp_list(pc->expr_count, NULL, pc->expr_count > 1 ? "][" : ", ");
447                                 fprintf(prof_fp, "%s %s[%s]", op2str(Op_K_delete), array, sub);
448                                 efree(sub);
449                         } else                          
450                                 fprintf(prof_fp, "%s %s", op2str(Op_K_delete), array);
451                         if (! in_for_header)
452                                 fprintf(prof_fp, "\n");
453                         pp_free(t1);
454                 }
455                         break;
456
457                 case Op_K_delete_loop:
458                         /* Efficency hack not in effect because of exec_count instruction */
459                         cant_happen();
460                         break;
461                 
462                 case Op_in_array:
463                 {
464                         char *array, *sub;
465                         t1 = pp_pop();
466                         array = t1->pp_str;
467                         if (pc->expr_count > 1) {
468                                 sub = pp_list(pc->expr_count, "()", ", ");
469                                 str = pp_group3(sub, op2str(Op_in_array), array);
470                                 efree(sub);
471                         } else {
472                                 t2 = pp_pop();
473                                 if (prec_level(t2->type) < prec_level(Op_in_array)) {
474                                                 pp_parenthesize(t2);
475                                 }
476                                 sub = t2->pp_str;
477                                 str = pp_group3(sub, op2str(Op_in_array), array);
478                                 pp_free(t2);
479                         }
480                         pp_free(t1);
481                         pp_push(Op_in_array, str, CAN_FREE);
482                 }
483                         break;
484
485                 case Op_var_update:
486                 case Op_var_assign:
487                 case Op_field_assign:
488                 case Op_subscript_assign:
489                 case Op_arrayfor_init:
490                 case Op_arrayfor_incr: 
491                 case Op_arrayfor_final:
492                 case Op_newfile:
493                 case Op_get_record:
494                 case Op_lint:
495                 case Op_jmp:
496                 case Op_jmp_false:
497                 case Op_jmp_true:
498                 case Op_no_op:
499                 case Op_and_final:
500                 case Op_or_final:
501                 case Op_cond_pair:
502                 case Op_after_beginfile:
503                 case Op_after_endfile:
504                         break;
505
506                 case Op_sub_builtin:
507                 {
508                         const char *fname = "sub";
509                         if ((pc->sub_flags & GSUB) != 0)
510                                 fname = "gsub";
511                         else if ((pc->sub_flags & GENSUB) != 0)
512                                 fname = "gensub";
513                         tmp = pp_list(pc->expr_count, "()", ", ");
514                         str = pp_group3(fname, tmp, "");
515                         efree(tmp);
516                         pp_push(Op_sub_builtin, str, CAN_FREE);
517                 }
518                         break;
519
520                 case Op_builtin:
521                 case Op_ext_builtin:
522                 {
523                         const char *fname;
524                         if (pc->opcode == Op_builtin)
525                                 fname = getfname(pc->builtin);
526                         else
527                                 fname = (pc + 1)->func_name;
528                         if (fname != NULL) {
529                                 if (pc->expr_count > 0) {
530                                         tmp = pp_list(pc->expr_count, "()", ", ");
531                                         str = pp_group3(fname, tmp, "");
532                                         efree(tmp);
533                                 } else
534                                         str = pp_group3(fname, "()", "");
535                                 pp_push(Op_builtin, str, CAN_FREE);
536                         } else
537                                 fatal(_("internal error: builtin with null fname"));
538                 }
539                         break;
540
541                 case Op_K_print:
542                 case Op_K_printf:
543                 case Op_K_print_rec:
544                         if (pc->opcode == Op_K_print_rec)
545                                 tmp = pp_group3(" ", op2str(Op_field_spec), "0");
546                         else if (pc->redir_type != 0)
547                                 tmp = pp_list(pc->expr_count, "()", ", ");
548                         else {
549                                 tmp = pp_list(pc->expr_count, "  ", ", ");
550                                 tmp[strlen(tmp) - 1] = '\0';    /* remove trailing space */
551                         }       
552
553                         if (pc->redir_type != 0) {
554                                 t1 = pp_pop();
555                                 if (is_binary(t1->type))
556                                         pp_parenthesize(t1);
557                                 fprintf(prof_fp, "%s%s%s%s", op2str(pc->opcode),
558                                                         tmp, redir2str(pc->redir_type), t1->pp_str);
559                                 pp_free(t1);
560                         } else
561                                 fprintf(prof_fp, "%s%s", op2str(pc->opcode), tmp);
562                         efree(tmp);
563                         if (! in_for_header)
564                                 fprintf(prof_fp, "\n");
565                         break;
566
567                 case Op_push_re:
568                         if (pc->memory->type != Node_regex)
569                                 break;
570                         /* else 
571                                 fall through */
572                 case Op_match_rec:
573                 {
574                         NODE *re = pc->memory->re_exp;
575                         str = pp_string(re->stptr, re->stlen, '/');
576                         pp_push(pc->opcode, str, CAN_FREE);
577                 }
578                         break;
579
580                 case Op_nomatch:
581                 case Op_match:
582                 {
583                         char *restr, *txt;
584                         t1 = pp_pop();
585                         if (is_binary(t1->type))
586                                 pp_parenthesize(t1);
587                         txt = t1->pp_str;
588                         m = pc->memory;
589                         if (m->type == Node_dynregex) {
590                                 restr = txt;
591                                 t2 = pp_pop();
592                                 if (is_binary(t2->type))
593                                         pp_parenthesize(t2);
594                                 txt = t2->pp_str;
595                                 str = pp_group3(txt, op2str(pc->opcode), restr);
596                                 pp_free(t2);
597                         } else {
598                                 NODE *re = m->re_exp;
599                                 restr = pp_string(re->stptr, re->stlen, '/');
600                                 str = pp_group3(txt, op2str(pc->opcode), restr);
601                                 efree(restr);
602                         }
603                         pp_free(t1);
604                         pp_push(pc->opcode, str, CAN_FREE);
605                 }
606                         break;
607
608                 case Op_K_getline:
609                 case Op_K_getline_redir:
610                         if (pc->into_var) {
611                                 t1 = pp_pop();
612                                 tmp = pp_group3(op2str(Op_K_getline), " ", t1->pp_str);
613                                 pp_free(t1);
614                         } else
615                                 tmp = pp_group3(op2str(Op_K_getline), "", "");
616
617                         if (pc->redir_type != 0) {
618                                 int before = (pc->redir_type == redirect_pipein
619                                                         || pc->redir_type == redirect_twoway);
620
621                                 t2 = pp_pop();
622                                 if (is_binary(t2->type))
623                                         pp_parenthesize(t2);
624                                 if (before)
625                                         str = pp_group3(t2->pp_str, redir2str(pc->redir_type), tmp);
626                                 else
627                                         str = pp_group3(tmp, redir2str(pc->redir_type), t2->pp_str);
628                                 efree(tmp);
629                                 pp_free(t2);
630                         } else
631                                 str = tmp;
632                         pp_push(pc->opcode, str, CAN_FREE);
633                         break;
634
635                 case Op_indirect_func_call:
636                 case Op_func_call:
637                 {
638                         char *fname = pc->func_name;
639                         char *pre;
640                         int pcount;
641
642                         if (pc->opcode == Op_indirect_func_call)
643                                 pre = "@";
644                         else
645                                 pre = "";               
646                         pcount = (pc + 1)->expr_count;
647                         if (pcount > 0) {
648                                 tmp = pp_list(pcount, "()", ", ");
649                                 str = pp_group3(pre, fname, tmp);
650                                 efree(tmp);
651                         } else
652                                 str = pp_group3(pre, fname, "()");
653                         if (pc->opcode == Op_indirect_func_call) {
654                                 t1 = pp_pop();  /* indirect var */
655                                 pp_free(t1);
656                         }
657                         pp_push(pc->opcode, str, CAN_FREE);
658                 }
659                         break;
660
661                 case Op_K_continue:
662                 case Op_K_break:
663                 case Op_K_nextfile:
664                 case Op_K_next:
665                         fprintf(prof_fp, "%s\n", op2str(pc->opcode));
666                         break;
667
668                 case Op_K_return:
669                 case Op_K_exit:
670                         t1 = pp_pop();
671                         if (is_binary(t1->type))
672                                 pp_parenthesize(t1);
673                         if (pc->source_line > 0)        /* don't print implicit 'return' at end of function */
674                                 fprintf(prof_fp, "%s %s\n", op2str(pc->opcode), t1->pp_str);
675                         pp_free(t1);
676                         break;
677
678                 case Op_pop:
679                         t1 = pp_pop();
680                         fprintf(prof_fp, "%s", t1->pp_str);
681                         if (! in_for_header)
682                                 fprintf(prof_fp, "\n");
683                         pp_free(t1);
684                         break;
685
686                 case Op_line_range:
687                         ip = pc + 1;
688                         pprint(pc->nexti, ip->condpair_left, false);
689                         pprint(ip->condpair_left->nexti, ip->condpair_right, false);
690                         t2 = pp_pop();
691                         t1 = pp_pop();
692                         str = pp_group3(t1->pp_str, ", ", t2->pp_str);
693                         pp_free(t1);
694                         pp_free(t2);
695                         pp_push(Op_line_range, str, CAN_FREE);
696                         pc = ip->condpair_right;
697                         break;
698
699                 case Op_K_while:
700                         ip = pc + 1;
701                         indent(ip->while_body->exec_count);
702                         fprintf(prof_fp, "%s (", op2str(pc->opcode));
703                         pprint(pc->nexti, ip->while_body, false);
704                         t1 = pp_pop();
705                         fprintf(prof_fp, "%s) {\n", t1->pp_str);
706                         pp_free(t1);
707                         indent_in();
708                         pprint(ip->while_body->nexti, pc->target_break, false);
709                         indent_out();
710                         indent(SPACEOVER);
711                         fprintf(prof_fp, "}\n");
712                         pc = pc->target_break;
713                         break;
714
715                 case Op_K_do:
716                         ip = pc + 1;
717                         indent(pc->nexti->exec_count);
718                         fprintf(prof_fp, "%s {\n", op2str(pc->opcode));
719                         indent_in();
720                         pprint(pc->nexti->nexti, ip->doloop_cond, false);
721                         indent_out();
722                         pprint(ip->doloop_cond, pc->target_break, false);
723                         indent(SPACEOVER);
724                         t1 = pp_pop();
725                         fprintf(prof_fp, "} %s (%s)\n", op2str(Op_K_while), t1->pp_str);
726                         pp_free(t1);
727                         pc = pc->target_break;
728                         break;
729
730                 case Op_K_for:
731                         ip = pc + 1;
732                         indent(ip->forloop_body->exec_count);
733                         fprintf(prof_fp, "%s (", op2str(pc->opcode));   
734                         pprint(pc->nexti, ip->forloop_cond, true);
735                         fprintf(prof_fp, "; ");
736
737                         if (ip->forloop_cond->opcode == Op_no_op &&
738                                         ip->forloop_cond->nexti == ip->forloop_body)
739                                 fprintf(prof_fp, "; ");
740                         else {
741                                 pprint(ip->forloop_cond, ip->forloop_body, true);
742                                 t1 = pp_pop();
743                                 fprintf(prof_fp, "%s; ", t1->pp_str);
744                                 pp_free(t1);
745                         }
746
747                         pprint(pc->target_continue, pc->target_break, true);
748                         fprintf(prof_fp, ") {\n");
749                         indent_in();
750                         pprint(ip->forloop_body->nexti, pc->target_continue, false);
751                         indent_out();
752                         indent(SPACEOVER);
753                         fprintf(prof_fp, "}\n");
754                         pc = pc->target_break;
755                         break;
756
757                 case Op_K_arrayfor:
758                 {
759                         char *array;
760                         const char *item;
761
762                         ip = pc + 1;
763                         t1 = pp_pop();
764                         array = t1->pp_str;
765                         m = ip->forloop_cond->array_var;
766                         if (m->type == Node_param_list)
767                                 item = func_params[m->param_cnt].param;
768                         else
769                                 item = m->vname;
770                         indent(ip->forloop_body->exec_count);
771                         fprintf(prof_fp, "%s (%s%s%s) {\n", op2str(Op_K_arrayfor),
772                                                 item, op2str(Op_in_array), array);
773                         indent_in();
774                         pp_free(t1);
775                         pprint(ip->forloop_body->nexti, pc->target_break, false);
776                         indent_out();
777                         indent(SPACEOVER);
778                         fprintf(prof_fp, "}\n");                        
779                         pc = pc->target_break;
780                 }
781                         break;
782
783                 case Op_K_switch:
784                         ip = pc + 1;
785                         fprintf(prof_fp, "%s (", op2str(pc->opcode));
786                         pprint(pc->nexti, ip->switch_start, false);
787                         t1 = pp_pop();
788                         fprintf(prof_fp, "%s) {\n", t1->pp_str);
789                         pp_free(t1);
790                         pprint(ip->switch_start, ip->switch_end, false);
791                         indent(SPACEOVER);
792                         fprintf(prof_fp, "}\n");
793                         pc = pc->target_break;
794                         break;
795
796                 case Op_K_case:
797                 case Op_K_default:
798                         indent(pc->stmt_start->exec_count);
799                         if (pc->opcode == Op_K_case) {
800                                 t1 = pp_pop();
801                                 fprintf(prof_fp, "%s %s:\n", op2str(pc->opcode), t1->pp_str);
802                                 pp_free(t1);
803                         } else
804                                 fprintf(prof_fp, "%s:\n", op2str(pc->opcode));
805                         indent_in();
806                         pprint(pc->stmt_start->nexti, pc->stmt_end->nexti, false);
807                         indent_out();
808                         break;
809
810                 case Op_K_if:
811                         fprintf(prof_fp, "%s (", op2str(pc->opcode));
812                         pprint(pc->nexti, pc->branch_if, false);
813                         t1 = pp_pop();
814                         fprintf(prof_fp, "%s) {", t1->pp_str);
815                         pp_free(t1);
816
817                         ip = pc->branch_if;
818                         if (ip->exec_count > 0)
819                                 fprintf(prof_fp, " # %ld", ip->exec_count);
820                         fprintf(prof_fp, "\n");
821                         indent_in();
822                         pprint(ip->nexti, pc->branch_else, false);
823                         indent_out();
824                         pc = pc->branch_else;
825                         if (pc->nexti->opcode == Op_no_op) {
826                                 indent(SPACEOVER);
827                                 fprintf(prof_fp, "}\n");
828                         }
829                         break;
830
831                 case Op_K_else:
832                         fprintf(prof_fp, "} %s {\n", op2str(pc->opcode));
833                         indent_in();
834                         pprint(pc->nexti, pc->branch_end, false);
835                         indent_out();
836                         indent(SPACEOVER);
837                         fprintf(prof_fp, "}\n");
838                         pc = pc->branch_end;
839                         break;
840
841                 case Op_cond_exp:
842                 {
843                         NODE *f, *t, *cond;
844                         size_t len;
845
846                         pprint(pc->nexti, pc->branch_if, false);
847                         ip = pc->branch_if;
848                         pprint(ip->nexti, pc->branch_else, false);
849                         ip = pc->branch_else->nexti;
850
851                         pc = ip->nexti;
852                         assert(pc->opcode == Op_cond_exp);
853                         pprint(pc->nexti, pc->branch_end, false);       
854
855                         f = pp_pop();
856                         t = pp_pop();
857                         cond = pp_pop();
858
859                         len =  f->pp_len + t->pp_len + cond->pp_len + 12;
860                         emalloc(str, char *, len, "pprint");
861                         sprintf(str, "(%s ? %s : %s)", cond->pp_str, t->pp_str, f->pp_str);
862
863                         pp_free(cond);
864                         pp_free(t);
865                         pp_free(f);
866                         pp_push(Op_cond_exp, str, CAN_FREE);
867                         pc = pc->branch_end;
868                 }
869                         break;                  
870
871                 case Op_exec_count:
872                         if (! in_for_header)
873                                 indent(pc->exec_count);
874                         break;
875
876                 default:
877                         cant_happen();
878                 }
879
880                 if (pc == endp)
881                         break;
882         }
883 }
884
885 /* pp_string_fp --- printy print a string to the fp */
886
887 /*
888  * This routine concentrates string pretty printing in one place,
889  * so that it can be called from multiple places within gawk.
890  */
891
892 void
893 pp_string_fp(Func_print print_func, FILE *fp, const char *in_str,
894                 size_t len, int delim, bool breaklines)
895 {
896         char *s = pp_string(in_str, len, delim);
897         int count;
898         size_t slen;
899         const char *str = (const char *) s;
900 #define BREAKPOINT      70 /* arbitrary */
901
902         slen = strlen(str);
903         for (count = 0; slen > 0; slen--, str++) {
904                 if (++count >= BREAKPOINT && breaklines) {
905                         print_func(fp, "%c\n%c", delim, delim);
906                         count = 0;
907                 } else
908                         print_func(fp, "%c", *str);
909         }
910         efree(s);
911 }
912
913
914 /* just_dump --- dump the profile and function stack and keep going */
915
916 static RETSIGTYPE
917 just_dump(int signum)
918 {
919         extern INSTRUCTION *code_block;
920
921         dump_prog(code_block);
922         dump_funcs();
923         dump_fcall_stack(prof_fp);
924         fflush(prof_fp);
925         signal(signum, just_dump);      /* for OLD Unix systems ... */
926 }
927
928 /* dump_and_exit --- dump the profile, the function stack, and exit */
929
930 static RETSIGTYPE
931 dump_and_exit(int signum)
932 {
933         just_dump(signum);
934         final_exit(EXIT_FAILURE);
935 }
936
937 /* print_lib_list --- print a list of all libraries loaded */
938
939 static void
940 print_lib_list(FILE *prof_fp)
941 {
942         SRCFILE *s;
943         static bool printed_header = false;
944
945         for (s = srcfiles->next; s != srcfiles; s = s->next) {
946                 if (s->stype == SRC_EXTLIB) {
947                         if (! printed_header) {
948                                 printed_header = true;
949                                 fprintf(prof_fp, _("\t# Loaded extensions (-l and/or @load)\n\n"));
950                         }
951                         fprintf(prof_fp, "\t@load \"%s\"\n", s->src);
952                 }
953         }
954         if (printed_header)     /* we found some */
955                 fprintf(prof_fp, "\n");
956 }
957
958 /* dump_prog --- dump the program */
959
960 /*
961  * XXX: I am not sure it is right to have the strings in the dump
962  * be translated, but I'll leave it alone for now.
963  */
964
965 void
966 dump_prog(INSTRUCTION *code)
967 {
968         time_t now;
969
970         (void) time(& now);
971         /* \n on purpose, with \n in ctime() output */
972         fprintf(prof_fp, _("\t# gawk profile, created %s\n"), ctime(& now));
973         print_lib_list(prof_fp);
974         pprint(code, NULL, false);
975 }
976
977 /* prec_level --- return the precedence of an operator, for paren tests */
978
979 static int
980 prec_level(int type)
981 {
982         switch (type) {
983         case Op_push_lhs:
984         case Op_push_param:
985         case Op_push_array:
986         case Op_push:
987         case Op_push_i:
988         case Op_push_re:
989         case Op_match_rec:
990         case Op_subscript:
991         case Op_subscript_lhs:
992         case Op_func_call:
993         case Op_K_delete_loop:
994         case Op_builtin:
995                 return 15;
996
997         case Op_field_spec:
998         case Op_field_spec_lhs:
999                 return 14;
1000
1001         case Op_exp:
1002         case Op_exp_i:
1003                 return 13;
1004
1005         case Op_preincrement:
1006         case Op_predecrement:
1007         case Op_postincrement:
1008         case Op_postdecrement:
1009                 return 12;
1010
1011         case Op_unary_minus:
1012         case Op_not:
1013                 return 11;
1014
1015         case Op_times:
1016         case Op_times_i:
1017         case Op_quotient:
1018         case Op_quotient_i:
1019         case Op_mod:
1020         case Op_mod_i:
1021                 return 10;
1022
1023         case Op_plus:
1024         case Op_plus_i:
1025         case Op_minus:
1026         case Op_minus_i:
1027                 return 9;
1028
1029         case Op_concat:
1030         case Op_assign_concat:
1031                 return 8;
1032
1033         case Op_equal:
1034         case Op_notequal:
1035         case Op_greater:
1036         case Op_leq:
1037         case Op_geq:
1038         case Op_match:
1039         case Op_nomatch:
1040                 return 7;
1041
1042         case Op_K_getline:
1043         case Op_K_getline_redir:
1044                 return 6;
1045
1046         case Op_less:
1047         case Op_in_array:
1048                 return 5;
1049
1050         case Op_and:
1051                 return 4;
1052
1053         case Op_or:
1054                 return 3;
1055
1056         case Op_cond_exp:
1057                 return 2;
1058
1059         case Op_assign:
1060         case Op_assign_times:
1061         case Op_assign_quotient:
1062         case Op_assign_mod:
1063         case Op_assign_plus:
1064         case Op_assign_minus:
1065         case Op_assign_exp:
1066                 return 1;
1067
1068         default:
1069                 return 0;
1070         }
1071 }
1072
1073 /* is_scalar --- return true if scalar, false otherwise */
1074
1075 static bool
1076 is_scalar(int type)
1077 {
1078         switch (type) {
1079         case Op_push_lhs:
1080         case Op_push_param:
1081         case Op_push_array:
1082         case Op_push:
1083         case Op_push_i:
1084         case Op_push_re:
1085         case Op_subscript:
1086         case Op_subscript_lhs:
1087         case Op_func_call:
1088         case Op_builtin:
1089         case Op_field_spec:
1090         case Op_field_spec_lhs:
1091         case Op_preincrement:
1092         case Op_predecrement:
1093         case Op_postincrement:
1094         case Op_postdecrement:
1095         case Op_unary_minus:
1096         case Op_not:
1097                 return true;
1098
1099         default:
1100                 return false;
1101         }
1102 }
1103
1104 /* is_binary --- return true if type represents a binary operator */
1105
1106 static bool
1107 is_binary(int type)
1108 {
1109         switch (type) {
1110         case Op_geq:
1111         case Op_leq:
1112         case Op_greater:
1113         case Op_less:
1114         case Op_notequal:
1115         case Op_equal:
1116         case Op_exp:
1117         case Op_times:
1118         case Op_quotient:
1119         case Op_mod:
1120         case Op_plus:
1121         case Op_minus:
1122         case Op_exp_i:
1123         case Op_times_i:
1124         case Op_quotient_i:
1125         case Op_mod_i:
1126         case Op_plus_i:
1127         case Op_minus_i:
1128         case Op_concat:
1129         case Op_assign_concat:
1130         case Op_match:
1131         case Op_nomatch:
1132         case Op_assign:
1133         case Op_assign_times:
1134         case Op_assign_quotient:
1135         case Op_assign_mod:
1136         case Op_assign_plus:
1137         case Op_assign_minus:
1138         case Op_assign_exp:
1139         case Op_cond_exp:
1140         case Op_and:
1141         case Op_or:
1142         case Op_in_array:
1143         case Op_K_getline_redir:        /* sometimes */
1144         case Op_K_getline:
1145                 return true;
1146
1147         default:
1148                 return false;
1149         }
1150 }
1151
1152 /* pp_parenthesize --- parenthesize an expression in stack */
1153
1154 static void
1155 pp_parenthesize(NODE *sp)
1156 {
1157         char *p = sp->pp_str;
1158         size_t len = sp->pp_len;
1159
1160         emalloc(p, char *, len + 3, "pp_parenthesize");
1161         *p = '(';
1162         memcpy(p + 1, sp->pp_str, len);
1163         p[len + 1] = ')';
1164         p[len + 2] = '\0';
1165         if ((sp->flags & CAN_FREE) != 0)
1166                 efree(sp->pp_str);
1167         sp->pp_str = p;
1168         sp->pp_len += 2;
1169         sp->flags |= CAN_FREE;
1170 }
1171
1172 /* parenthesize --- parenthesize two nodes relative to parent node type */
1173
1174 static void
1175 parenthesize(int type, NODE *left, NODE *right)
1176 {
1177         int rprec = prec_level(right->type);
1178         int lprec = prec_level(left->type);
1179         int prec = prec_level(type);
1180
1181         if (lprec < prec)
1182                 pp_parenthesize(left);
1183         if (rprec < prec)
1184                 pp_parenthesize(right);
1185 }
1186
1187 /* pp_string --- pretty format a string or regex constant */
1188
1189 char *
1190 pp_string(const char *in_str, size_t len, int delim)
1191 {
1192         static char str_escapes[] = "\a\b\f\n\r\t\v\\";
1193         static char str_printables[] = "abfnrtv\\";
1194         static char re_escapes[] = "\a\b\f\n\r\t\v";
1195         static char re_printables[] = "abfnrtv";
1196         char *escapes;
1197         char *printables;
1198         char *cp;
1199         int i;
1200         const unsigned char *str = (const unsigned char *) in_str;
1201         size_t ofre, osiz;
1202         char *obuf, *obufout;
1203
1204         assert(delim == '"' || delim == '/');
1205
1206         if (delim == '/') {
1207                 escapes = re_escapes;
1208                 printables = re_printables;
1209         } else {
1210                 escapes = str_escapes;
1211                 printables = str_printables;
1212         }
1213
1214 /* make space for something l big in the buffer */
1215 #define chksize(l)  if ((l) > ofre) { \
1216                 long olen = obufout - obuf; \
1217                 erealloc(obuf, char *, osiz * 2, "pp_string"); \
1218                 obufout = obuf + olen; \
1219                 ofre += osiz; \
1220                 osiz *= 2; \
1221         } ofre -= (l)
1222
1223         osiz = len + 3 + 2;     /* initial size; 3 for delim + terminating null */
1224         emalloc(obuf, char *, osiz, "pp_string");
1225         obufout = obuf;
1226         ofre = osiz - 1;
1227
1228         *obufout++ = delim;
1229         for (; len > 0; len--, str++) {
1230                 chksize(2);             /* make space for 2 chars */
1231                 if (delim != '/' && *str == delim) {
1232                         *obufout++ = '\\';
1233                         *obufout++ = delim;
1234                 } else if (*str == '\0') {
1235                         chksize(4);
1236
1237                         *obufout++ = '\\';
1238                         *obufout++ = '0';
1239                         *obufout++ = '0';
1240                         *obufout++ = '0';
1241                 } else if ((cp = strchr(escapes, *str)) != NULL) {
1242                         i = cp - escapes;
1243                         *obufout++ = '\\';
1244                         *obufout++ = printables[i];
1245                 /* NB: Deliberate use of lower-case versions. */
1246                 } else if (isascii(*str) && isprint(*str)) {
1247                         *obufout++ = *str;
1248                         ofre += 1;
1249                 } else {
1250                         size_t len;
1251
1252                         chksize(8);             /* total available space is 10 */
1253
1254                         sprintf(obufout, "\\%03o", *str & 0xff);
1255                         len = strlen(obufout);
1256                         ofre += (10 - len);      /* adjust free space count */
1257                         obufout += len;
1258                 }
1259         }
1260         chksize(2);
1261         *obufout++ = delim;
1262         *obufout = '\0';
1263         return obuf;
1264 #undef chksize
1265 }
1266
1267 /* pp_number --- pretty format a number */
1268
1269 char *
1270 pp_number(NODE *n)
1271 {
1272 #define PP_PRECISION 6
1273         char *str;
1274
1275         emalloc(str, char *, PP_PRECISION + 10, "pp_number");
1276 #ifdef HAVE_MPFR
1277         if (is_mpg_float(n))
1278                 mpfr_sprintf(str, "%0.*R*g", PP_PRECISION, ROUND_MODE, n->mpg_numbr);
1279         else if (is_mpg_integer(n))
1280                 mpfr_sprintf(str, "%Zd", n->mpg_i);
1281         else
1282 #endif
1283         sprintf(str, "%0.*g", PP_PRECISION, n->numbr);
1284         return str;
1285 #undef PP_PRECISION
1286 }
1287
1288 /* pp_node --- pretty format a node */
1289
1290 char *
1291 pp_node(NODE *n)
1292 {
1293         if ((n->flags & NUMBER) != 0)
1294                 return pp_number(n);
1295         return pp_string(n->stptr, n->stlen, '"');
1296 }
1297
1298 /* pp_list --- pretty print a list, with surrounding characters and separator */
1299
1300 static NODE **pp_args = NULL;
1301 static int npp_args;
1302
1303 static char *
1304 pp_list(int nargs, const char *paren, const char *delim)
1305 {
1306         NODE *r;
1307         char *str, *s;
1308         size_t len;
1309         size_t delimlen;
1310         int i;
1311
1312         if (pp_args == NULL) {
1313                 npp_args = nargs;
1314                 emalloc(pp_args, NODE **, (nargs + 2) * sizeof(NODE *), "pp_list");
1315         } else if (nargs > npp_args) {
1316                 npp_args = nargs;
1317                 erealloc(pp_args, NODE **, (nargs + 2) * sizeof(NODE *), "pp_list");
1318         }
1319
1320         delimlen = strlen(delim);
1321         len = -delimlen;
1322         for (i = 1; i <= nargs; i++) {
1323                 r = pp_args[i] = pp_pop();
1324                 len += r->pp_len + delimlen;
1325         }
1326         if (paren != NULL) {
1327                 assert(strlen(paren) == 2);
1328                 len += 2;
1329         }
1330
1331         emalloc(str, char *, len + 1, "pp_list");
1332         s = str;
1333         if (paren != NULL)
1334                 *s++ = paren[0];  
1335         r = pp_args[nargs];
1336         memcpy(s, r->pp_str, r->pp_len);
1337         s += r->pp_len;
1338         pp_free(r);
1339         for (i = nargs - 1; i > 0; i--) {
1340                 if (delimlen > 0) {
1341                         memcpy(s, delim, delimlen);
1342                         s += delimlen;
1343                 }
1344                 r = pp_args[i];
1345                 memcpy(s, r->pp_str, r->pp_len);
1346                 s += r->pp_len;
1347                 pp_free(r);
1348         }
1349         if (paren != NULL)
1350                 *s++ = paren[1];
1351         *s = '\0';
1352         return str;                                     
1353 }
1354
1355 /* pp_concat --- handle concatenation and correct parenthesizing of expressions */
1356
1357 static char *
1358 pp_concat(int nargs)
1359 {
1360         NODE *r;
1361         char *str, *s;
1362         size_t len;
1363         static const size_t delimlen = 1;       /* " " */
1364         int i;
1365         int pl_l, pl_r;
1366
1367         if (pp_args == NULL) {
1368                 npp_args = nargs;
1369                 emalloc(pp_args, NODE **, (nargs + 2) * sizeof(NODE *), "pp_concat");
1370         } else if (nargs > npp_args) {
1371                 npp_args = nargs;
1372                 erealloc(pp_args, NODE **, (nargs + 2) * sizeof(NODE *), "pp_concat");
1373         }
1374
1375         /*
1376          * items are on the stack in reverse order that they
1377          * will be printed to pop them off backwards.
1378          */
1379
1380         len = -delimlen;
1381         for (i = nargs; i >= 1; i--) {
1382                 r = pp_args[i] = pp_pop();
1383                 len += r->pp_len + delimlen + 2;
1384         }
1385
1386         emalloc(str, char *, len + 1, "pp_concat");
1387         s = str;
1388
1389         /* now copy in */
1390         for (i = 1; i < nargs; i++) {
1391                 r = pp_args[i];
1392
1393                 pl_l = prec_level(pp_args[i]->type);
1394                 pl_r = prec_level(pp_args[i+1]->type);
1395
1396                 if (is_scalar(pp_args[i]->type) && is_scalar(pp_args[i+1]->type)) {
1397                         memcpy(s, r->pp_str, r->pp_len);
1398                         s += r->pp_len;
1399                 } else if (pl_l <= pl_r || is_scalar(pp_args[i+1]->type)) {
1400                         *s++ = '(';
1401                         memcpy(s, r->pp_str, r->pp_len);
1402                         s += r->pp_len;
1403                         *s++ = ')';
1404                 } else {
1405                         memcpy(s, r->pp_str, r->pp_len);
1406                         s += r->pp_len;
1407                 }
1408                 pp_free(r);
1409
1410                 if (i < nargs) {
1411                         *s++ = ' ';
1412                 }
1413         }
1414         
1415         pl_l = prec_level(pp_args[nargs-1]->type);
1416         pl_r = prec_level(pp_args[nargs]->type);
1417         r = pp_args[nargs];
1418         if (pl_l >= pl_r && ! is_scalar(pp_args[nargs]->type)) {
1419                 *s++ = '(';
1420                 memcpy(s, r->pp_str, r->pp_len);
1421                 s += r->pp_len;
1422                 *s++ = ')';
1423         } else {
1424                 memcpy(s, r->pp_str, r->pp_len);
1425                 s += r->pp_len;
1426         }
1427         pp_free(r);
1428
1429         *s = '\0';
1430         return str;                                     
1431 }
1432
1433 /* pp_group3 --- string together up to 3 strings */
1434
1435 static char *
1436 pp_group3(const char *s1, const char *s2, const char *s3)
1437 {
1438         size_t len1, len2, len3, l;
1439         char *str, *s;
1440
1441         len1 = strlen(s1);
1442         len2 = strlen(s2);
1443         len3 = strlen(s3);
1444         l = len1 + len2 + len3 + 2;
1445         emalloc(str, char *, l, "pp_group3");
1446         s = str;
1447         if (len1 > 0) {
1448                 memcpy(s, s1, len1);
1449                 s += len1;
1450         }
1451         if (len2 > 0) {
1452                 memcpy(s, s2, len2);
1453                 s += len2;
1454         }
1455         if (len3 > 0) {
1456                 memcpy(s, s3, len3);
1457                 s += len3;
1458         }
1459         *s = '\0';
1460         return str;
1461 }
1462
1463 /* pp_func --- pretty print a function */
1464
1465 int
1466 pp_func(INSTRUCTION *pc, void *data ATTRIBUTE_UNUSED)
1467 {
1468         int j;
1469         static bool first = true;
1470         NODE *func;
1471         int pcount;
1472
1473         if (first) {
1474                 first = false;
1475                 fprintf(prof_fp, _("\n\t# Functions, listed alphabetically\n"));
1476         }
1477
1478         func = pc->func_body;
1479         fprintf(prof_fp, "\n");
1480         indent(pc->nexti->exec_count);
1481         fprintf(prof_fp, "%s %s(", op2str(Op_K_function), func->vname);
1482         pcount = func->param_cnt;
1483         func_params = func->fparms;
1484         for (j = 0; j < pcount; j++) {
1485                 fprintf(prof_fp, "%s", func_params[j].param);
1486                 if (j < pcount - 1)
1487                         fprintf(prof_fp, ", ");
1488         }
1489         fprintf(prof_fp, ")\n\t{\n");
1490         indent_in();
1491         pprint(pc->nexti->nexti, NULL, false);  /* function body */
1492         indent_out();
1493         fprintf(prof_fp, "\t}\n");
1494         return 0;
1495 }
1496
1497 /* redir2str --- convert a redirection type into a printable value */
1498
1499 const char *
1500 redir2str(int redirtype)
1501 {
1502         static const char *const redirtab[] = {
1503                 "",
1504                 " > ",  /* redirect_output */
1505                 " >> ", /* redirect_append */
1506                 " | ",  /* redirect_pipe */
1507                 " | ",  /* redirect_pipein */
1508                 " < ",  /* redirect_input */
1509                 " |& ", /* redirect_twoway */
1510         };
1511
1512         if (redirtype < 0 || redirtype > redirect_twoway)
1513                 fatal(_("redir2str: unknown redirection type %d"), redirtype);
1514         return redirtab[redirtype];
1515 }