2 * profile.c - gawk bytecode pretty-printer with counts
6 * Copyright (C) 1999-2011 the Free Software Foundation, Inc.
8 * This file is part of GAWK, the GNU implementation of the
9 * AWK Programming Language.
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.
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.
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
28 static void pprint(INSTRUCTION *startp, INSTRUCTION *endp, int 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_concat(const char *s1, const char *s2, const char *s3);
33 static int is_binary(int type);
34 static int prec_level(int type);
35 static void pp_push(int type, char *s, int flag);
36 static NODE *pp_pop(void);
37 static void pp_free(NODE *n);
38 const char *redir2str(int redirtype);
41 #define pp_len hlength
47 static RETSIGTYPE dump_and_exit(int signum) ATTRIBUTE_NORETURN;
48 static RETSIGTYPE just_dump(int signum);
51 /* pretty printing related functions and variables */
53 static NODE *pp_stack = NULL;
54 static char **fparms; /* function parameter names */
55 static FILE *prof_fp; /* where to send the profile */
57 static long indent_level = 0;
62 /* init_profiling --- do needed initializations, see also main.c */
65 init_profiling(int *flag ATTRIBUTE_UNUSED, const char *def_file ATTRIBUTE_UNUSED)
70 set_prof_file(def_file);
75 /* set_prof_file --- set the output file for profiling */
78 set_prof_file(const char *file)
81 prof_fp = fopen(file, "w");
82 if (prof_fp == NULL) {
83 warning(_("could not open `%s' for writing: %s"),
84 file, strerror(errno));
85 warning(_("sending profile to standard error"));
90 /* init_profiling_signals --- set up signal handling for pgawk */
93 init_profiling_signals()
97 signal(SIGINT, dump_and_exit);
98 signal(SIGQUIT, just_dump);
99 #else /* !__DJGPP__ */
101 signal(SIGHUP, dump_and_exit);
104 signal(SIGUSR1, just_dump);
106 #endif /* !__DJGPP__ */
107 #endif /* PROFILING */
110 /* indent --- print out enough tabs */
118 fprintf(prof_fp, "\t");
120 fprintf(prof_fp, "%6ld ", count);
122 assert(indent_level >= 0);
123 for (i = 0; i < indent_level; i++)
124 fprintf(prof_fp, "\t");
127 /* indent_in --- increase the level, with error checking */
132 assert(indent_level >= 0);
136 /* indent_out --- decrease the level, with error checking */
142 assert(indent_level >= 0);
146 pp_push(int type, char *s, int flag)
151 n->pp_len = strlen(s);
170 if ((n->flags & CAN_FREE) != 0)
176 * pprint --- pretty print a program segment
180 pprint(INSTRUCTION *startp, INSTRUCTION *endp, int in_for_header)
190 static int rule_count[MAXRULE];
192 for (pc = startp; pc != endp; pc = pc->nexti) {
193 if (pc->source_line > 0)
194 sourceline = pc->source_line;
196 switch (pc->opcode) {
198 source = pc->source_file;
202 if (! rule_count[rule]++)
203 fprintf(prof_fp, _("\t# %s block(s)\n\n"), ruletab[rule]);
204 fprintf(prof_fp, "\t%s {\n", ruletab[rule]);
205 ip = (pc + 1)->firsti;
207 if (! rule_count[rule]++)
208 fprintf(prof_fp, _("\t# Rule(s)\n\n"));
210 indent(ip->exec_count);
211 if (ip != (pc + 1)->firsti) { /* non-empty pattern */
212 pprint(ip->nexti, (pc + 1)->firsti, FALSE);
214 fprintf(prof_fp, "%s {", t1->pp_str);
216 ip = (pc + 1)->firsti;
218 if (ip->exec_count > 0)
219 fprintf(prof_fp, " # %ld", ip->exec_count);
221 fprintf(prof_fp, "\n");
223 fprintf(prof_fp, "{\n");
224 ip = (pc + 1)->firsti;
229 pprint(ip, (pc + 1)->lasti, FALSE);
231 fprintf(prof_fp, "\t}\n\n");
232 pc = (pc + 1)->lasti;
239 memset(rule_count, 0, MAXRULE * sizeof(int));
244 if (m == Nnull_string) /* optional return or exit value; don't print 0 or "" */
245 pp_push(pc->opcode, m->stptr, DONT_FREE);
246 else if ((m->flags & NUMBER) != 0)
247 pp_push(pc->opcode, pp_number(m->numbr), CAN_FREE);
249 str = pp_string(m->stptr, m->stlen, '"');
250 if ((m->flags & INTLSTR) != 0) {
252 str = pp_concat("_", tmp, "");
255 pp_push(pc->opcode, str, CAN_FREE);
261 case Op_assign_concat:
269 case Node_param_list:
270 pp_push(pc->opcode, fparms[m->param_cnt], DONT_FREE);
276 if (m->vname != NULL)
277 pp_push(pc->opcode, m->vname, DONT_FREE);
279 fatal(_("internal error: %s with null vname"),
280 nodetype2str(m->type));
287 switch (pc->opcode) {
289 t2 = pp_pop(); /* l.h.s. */
290 t1 = pp_pop(); /* r.h.s. */
291 fprintf(prof_fp, "%s%s%s", t2->pp_str, op2str(pc->opcode), t1->pp_str);
295 t1 = pp_pop(); /* array */
296 tmp = pp_list(pc->expr_count, op2str(Op_subscript), ", "); /*subscript*/
297 t2 = pp_pop(); /* r.h.s. */
298 fprintf(prof_fp, "%s%s%s%s", t1->pp_str, tmp,
299 op2str(pc->opcode), t2->pp_str);
303 case Op_assign_concat:
304 t2 = pp_pop(); /* l.h.s. */
306 tmp = pp_concat(t2->pp_str, op2str(Op_concat), t1->pp_str);
307 fprintf(prof_fp, "%s%s%s", t2->pp_str, op2str(Op_assign), tmp);
313 fprintf(prof_fp, "\n");
322 case Op_subscript_lhs:
324 tmp = pp_list(pc->sub_count, op2str(pc->opcode), ", ");
326 str = pp_concat(t1->pp_str, tmp, "");
329 pp_push(pc->opcode, str, CAN_FREE);
334 pprint(pc->nexti, pc->target_jmp, in_for_header);
337 parenthesize(pc->opcode, t1, t2);
338 str = pp_concat(t1->pp_str, op2str(pc->opcode), t2->pp_str);
341 pp_push(pc->opcode, str, CAN_FREE);
353 if (prec_level(pc->opcode) > prec_level(t1->type)
354 && is_binary(t1->type)) /* (a - b) * 1 */
356 if ((m->flags & NUMBER) != 0)
357 tmp = pp_number(m->numbr);
359 tmp = pp_string(m->stptr, m->stlen, '"');
360 str = pp_concat(t1->pp_str, op2str(pc->opcode), tmp);
363 pp_push(pc->opcode, str, CAN_FREE);
380 parenthesize(pc->opcode, t1, t2);
381 str = pp_concat(t1->pp_str, op2str(pc->opcode), t2->pp_str);
384 pp_push(pc->opcode, str, CAN_FREE);
387 case Op_preincrement:
388 case Op_predecrement:
389 case Op_postincrement:
390 case Op_postdecrement:
392 if (pc->opcode == Op_preincrement || pc->opcode == Op_predecrement)
393 str = pp_concat(op2str(pc->opcode), t1->pp_str, "");
395 str = pp_concat(t1->pp_str, op2str(pc->opcode), "");
397 pp_push(pc->opcode, str, CAN_FREE);
401 case Op_field_spec_lhs:
405 if (is_binary(t1->type))
408 /* optypes table (eval.c) includes space after ! */
409 str = pp_concat(op2str(pc->opcode), t1->pp_str, "");
411 pp_push(pc->opcode, str, CAN_FREE);
416 case Op_assign_minus:
417 case Op_assign_times:
418 case Op_assign_quotient:
421 t2 = pp_pop(); /* l.h.s. */
423 str = pp_concat(t2->pp_str, op2str(pc->opcode), t1->pp_str);
426 pp_push(pc->opcode, str, CAN_FREE);
430 t1 = pp_pop(); /* field num */
431 if (is_binary(t1->type))
433 t2 = pp_pop(); /* r.h.s. */
434 fprintf(prof_fp, "$%s%s%s", t1->pp_str, op2str(pc->opcode), t2->pp_str);
438 fprintf(prof_fp, "\n");
442 str = pp_list(pc->expr_count, NULL,
443 (pc->concat_flag & CSUBSEP) ? ", " : op2str(Op_concat));
444 pp_push(Op_concat, str, CAN_FREE);
452 if (pc->expr_count > 0) {
454 sub = pp_list(pc->expr_count, NULL, ", ");
455 fprintf(prof_fp, "%s %s[%s]", op2str(Op_K_delete), array, sub);
458 fprintf(prof_fp, "%s %s", op2str(Op_K_delete), array);
460 fprintf(prof_fp, "\n");
465 case Op_K_delete_loop:
466 /* Efficency hack not in effect because of exec_count instruction */
475 if (pc->expr_count > 1) {
476 sub = pp_list(pc->expr_count, "()", ", ");
477 str = pp_concat(sub, op2str(Op_in_array), array);
482 str = pp_concat(sub, op2str(Op_in_array), array);
486 pp_push(Op_in_array, str, CAN_FREE);
492 case Op_field_assign:
493 case Op_arrayfor_init:
494 case Op_arrayfor_incr:
495 case Op_arrayfor_final:
506 case Op_after_beginfile:
507 case Op_after_endfile:
512 const char *fname = "sub";
513 if (pc->sub_flags & GSUB)
515 else if (pc->sub_flags & GENSUB)
517 tmp = pp_list(pc->expr_count, "()", ", ");
518 str = pp_concat(fname, tmp, "");
520 pp_push(Op_sub_builtin, str, CAN_FREE);
526 static char *ext_func = "extension_function()";
527 const char *fname = getfname(pc->builtin);
529 if (pc->expr_count > 0) {
530 tmp = pp_list(pc->expr_count, "()", ", ");
531 str = pp_concat(fname, tmp, "");
534 str = pp_concat(fname, "()", "");
535 pp_push(Op_builtin, str, CAN_FREE);
537 pp_push(Op_builtin, ext_func, DONT_FREE);
544 if (pc->opcode == Op_K_print_rec)
545 tmp = pp_concat(" ", op2str(Op_field_spec), "0");
546 else if (pc->redir_type != 0)
547 tmp = pp_list(pc->expr_count, "()", ", ");
549 tmp = pp_list(pc->expr_count, " ", ", ");
550 tmp[strlen(tmp) - 1] = '\0'; /* remove trailing space */
553 if (pc->redir_type != 0) {
555 if (is_binary(t1->type))
557 fprintf(prof_fp, "%s%s%s%s", op2str(pc->opcode),
558 tmp, redir2str(pc->redir_type), t1->pp_str);
561 fprintf(prof_fp, "%s%s", op2str(pc->opcode), tmp);
564 fprintf(prof_fp, "\n");
568 if (pc->memory->type != Node_regex)
574 NODE *re = pc->memory->re_exp;
575 str = pp_string(re->stptr, re->stlen, '/');
576 pp_push(pc->opcode, str, CAN_FREE);
585 if (is_binary(t1->type))
589 if (m->type == Node_dynregex) {
592 if (is_binary(t2->type))
595 str = pp_concat(txt, op2str(pc->opcode), restr);
598 NODE *re = m->re_exp;
599 restr = pp_string(re->stptr, re->stlen, '/');
600 str = pp_concat(txt, op2str(pc->opcode), restr);
604 pp_push(pc->opcode, str, CAN_FREE);
609 case Op_K_getline_redir:
612 tmp = pp_concat(op2str(Op_K_getline), " ", t1->pp_str);
615 tmp = pp_concat(op2str(Op_K_getline), "", "");
617 if (pc->redir_type != 0) {
618 int before = (pc->redir_type == redirect_pipein
619 || pc->redir_type == redirect_twoway);
622 if (is_binary(t2->type))
625 str = pp_concat(t2->pp_str, redir2str(pc->redir_type), tmp);
627 str = pp_concat(tmp, redir2str(pc->redir_type), t2->pp_str);
632 pp_push(pc->opcode, str, CAN_FREE);
635 case Op_indirect_func_call:
638 char *fname = pc->func_name;
642 if (pc->opcode == Op_indirect_func_call)
646 pcount = (pc + 1)->expr_count;
648 tmp = pp_list(pcount, "()", ", ");
649 str = pp_concat(pre, fname, tmp);
652 str = pp_concat(pre, fname, "()");
653 if (pc->opcode == Op_indirect_func_call) {
654 t1 = pp_pop(); /* indirect var */
657 pp_push(pc->opcode, str, CAN_FREE);
665 fprintf(prof_fp, "%s\n", op2str(pc->opcode));
671 if (is_binary(t1->type))
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);
680 fprintf(prof_fp, "%s", t1->pp_str);
682 fprintf(prof_fp, "\n");
688 pprint(pc->nexti, ip->condpair_left, FALSE);
689 pprint(ip->condpair_left->nexti, ip->condpair_right, FALSE);
692 str = pp_concat(t1->pp_str, ", ", t2->pp_str);
695 pp_push(Op_line_range, str, CAN_FREE);
696 pc = ip->condpair_right;
701 indent(ip->while_body->exec_count);
702 fprintf(prof_fp, "%s (", op2str(pc->opcode));
703 pprint(pc->nexti, ip->while_body, FALSE);
705 fprintf(prof_fp, "%s) {\n", t1->pp_str);
708 pprint(ip->while_body->nexti, pc->target_break, FALSE);
711 fprintf(prof_fp, "}\n");
712 pc = pc->target_break;
717 indent(pc->nexti->exec_count);
718 fprintf(prof_fp, "%s {\n", op2str(pc->opcode));
720 pprint(pc->nexti->nexti, ip->doloop_cond, FALSE);
722 pprint(ip->doloop_cond, pc->target_break, FALSE);
725 fprintf(prof_fp, "} %s (%s)\n", op2str(Op_K_while), t1->pp_str);
727 pc = pc->target_break;
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, "; ");
737 if (ip->forloop_cond->opcode == Op_no_op &&
738 ip->forloop_cond->nexti == ip->forloop_body)
739 fprintf(prof_fp, "; ");
741 pprint(ip->forloop_cond, ip->forloop_body, TRUE);
743 fprintf(prof_fp, "%s; ", t1->pp_str);
747 pprint(pc->target_continue, pc->target_break, TRUE);
748 fprintf(prof_fp, ") {\n");
750 pprint(ip->forloop_body->nexti, pc->target_continue, FALSE);
753 fprintf(prof_fp, "}\n");
754 pc = pc->target_break;
764 m = ip->forloop_cond->array_var;
765 if (m->type == Node_param_list)
766 item = fparms[m->param_cnt];
769 indent(ip->forloop_body->exec_count);
770 fprintf(prof_fp, "%s (%s%s%s) {\n", op2str(Op_K_arrayfor),
771 item, op2str(Op_in_array), array);
774 pprint(ip->forloop_body->nexti, pc->target_break, FALSE);
777 fprintf(prof_fp, "}\n");
778 pc = pc->target_break;
784 fprintf(prof_fp, "%s (", op2str(pc->opcode));
785 pprint(pc->nexti, ip->switch_start, FALSE);
787 fprintf(prof_fp, "%s) {\n", t1->pp_str);
789 pprint(ip->switch_start, ip->switch_end, FALSE);
791 fprintf(prof_fp, "}\n");
792 pc = pc->target_break;
797 indent(pc->stmt_start->exec_count);
798 if (pc->opcode == Op_K_case) {
800 fprintf(prof_fp, "%s %s:\n", op2str(pc->opcode), t1->pp_str);
803 fprintf(prof_fp, "%s:\n", op2str(pc->opcode));
805 pprint(pc->stmt_start->nexti, pc->stmt_end->nexti, FALSE);
810 fprintf(prof_fp, "%s (", op2str(pc->opcode));
811 pprint(pc->nexti, pc->branch_if, FALSE);
813 fprintf(prof_fp, "%s) {", t1->pp_str);
817 if (ip->exec_count > 0)
818 fprintf(prof_fp, " # %ld", ip->exec_count);
819 fprintf(prof_fp, "\n");
821 pprint(ip->nexti, pc->branch_else, FALSE);
823 pc = pc->branch_else;
824 if (pc->nexti->opcode == Op_no_op) {
826 fprintf(prof_fp, "}\n");
831 fprintf(prof_fp, "} %s {\n", op2str(pc->opcode));
833 pprint(pc->nexti, pc->branch_end, FALSE);
836 fprintf(prof_fp, "}\n");
845 pprint(pc->nexti, pc->branch_if, FALSE);
847 pprint(ip->nexti, pc->branch_else, FALSE);
848 ip = pc->branch_else->nexti;
851 assert(pc->opcode == Op_cond_exp);
852 pprint(pc->nexti, pc->branch_end, FALSE);
858 len = f->pp_len + t->pp_len + cond->pp_len + 12;
859 emalloc(str, char *, len, "pprint");
860 sprintf(str, "(%s ? %s : %s)", cond->pp_str, t->pp_str, f->pp_str);
865 pp_push(Op_cond_exp, str, CAN_FREE);
872 indent(pc->exec_count);
884 /* pp_string_fp --- printy print a string to the fp */
887 * This routine concentrates string pretty printing in one place,
888 * so that it can be called from multiple places within gawk.
892 pp_string_fp(Func_print print_func, FILE *fp, const char *in_str,
893 size_t len, int delim, int breaklines)
895 char *s = pp_string(in_str, len, delim);
898 const char *str = (const char *) s;
899 #define BREAKPOINT 70 /* arbitrary */
902 for (count = 0; slen > 0; slen--, str++) {
903 if (++count >= BREAKPOINT && breaklines) {
904 print_func(fp, "%c\n%c", delim, delim);
907 print_func(fp, "%c", *str);
913 /* just_dump --- dump the profile and function stack and keep going */
916 just_dump(int signum)
918 extern INSTRUCTION *code_block;
920 dump_prog(code_block);
922 dump_fcall_stack(prof_fp);
924 signal(signum, just_dump); /* for OLD Unix systems ... */
927 /* dump_and_exit --- dump the profile, the function stack, and exit */
930 dump_and_exit(int signum)
938 /* dump_prog --- dump the program */
941 * XXX: I am not sure it is right to have the strings in the dump
942 * be translated, but I'll leave it alone for now.
946 dump_prog(INSTRUCTION *code)
951 /* \n on purpose, with \n in ctime() output */
952 fprintf(prof_fp, _("\t# gawk profile, created %s\n"), ctime(& now));
953 pprint(code, NULL, FALSE);
956 /* prec_level --- return the precedence of an operator, for paren tests */
970 case Op_subscript_lhs:
972 case Op_K_delete_loop:
977 case Op_field_spec_lhs:
984 case Op_preincrement:
985 case Op_predecrement:
986 case Op_postincrement:
987 case Op_postdecrement:
1009 case Op_assign_concat:
1022 case Op_K_getline_redir:
1041 case Op_assign_times:
1042 case Op_assign_quotient:
1044 case Op_assign_plus:
1045 case Op_assign_minus:
1077 case Op_assign_concat:
1081 case Op_assign_times:
1082 case Op_assign_quotient:
1084 case Op_assign_plus:
1085 case Op_assign_minus:
1091 case Op_K_getline_redir: /* sometimes */
1100 /* parenthesize --- parenthesize an expression in stack */
1103 pp_parenthesize(NODE *sp)
1105 char *p = sp->pp_str;
1106 size_t len = sp->pp_len;
1108 emalloc(p, char *, len + 3, "pp_parenthesize");
1110 memcpy(p + 1, sp->pp_str, len);
1113 if ((sp->flags & CAN_FREE) != 0)
1117 sp->flags |= CAN_FREE;
1121 parenthesize(int type, NODE *left, NODE *right)
1123 int rprec = prec_level(right->type);
1124 int lprec = prec_level(left->type);
1125 int prec = prec_level(type);
1128 if (is_binary(left->type)) /* (a - b) * c */
1129 pp_parenthesize(left);
1130 if (prec >= rprec && is_binary(right->type)) /* (a - b) * (c - d) */
1131 pp_parenthesize(right);
1133 if (prec >= rprec && is_binary(right->type)) /* a - b - (c - d) */
1134 pp_parenthesize(right);
1138 /* pp_string --- pretty format a string or regex constant */
1141 pp_string(const char *in_str, size_t len, int delim)
1143 static char str_escapes[] = "\a\b\f\n\r\t\v\\";
1144 static char str_printables[] = "abfnrtv\\";
1145 static char re_escapes[] = "\a\b\f\n\r\t\v";
1146 static char re_printables[] = "abfnrtv";
1151 const unsigned char *str = (const unsigned char *) in_str;
1153 char *obuf, *obufout;
1155 assert(delim == '"' || delim == '/');
1158 escapes = re_escapes;
1159 printables = re_printables;
1161 escapes = str_escapes;
1162 printables = str_printables;
1165 /* make space for something l big in the buffer */
1166 #define chksize(l) if ((l) > ofre) { \
1167 long olen = obufout - obuf; \
1168 erealloc(obuf, char *, osiz * 2, "pp_string"); \
1169 obufout = obuf + olen; \
1174 osiz = len + 3 + 2; /* initial size; 3 for delim + terminating null */
1175 emalloc(obuf, char *, osiz, "pp_string");
1180 for (; len > 0; len--, str++) {
1181 chksize(2); /* make space for 2 chars */
1182 if (delim != '/' && *str == delim) {
1185 } else if ((cp = strchr(escapes, *str)) != NULL) {
1188 *obufout++ = printables[i];
1189 /* NB: Deliberate use of lower-case versions. */
1190 } else if (isascii(*str) && isprint(*str)) {
1196 chksize(8); /* total available space is 10 */
1198 sprintf(obufout, "\\%03o", *str & 0xff);
1199 len = strlen(obufout);
1200 ofre += (10 - len); /* adjust free space count */
1211 /* pp_number --- pretty format a number */
1216 #define PP_PRECISION 6
1219 emalloc(str, char *, PP_PRECISION + 10, "pp_number");
1220 sprintf(str, "%0.*g", PP_PRECISION, d);
1225 /* pp_node --- pretty format a node */
1230 if ((n->flags & NUMBER) != 0)
1231 return pp_number(n->numbr);
1232 return pp_string(n->stptr, n->stlen, '"');
1235 static NODE **pp_args = NULL;
1236 static int npp_args;
1239 pp_list(int nargs, const char *paren, const char *delim)
1247 if (pp_args == NULL) {
1249 emalloc(pp_args, NODE **, (nargs + 2) * sizeof(NODE *), "pp_list");
1250 } else if (nargs > npp_args) {
1252 erealloc(pp_args, NODE **, (nargs + 2) * sizeof(NODE *), "pp_list");
1255 delimlen = strlen(delim);
1257 for (i = 1; i <= nargs; i++) {
1258 r = pp_args[i] = pp_pop();
1259 len += r->pp_len + delimlen;
1261 if (paren != NULL) {
1262 assert(strlen(paren) == 2);
1266 emalloc(str, char *, len + 1, "pp_list");
1271 memcpy(s, r->pp_str, r->pp_len);
1274 for (i = nargs - 1; i > 0; i--) {
1276 memcpy(s, delim, delimlen);
1280 memcpy(s, r->pp_str, r->pp_len);
1291 pp_concat(const char *s1, const char *s2, const char *s3)
1293 size_t len1, len2, len3, l;
1299 l = len1 + len2 + len3 + 2;
1300 emalloc(str, char *, l, "pp_concat");
1303 memcpy(s, s1, len1);
1307 memcpy(s, s2, len2);
1311 memcpy(s, s3, len3);
1318 /* pp_func --- pretty print a function */
1321 pp_func(INSTRUCTION *pc, void *data ATTRIBUTE_UNUSED)
1326 static int first = TRUE;
1331 fprintf(prof_fp, _("\n\t# Functions, listed alphabetically\n"));
1335 fprintf(prof_fp, "\n");
1336 indent(pc->nexti->exec_count);
1337 fprintf(prof_fp, "%s %s(", op2str(Op_K_function), f->lnode->param);
1338 pnames = f->parmlist;
1340 pcount = f->lnode->param_cnt;
1341 for (j = 0; j < pcount; j++) {
1342 fprintf(prof_fp, "%s", pnames[j]);
1344 fprintf(prof_fp, ", ");
1346 fprintf(prof_fp, ")\n\t{\n");
1348 pprint(pc->nexti->nexti, NULL, FALSE); /* function body */
1350 fprintf(prof_fp, "\t}\n");
1354 /* redir2str --- convert a redirection type into a printable value */
1357 redir2str(int redirtype)
1359 static const char *const redirtab[] = {
1361 " > ", /* redirect_output */
1362 " >> ", /* redirect_append */
1363 " | ", /* redirect_pipe */
1364 " | ", /* redirect_pipein */
1365 " < ", /* redirect_input */
1366 " |& ", /* redirect_twoway */
1369 if (redirtype < 0 || redirtype > redirect_twoway)
1370 fatal(_("redir2str: unknown redirection type %d"), redirtype);
1371 return redirtab[redirtype];