"Fossies" - the Fresh Open Source Software Archive

Member "gawk-5.1.0/profile.c" (6 Feb 2020, 50838 Bytes) of package /linux/misc/gawk-5.1.0.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "profile.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 5.0.1_vs_5.1.0.

    1 /*
    2  * profile.c - gawk bytecode pretty-printer with counts
    3  */
    4 
    5 /*
    6  * Copyright (C) 1999-2020 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, int flags);
   29 static INSTRUCTION *end_line(INSTRUCTION *ip);
   30 static void pp_parenthesize(NODE *n);
   31 static void parenthesize(int type, NODE *left, NODE *right);
   32 static char *pp_list(int nargs, const char *paren, const char *delim);
   33 static char *pp_group3(const char *s1, const char *s2, const char *s3);
   34 static char *pp_concat(int nargs);
   35 static char *pp_string_or_typed_regex(const char *in_str, size_t len, int delim, bool typed_regex);
   36 static char *pp_typed_regex(const char *in_str, size_t len, int delim);
   37 static bool is_binary(int type);
   38 static bool is_scalar(int type);
   39 static int prec_level(int type);
   40 static void pp_push(int type, char *s, int flag, INSTRUCTION *comment);
   41 static NODE *pp_pop(void);
   42 static void print_comment(INSTRUCTION *pc, long in);
   43 const char *redir2str(int redirtype);
   44 static void pp_namespace(const char *name, INSTRUCTION *comment);
   45 static void pp_namespace_list(INSTRUCTION *list);
   46 static char *adjust_namespace(char *name, bool *malloced);
   47 
   48 #define pp_str  vname
   49 #define pp_len  sub.nodep.reserved
   50 #define pp_next rnode
   51 #define pp_comment  sub.nodep.x.cmnt
   52 
   53 #define DONT_FREE 1
   54 #define CAN_FREE  2
   55 
   56 static void dump_and_exit(int signum) ATTRIBUTE_NORETURN;
   57 static void just_dump(int signum);
   58 
   59 /* pretty printing related functions and variables */
   60 
   61 static NODE *pp_stack = NULL;
   62 static NODE *func_params;   /* function parameters */
   63 static FILE *prof_fp;   /* where to send the profile */
   64 
   65 static long indent_level = 0;
   66 
   67 static const char tabs[] = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
   68 static const size_t tabs_len = sizeof(tabs) - 1;
   69 
   70 #define check_indent_level() \
   71     if (indent_level + 1 > tabs_len) \
   72         /* We're allowed to be snarky, occasionally. */ \
   73         fatal(_("Program indentation level too deep. Consider refactoring your code"));
   74 
   75 
   76 #define SPACEOVER   0
   77 
   78 #define NO_PPRINT_FLAGS 0
   79 #define IN_FOR_HEADER   1
   80 #define IN_ELSE_IF  2
   81 
   82 /* set_prof_file --- set the output file for profiling or pretty-printing */
   83 
   84 void
   85 set_prof_file(const char *file)
   86 {
   87     int fd;
   88 
   89     assert(file != NULL);
   90     fd = devopen_simple(file, "w", true);
   91     if (fd == INVALID_HANDLE)
   92         prof_fp = NULL;
   93     else if (fd == fileno(stdout))
   94         prof_fp = stdout;
   95     else if (fd == fileno(stderr))
   96         prof_fp = stderr;
   97     else
   98         prof_fp = fdopen(fd, "w");
   99 
  100     if (prof_fp == NULL) {
  101         /* don't leak file descriptors */
  102         int e = errno;
  103 
  104         if (   fd != INVALID_HANDLE
  105             && fd != fileno(stdout)
  106             && fd != fileno(stderr))
  107             (void) close(fd);
  108 
  109         errno = e;
  110         warning(_("could not open `%s' for writing: %s"),
  111                 file, strerror(errno));
  112         warning(_("sending profile to standard error"));
  113         prof_fp = stderr;
  114     }
  115 }
  116 
  117 /* init_profiling_signals --- set up signal handling for gawk --profile */
  118 
  119 void
  120 init_profiling_signals()
  121 {
  122 #ifdef __DJGPP__
  123     signal(SIGINT, dump_and_exit);
  124     signal(SIGQUIT, just_dump);
  125 #else  /* !__DJGPP__ */
  126 #ifdef SIGHUP
  127     signal(SIGHUP, dump_and_exit);
  128 #endif
  129 #ifdef SIGUSR1
  130     signal(SIGUSR1, just_dump);
  131 #endif
  132 #endif /* !__DJGPP__ */
  133 }
  134 
  135 /* indent --- print out enough tabs */
  136 
  137 static void
  138 indent(long count)
  139 {
  140     int i;
  141 
  142     if (do_profile) {
  143         if (count == 0)
  144             fprintf(prof_fp, "\t");
  145         else
  146             fprintf(prof_fp, "%6ld  ", count);
  147     }
  148 
  149     assert(indent_level >= 0);
  150     for (i = 0; i < indent_level; i++)
  151         fprintf(prof_fp, "\t");
  152 }
  153 
  154 /* indent_in --- increase the level, with error checking */
  155 
  156 static void
  157 indent_in(void)
  158 {
  159     assert(indent_level >= 0);
  160     indent_level++;
  161 }
  162 
  163 /* indent_out --- decrease the level, with error checking */
  164 
  165 static void
  166 indent_out(void)
  167 {
  168     indent_level--;
  169     assert(indent_level >= 0);
  170 }
  171 
  172 /* pp_push --- push a pretty printed string onto the stack */
  173 
  174 static void
  175 pp_push(int type, char *s, int flag, INSTRUCTION *comment)
  176 {
  177     NODE *n;
  178     getnode(n);
  179     n->pp_str = s;
  180     n->pp_len = strlen(s);
  181     n->flags = flag;
  182     n->type = type;
  183     n->pp_next = pp_stack;
  184     n->pp_comment = comment;
  185     pp_stack = n;
  186 }
  187 
  188 /* pp_pop --- pop a pretty printed string off the stack */
  189 
  190 static NODE *
  191 pp_pop()
  192 {
  193     NODE *n;
  194     n = pp_stack;
  195     pp_stack = n->pp_next;
  196     return n;
  197 }
  198 
  199 /* pp_top --- look at what's on the top of the stack */
  200 
  201 #define pp_top()    pp_stack
  202 
  203 /* pp_free --- release a pretty printed node */
  204 
  205 static void
  206 pp_free(NODE *n)
  207 {
  208     if ((n->flags & CAN_FREE) != 0)
  209         efree(n->pp_str);
  210     freenode(n);
  211 }
  212 
  213 /* pprint --- pretty print a program segment */
  214 
  215 static void
  216 pprint(INSTRUCTION *startp, INSTRUCTION *endp, int flags)
  217 {
  218     INSTRUCTION *pc;
  219     NODE *t1;
  220     char *str;
  221     NODE *t2;
  222     INSTRUCTION *ip1;
  223     INSTRUCTION *ip2;
  224     NODE *m;
  225     char *tmp;
  226     int rule;
  227     static int rule_count[MAXRULE];
  228     static bool skip_comment = false;
  229 
  230     for (pc = startp; pc != endp; pc = pc->nexti) {
  231         if (pc->source_line > 0)
  232             sourceline = pc->source_line;
  233 
  234         /* skip leading EOL comment as it has already been printed  */
  235         if (pc->opcode == Op_comment
  236             && pc->memory->comment_type == EOL_COMMENT
  237             && skip_comment) {
  238             skip_comment = false;
  239             continue;
  240         }
  241         skip_comment = false;
  242 
  243         switch (pc->opcode) {
  244         case Op_rule:
  245             /*
  246              * Rules are four instructions long.
  247              * See append_rule in awkgram.y.
  248              * The first has the Rule Op Code, nexti etc.
  249              * The second, (pc + 1) has firsti and lasti:
  250              *  the first/last ACTION instructions for this rule.
  251              * The third has first_line and last_line:
  252              *  the first and last source line numbers.
  253              * The fourth holds the namespace name if there is one.
  254              *  (there should be one if we're in this file)
  255              * This can actually be a list in reverse order if
  256              * there were several @namespace directives one
  257              * after the other.
  258              */
  259             source = pc->source_file;
  260             rule = pc->in_rule;
  261 
  262             pp_namespace_list(pc[3].nexti);
  263 
  264             if (rule != Rule) {
  265                 /* Allow for pre-non-rule-block comment  */
  266                 if (pc->nexti != (pc+1)->firsti
  267                     && pc->nexti->opcode == Op_comment
  268                     && pc->nexti->memory->comment_type == BLOCK_COMMENT)
  269                     print_comment(pc->nexti, -1);
  270                 ip1 = (pc + 1)->firsti;
  271                 ip2 = (pc + 1)->lasti;
  272 
  273                 if (do_profile) {
  274                     if (! rule_count[rule]++)
  275                         fprintf(prof_fp, _("\t# %s rule(s)\n\n"), ruletab[rule]);
  276                     indent(0);
  277                 }
  278                 fprintf(prof_fp, "%s {", ruletab[rule]);
  279                 end_line(pc);
  280                 skip_comment = true;
  281             } else {
  282                 if (do_profile && ! rule_count[rule]++)
  283                     fprintf(prof_fp, _("\t# Rule(s)\n\n"));
  284                 ip1 = pc->nexti;
  285                 indent(ip1->exec_count);
  286                 if (ip1 != (pc + 1)->firsti) {      /* non-empty pattern */
  287                     pprint(ip1->nexti, (pc + 1)->firsti, NO_PPRINT_FLAGS);
  288                     /* Allow for case where the "pattern" is just a comment  */
  289                     if (ip1->nexti->nexti->nexti != (pc +1)->firsti
  290                         || ip1->nexti->opcode != Op_comment) {
  291                         t1 = pp_pop();
  292                         fprintf(prof_fp, "%s {", t1->pp_str);
  293                         pp_free(t1);
  294                     } else
  295                         fprintf(prof_fp, "{");
  296                     ip1 = (pc + 1)->firsti;
  297                     ip2 = (pc + 1)->lasti;
  298 
  299                     if (do_profile && ip1->exec_count > 0)
  300                         fprintf(prof_fp, " # %ld", ip1->exec_count);
  301 
  302                     end_line(ip1);
  303                     skip_comment = true;
  304                 } else {
  305                     fprintf(prof_fp, "{\n");
  306                     ip1 = (pc + 1)->firsti;
  307                     ip2 = (pc + 1)->lasti;
  308                 }
  309                 ip1 = ip1->nexti;
  310             }
  311             indent_in();
  312             pprint(ip1, ip2, NO_PPRINT_FLAGS);
  313             indent_out();
  314             if (do_profile)
  315                 indent(0);
  316             fprintf(prof_fp, "}\n\n");
  317             pc = (pc + 1)->lasti;
  318             break;
  319 
  320         case Op_atexit:
  321             break;
  322 
  323         case Op_stop:
  324             memset(rule_count, 0, MAXRULE * sizeof(int));
  325             break;
  326 
  327         case Op_push_i:
  328             m = pc->memory;
  329             if (m == Nnull_string)  /* optional return or exit value; don't print 0 or "" */
  330                 pp_push(pc->opcode, m->stptr, DONT_FREE, pc->comment);
  331             else if ((m->flags & NUMBER) != 0)
  332                 pp_push(pc->opcode, pp_number(m), CAN_FREE, pc->comment);
  333             else {
  334                 str = pp_string(m->stptr, m->stlen, '"');
  335                 if ((m->flags & INTLSTR) != 0) {
  336                     char *tmp = str;
  337                     str = pp_group3("_", tmp, "");
  338                     efree(tmp);
  339                 }
  340                 pp_push(pc->opcode, str, CAN_FREE, pc->comment);
  341             }
  342             break;
  343 
  344         case Op_store_var:
  345             if (pc->initval != NULL)
  346                 pp_push(Op_push_i, pp_node(pc->initval), CAN_FREE, pc->comment);
  347             /* fall through */
  348         case Op_store_sub:
  349         case Op_assign_concat:
  350         case Op_push_lhs:
  351         case Op_push_param:
  352         case Op_push_array:
  353         case Op_push:
  354         case Op_push_arg:
  355         case Op_push_arg_untyped:
  356             m = pc->memory;
  357             switch (m->type) {
  358             case Node_param_list:
  359                 pp_push(pc->opcode, func_params[m->param_cnt].param, DONT_FREE, pc->comment);
  360                 break;
  361 
  362             case Node_var:
  363             case Node_var_new:
  364             case Node_var_array:
  365                 if (m->vname != NULL) {
  366                     bool malloced = false;
  367                     char *name = adjust_namespace(m->vname, & malloced);
  368 
  369                     pp_push(pc->opcode, name, malloced ? CAN_FREE : DONT_FREE, pc->comment);
  370                 } else
  371                     fatal(_("internal error: %s with null vname"),
  372                             nodetype2str(m->type));
  373                 break;
  374 
  375             default:
  376                 cant_happen();
  377             }
  378 
  379             switch (pc->opcode) {
  380             case Op_store_var:
  381                 t2 = pp_pop(); /* l.h.s. */
  382                 t1 = pp_pop(); /* r.h.s. */
  383                 fprintf(prof_fp, "%s%s%s", t2->pp_str, op2str(pc->opcode), t1->pp_str);
  384                 goto cleanup;
  385 
  386             case Op_store_sub:
  387                 t1 = pp_pop();  /* array */
  388                 tmp = pp_list(pc->expr_count, op2str(Op_subscript), ", "); /*subscript*/
  389                 t2 = pp_pop(); /* r.h.s. */
  390                 fprintf(prof_fp, "%s%s%s%s", t1->pp_str, tmp,
  391                                     op2str(pc->opcode), t2->pp_str);
  392                 efree(tmp);
  393                 goto cleanup;
  394 
  395             case Op_assign_concat:
  396                 t2 = pp_pop(); /* l.h.s. */
  397                 t1 = pp_pop();
  398                 tmp = pp_group3(t2->pp_str, op2str(Op_concat), t1->pp_str);
  399                 fprintf(prof_fp, "%s%s%s", t2->pp_str, op2str(Op_assign), tmp);
  400                 efree(tmp);
  401 cleanup:
  402                 pp_free(t2);
  403                 pp_free(t1);
  404                 if ((flags & IN_FOR_HEADER) == 0)
  405                     pc = end_line(pc);
  406                 break;
  407 
  408             default:
  409                 break;
  410             }
  411             break;
  412 
  413         case Op_sub_array:
  414         case Op_subscript_lhs:
  415         case Op_subscript:
  416             tmp = pp_list(pc->sub_count, op2str(pc->opcode), ", ");
  417             t1 = pp_pop();
  418             str = pp_group3(t1->pp_str, tmp, "");
  419             efree(tmp);
  420             pp_free(t1);
  421             pp_push(pc->opcode, str, CAN_FREE, pc->comment);
  422             break;
  423 
  424         case Op_and:
  425         case Op_or:
  426             pprint(pc->nexti, pc->target_jmp, flags);
  427             t2 = pp_pop();
  428             t1 = pp_pop();
  429             parenthesize(pc->opcode, t1, t2);
  430             if (pc->comment == NULL)
  431                 str = pp_group3(t1->pp_str, op2str(pc->opcode), t2->pp_str);
  432             else {
  433                 check_indent_level();
  434 
  435                 size_t len = strlen(t1->pp_str)
  436                         + strlen(op2str(pc->opcode)) + strlen(t2->pp_str)   // foo && bar
  437                         + indent_level + 1              // indent
  438                         + pc->comment->memory->stlen + 3;       // tab comment
  439 
  440                 emalloc(str, char *, len, "pprint");
  441                 sprintf(str, "%s%s%s%.*s %s", t1->pp_str, op2str(pc->opcode),
  442                         pc->comment->memory->stptr,
  443                         (int) (indent_level + 1), tabs, t2->pp_str);
  444             }
  445             pp_free(t1);
  446             pp_free(t2);
  447             pp_push(pc->opcode, str, CAN_FREE, pc->comment);
  448             pc = pc->target_jmp;
  449             break;
  450 
  451         case Op_plus_i:
  452         case Op_minus_i:
  453         case Op_times_i:
  454         case Op_exp_i:
  455         case Op_quotient_i:
  456         case Op_mod_i:
  457             m = pc->memory;
  458             t1 = pp_pop();
  459             if (prec_level(pc->opcode) > prec_level(t1->type)
  460                     && is_binary(t1->type))  /* (a - b) * 1 */
  461                 pp_parenthesize(t1);
  462             if ((m->flags & NUMBER) != 0)
  463                 tmp = pp_number(m);
  464             else
  465                 tmp = pp_string(m->stptr, m->stlen, '"');
  466             str = pp_group3(t1->pp_str, op2str(pc->opcode), tmp);
  467             efree(tmp);
  468             pp_free(t1);
  469             pp_push(pc->opcode, str, CAN_FREE, pc->comment);
  470             break;
  471 
  472         case Op_parens:
  473             t1 = pp_pop();
  474             str = pp_group3("(", t1->pp_str, ")");
  475             pp_free(t1);
  476             pp_push(pc->opcode, str, CAN_FREE, pc->comment);
  477             break;
  478 
  479         case Op_plus:
  480         case Op_minus:
  481         case Op_times:
  482         case Op_exp:
  483         case Op_quotient:
  484         case Op_mod:
  485         case Op_equal:
  486         case Op_notequal:
  487         case Op_less:
  488         case Op_greater:
  489         case Op_leq:
  490         case Op_geq:
  491             t2 = pp_pop();
  492             t1 = pp_pop();
  493             parenthesize(pc->opcode, t1, t2);
  494             str = pp_group3(t1->pp_str, op2str(pc->opcode), t2->pp_str);
  495             pp_free(t1);
  496             pp_free(t2);
  497             pp_push(pc->opcode, str, CAN_FREE, pc->comment);
  498             break;
  499 
  500         case Op_preincrement:
  501         case Op_predecrement:
  502         case Op_postincrement:
  503         case Op_postdecrement:
  504             t1 = pp_pop();
  505             if (pc->opcode == Op_preincrement || pc->opcode == Op_predecrement)
  506                 str = pp_group3(op2str(pc->opcode), t1->pp_str, "");
  507             else
  508                 str = pp_group3(t1->pp_str, op2str(pc->opcode), "");
  509             pp_free(t1);
  510             pp_push(pc->opcode, str, CAN_FREE, pc->comment);
  511             break;
  512 
  513         case Op_field_spec:
  514         case Op_field_spec_lhs:
  515         case Op_unary_minus:
  516         case Op_unary_plus:
  517         case Op_not:
  518             t1 = pp_pop();
  519             if (is_binary(t1->type)
  520                 || (((OPCODE) t1->type) == pc->opcode
  521                     && (pc->opcode == Op_unary_minus
  522                         || pc->opcode == Op_unary_plus)))
  523                 pp_parenthesize(t1);
  524 
  525             /* optypes table (eval.c) includes space after ! */
  526             str = pp_group3(op2str(pc->opcode), t1->pp_str, "");
  527             pp_free(t1);
  528             pp_push(pc->opcode, str, CAN_FREE, pc->comment);
  529             break;
  530 
  531         case Op_assign:
  532         case Op_assign_plus:
  533         case Op_assign_minus:
  534         case Op_assign_times:
  535         case Op_assign_quotient:
  536         case Op_assign_mod:
  537         case Op_assign_exp:
  538             t2 = pp_pop(); /* l.h.s. */
  539             t1 = pp_pop();
  540             str = pp_group3(t2->pp_str, op2str(pc->opcode), t1->pp_str);
  541             pp_free(t2);
  542             pp_free(t1);
  543             pp_push(pc->opcode, str, CAN_FREE, pc->comment);
  544             break;
  545 
  546         case Op_store_field:
  547             t1 = pp_pop(); /* field num */
  548             if (is_binary(t1->type))
  549                 pp_parenthesize(t1);
  550             t2 = pp_pop(); /* r.h.s. */
  551             fprintf(prof_fp, "$%s%s%s", t1->pp_str, op2str(pc->opcode), t2->pp_str);
  552             pp_free(t2);
  553             pp_free(t1);
  554             if ((flags & IN_FOR_HEADER) == 0)
  555                 pc = end_line(pc);
  556             break;
  557 
  558         case Op_concat:
  559             str = pp_concat(pc->expr_count);
  560             pp_push(Op_concat, str, CAN_FREE, pc->comment);
  561             break;
  562 
  563         case Op_K_delete:
  564         {
  565             char *array;
  566             t1 = pp_pop();
  567             array = t1->pp_str;
  568             if (pc->expr_count > 0) {
  569                 char *sub;
  570                 sub = pp_list(pc->expr_count, NULL, pc->expr_count > 1 ? "][" : ", ");
  571                 fprintf(prof_fp, "%s %s[%s]", op2str(Op_K_delete), array, sub);
  572                 efree(sub);
  573             } else
  574                 fprintf(prof_fp, "%s %s", op2str(Op_K_delete), array);
  575             if ((flags & IN_FOR_HEADER) == 0)
  576                 pc = end_line(pc);
  577             pp_free(t1);
  578         }
  579             break;
  580 
  581         case Op_K_delete_loop:
  582             /* Efficency hack not in effect because of exec_count instruction */
  583             cant_happen();
  584             break;
  585 
  586         case Op_in_array:
  587         {
  588             char *array, *sub;
  589             t1 = pp_pop();
  590             array = t1->pp_str;
  591             if (pc->expr_count > 1) {
  592                 sub = pp_list(pc->expr_count, "()", ", ");
  593                 str = pp_group3(sub, op2str(Op_in_array), array);
  594                 efree(sub);
  595             } else {
  596                 t2 = pp_pop();
  597                 if (prec_level(t2->type) < prec_level(Op_in_array)) {
  598                     pp_parenthesize(t2);
  599                 }
  600                 sub = t2->pp_str;
  601                 str = pp_group3(sub, op2str(Op_in_array), array);
  602                 pp_free(t2);
  603             }
  604             pp_free(t1);
  605             pp_push(Op_in_array, str, CAN_FREE, pc->comment);
  606         }
  607             break;
  608 
  609         case Op_var_update:
  610         case Op_var_assign:
  611         case Op_field_assign:
  612         case Op_subscript_assign:
  613         case Op_arrayfor_init:
  614         case Op_arrayfor_incr:
  615         case Op_arrayfor_final:
  616         case Op_newfile:
  617         case Op_get_record:
  618         case Op_lint:
  619         case Op_jmp:
  620         case Op_jmp_false:
  621         case Op_jmp_true:
  622         case Op_no_op:
  623         case Op_and_final:
  624         case Op_or_final:
  625         case Op_cond_pair:
  626         case Op_after_beginfile:
  627         case Op_after_endfile:
  628             break;
  629 
  630         case Op_sub_builtin:
  631         {
  632             const char *fname = "sub";
  633             if ((pc->sub_flags & GSUB) != 0)
  634                 fname = "gsub";
  635             else if ((pc->sub_flags & GENSUB) != 0)
  636                 fname = "gensub";
  637             tmp = pp_list(pc->expr_count, "()", ", ");
  638             str = pp_group3(fname, tmp, "");
  639             efree(tmp);
  640             pp_push(Op_sub_builtin, str, CAN_FREE, pc->comment);
  641         }
  642             break;
  643 
  644         case Op_builtin:
  645         case Op_ext_builtin:
  646         {
  647             const char *fname;
  648             if (pc->opcode == Op_builtin) {
  649                 bool prepend_awk = (current_namespace != awk_namespace && strcmp(current_namespace, "awk") != 0);
  650                 fname = getfname(pc->builtin, prepend_awk);
  651             } else
  652                 fname = (pc + 1)->func_name;
  653             if (fname != NULL) {
  654                 if (pc->expr_count > 0) {
  655                     tmp = pp_list(pc->expr_count, "()", ", ");
  656                     str = pp_group3(fname, tmp, "");
  657                     efree(tmp);
  658                 } else
  659                     str = pp_group3(fname, "()", "");
  660                 pp_push(Op_builtin, str, CAN_FREE, pc->comment);
  661             } else
  662                 fatal(_("internal error: builtin with null fname"));
  663         }
  664             break;
  665 
  666         case Op_K_print:
  667         case Op_K_printf:
  668         case Op_K_print_rec:
  669             if (pc->opcode == Op_K_print_rec)
  670                 // instead of `print $0', just `print'
  671                 tmp = strdup("");
  672             else if (pc->redir_type != 0) {
  673                 // Avoid turning printf("hello\n") into printf(("hello\n"))
  674                 NODE *n = pp_top();
  675 
  676                 if (pc->expr_count == 1
  677                     && n->pp_str[0] == '(' 
  678                     && n->pp_str[n->pp_len - 1] == ')') {
  679                     n = pp_pop();
  680 
  681                     tmp = strdup(n->pp_str);
  682                     pp_free(n);
  683                 } else
  684                     tmp = pp_list(pc->expr_count, "()", ", ");
  685             } else {
  686                 tmp = pp_list(pc->expr_count, "  ", ", ");
  687                 tmp[strlen(tmp) - 1] = '\0';    /* remove trailing space */
  688             }
  689 
  690             if (pc->redir_type != 0) {
  691                 t1 = pp_pop();
  692                 if (is_binary(t1->type))
  693                     pp_parenthesize(t1);
  694                 fprintf(prof_fp, "%s%s%s%s", op2str(pc->opcode),
  695                             tmp, redir2str(pc->redir_type), t1->pp_str);
  696                 pp_free(t1);
  697             } else
  698                 fprintf(prof_fp, "%s%s", op2str(pc->opcode), tmp);
  699             efree(tmp);
  700             if ((flags & IN_FOR_HEADER) == 0)
  701                 pc = end_line(pc);
  702             break;
  703 
  704         case Op_push_re:
  705             if (pc->memory->type != Node_regex && (pc->memory->flags & REGEX) == 0)
  706                 break;
  707             /* else
  708                 fall through */
  709         case Op_match_rec:
  710         {
  711             if (pc->memory->type == Node_regex) {
  712                 NODE *re = pc->memory->re_exp;
  713                 str = pp_string(re->stptr, re->stlen, '/');
  714             } else {
  715                 assert((pc->memory->flags & REGEX) != 0);
  716                 str = pp_typed_regex(pc->memory->stptr, pc->memory->stlen, '/');
  717             }
  718             pp_push(pc->opcode, str, CAN_FREE, pc->comment);
  719         }
  720             break;
  721 
  722         case Op_nomatch:
  723         case Op_match:
  724         {
  725             char *restr, *txt;
  726             t1 = pp_pop();
  727             if (is_binary(t1->type))
  728                 pp_parenthesize(t1);
  729             txt = t1->pp_str;
  730             m = pc->memory;
  731             if (m->type == Node_dynregex) {
  732                 restr = txt;
  733                 t2 = pp_pop();
  734                 if (is_binary(t2->type))
  735                     pp_parenthesize(t2);
  736                 txt = t2->pp_str;
  737                 str = pp_group3(txt, op2str(pc->opcode), restr);
  738                 pp_free(t2);
  739             } else if (m->type == Node_val && (m->flags & REGEX) != 0) {
  740                 restr = pp_typed_regex(m->stptr, m->stlen, '/');
  741                 str = pp_group3(txt, op2str(pc->opcode), restr);
  742                 efree(restr);
  743             } else {
  744                 NODE *re = m->re_exp;
  745                 restr = pp_string(re->stptr, re->stlen, '/');
  746                 str = pp_group3(txt, op2str(pc->opcode), restr);
  747                 efree(restr);
  748             }
  749             pp_free(t1);
  750             pp_push(pc->opcode, str, CAN_FREE, pc->comment);
  751         }
  752             break;
  753 
  754         case Op_K_getline:
  755         case Op_K_getline_redir:
  756             if (pc->into_var) {
  757                 t1 = pp_pop();
  758                 tmp = pp_group3(op2str(Op_K_getline), " ", t1->pp_str);
  759                 pp_free(t1);
  760             } else
  761                 tmp = pp_group3(op2str(Op_K_getline), "", "");
  762 
  763             if (pc->redir_type != 0) {
  764                 int before = (pc->redir_type == redirect_pipein
  765                             || pc->redir_type == redirect_twoway);
  766 
  767                 t2 = pp_pop();
  768                 if (is_binary(t2->type))
  769                     pp_parenthesize(t2);
  770                 if (before)
  771                     str = pp_group3(t2->pp_str, redir2str(pc->redir_type), tmp);
  772                 else
  773                     str = pp_group3(tmp, redir2str(pc->redir_type), t2->pp_str);
  774                 efree(tmp);
  775                 pp_free(t2);
  776             } else
  777                 str = tmp;
  778             pp_push(pc->opcode, str, CAN_FREE, pc->comment);
  779             break;
  780 
  781         case Op_indirect_func_call:
  782         case Op_func_call:
  783         {
  784             char *pre;
  785             int pcount;
  786             bool malloced = false;
  787             char *fname = adjust_namespace(pc->func_name, & malloced);
  788 
  789             if (pc->opcode == Op_indirect_func_call)
  790                 pre = "@";
  791             else
  792                 pre = "";
  793             pcount = (pc + 1)->expr_count;
  794             if (pcount > 0) {
  795                 tmp = pp_list(pcount, "()", ", ");
  796                 str = pp_group3(pre, fname, tmp);
  797                 efree(tmp);
  798             } else
  799                 str = pp_group3(pre, fname, "()");
  800             if (pc->opcode == Op_indirect_func_call) {
  801                 t1 = pp_pop();  /* indirect var */
  802                 pp_free(t1);
  803             }
  804 
  805             pp_push(pc->opcode, str, CAN_FREE, pc->comment);
  806             if (malloced)
  807                 efree((void *) fname);
  808         }
  809             break;
  810 
  811         case Op_K_continue:
  812         case Op_K_break:
  813         case Op_K_nextfile:
  814         case Op_K_next:
  815             fprintf(prof_fp, "%s", op2str(pc->opcode));
  816             pc = end_line(pc);
  817             break;
  818 
  819         case Op_K_return:
  820         case Op_K_exit:
  821             t1 = pp_pop();
  822             if (is_binary(t1->type))
  823                 pp_parenthesize(t1);
  824             if (pc->source_line > 0) {  /* don't print implicit 'return' at end of function */
  825                 // avoid final trailing space to keep whiny users happy
  826                 if (t1->pp_str[0] != '\0')
  827                     fprintf(prof_fp, "%s %s", op2str(pc->opcode), t1->pp_str);
  828                 else
  829                     fprintf(prof_fp, "%s", op2str(pc->opcode));
  830                 pc = end_line(pc);
  831             }
  832             pp_free(t1);
  833             break;
  834 
  835         case Op_pop:
  836             t1 = pp_pop();
  837             fprintf(prof_fp, "%s", t1->pp_str);
  838             if ((flags & IN_FOR_HEADER) == 0)
  839                 pc = end_line(pc);
  840             pp_free(t1);
  841             break;
  842 
  843         case Op_line_range:
  844             ip1 = pc + 1;
  845             pprint(pc->nexti, ip1->condpair_left, NO_PPRINT_FLAGS);
  846             pprint(ip1->condpair_left->nexti, ip1->condpair_right, NO_PPRINT_FLAGS);
  847             t2 = pp_pop();
  848             t1 = pp_pop();
  849             str = pp_group3(t1->pp_str, ", ", t2->pp_str);
  850             pp_free(t1);
  851             pp_free(t2);
  852             pp_push(Op_line_range, str, CAN_FREE, pc->comment);
  853             pc = ip1->condpair_right;
  854             break;
  855 
  856         case Op_K_while:
  857             ip1 = pc + 1;
  858             indent(ip1->while_body->exec_count);
  859             fprintf(prof_fp, "%s (", op2str(pc->opcode));
  860             pprint(pc->nexti, ip1->while_body, NO_PPRINT_FLAGS);
  861             t1 = pp_pop();
  862             fprintf(prof_fp, "%s) {", t1->pp_str);
  863             pp_free(t1);
  864             ip1->while_body = end_line(ip1->while_body);
  865             indent_in();
  866             pprint(ip1->while_body->nexti, pc->target_break, NO_PPRINT_FLAGS);
  867             indent_out();
  868             indent(SPACEOVER);
  869             fprintf(prof_fp, "}");
  870             pc = end_line(pc->target_break);
  871             break;
  872 
  873         case Op_K_do:
  874             ip1 = pc + 1;
  875             indent(pc->nexti->exec_count);
  876             fprintf(prof_fp, "%s {", op2str(pc->opcode));
  877             end_line(pc->nexti);
  878             skip_comment = true;
  879             indent_in();
  880             pprint(pc->nexti->nexti, ip1->doloop_cond, NO_PPRINT_FLAGS);
  881             indent_out();
  882             pprint(ip1->doloop_cond, pc->target_break, NO_PPRINT_FLAGS);
  883             indent(SPACEOVER);
  884             t1 = pp_pop();
  885             fprintf(prof_fp, "} %s (%s)", op2str(Op_K_while), t1->pp_str);
  886             if (pc->comment)
  887                 fprintf(prof_fp, "\t%s", pc->comment->memory->stptr);
  888             else {
  889                 end_line(pc->target_break);
  890                 skip_comment = true;
  891             }
  892             pp_free(t1);
  893             pc = pc->target_break;
  894             break;
  895 
  896         case Op_K_for:
  897         {
  898             INSTRUCTION *comment1 = NULL, *comment2 = NULL;
  899 
  900             if (pc->comment != NULL) {
  901                 comment1 = pc->comment;
  902                 pc->comment = NULL;
  903                 if (comment1 != NULL && comment1->comment != NULL) {
  904                     comment2 = comment1->comment;
  905                     comment1->comment = NULL;
  906                 }
  907                 if (comment2 == NULL && comment1->memory->comment_type == FOR_COMMENT) {
  908                     comment2 = comment1;
  909                     comment2->memory->comment_type = EOL_COMMENT;
  910                     comment1 = NULL;
  911                 }
  912             }
  913 
  914             ip1 = pc + 1;
  915             indent(ip1->forloop_body->exec_count);
  916             fprintf(prof_fp, "%s (", op2str(pc->opcode));
  917 
  918             /* If empty for looop header, print it a little more nicely. */
  919             if (   pc->nexti->opcode == Op_no_op
  920                 && ip1->forloop_cond == pc->nexti
  921                 && pc->target_continue->opcode == Op_jmp
  922                 && comment1 == NULL && comment2 == NULL) {
  923                 fprintf(prof_fp, ";;");
  924             } else {
  925                 pprint(pc->nexti, ip1->forloop_cond, IN_FOR_HEADER);
  926                 fprintf(prof_fp, "; ");
  927 
  928                 if (comment1 != NULL) {
  929                     print_comment(comment1, 0);
  930                     indent(ip1->forloop_body->exec_count);
  931                     indent(1);
  932                 }
  933 
  934                 if (ip1->forloop_cond->opcode == Op_no_op &&
  935                         ip1->forloop_cond->nexti == ip1->forloop_body)
  936                     fprintf(prof_fp, "; ");
  937                 else {
  938                     pprint(ip1->forloop_cond, ip1->forloop_body, IN_FOR_HEADER);
  939                     t1 = pp_pop();
  940                     fprintf(prof_fp, "%s; ", t1->pp_str);
  941                     pp_free(t1);
  942                 }
  943 
  944                 if (comment2 != NULL) {
  945                     print_comment(comment2, 0);
  946                     indent(ip1->forloop_body->exec_count);
  947                     indent(1);
  948                 }
  949 
  950                 pprint(pc->target_continue, pc->target_break, IN_FOR_HEADER);
  951             }
  952             fprintf(prof_fp, ") {");
  953             end_line(ip1->forloop_body);
  954             skip_comment = true;
  955             indent_in();
  956             pprint(ip1->forloop_body->nexti, pc->target_continue, NO_PPRINT_FLAGS);
  957             indent_out();
  958             indent(SPACEOVER);
  959             fprintf(prof_fp, "}");
  960             end_line(pc->target_break);
  961             skip_comment = true;
  962             pc = pc->target_break;
  963         }
  964             break;
  965 
  966         case Op_K_arrayfor:
  967         {
  968             char *array;
  969             const char *item;
  970 
  971             ip1 = pc + 1;
  972             t1 = pp_pop();
  973             array = t1->pp_str;
  974             m = ip1->forloop_cond->array_var;
  975             if (m->type == Node_param_list)
  976                 item = func_params[m->param_cnt].param;
  977             else
  978                 item = m->vname;
  979             indent(ip1->forloop_body->exec_count);
  980             fprintf(prof_fp, "%s (%s%s%s) {", op2str(Op_K_arrayfor),
  981                         item, op2str(Op_in_array), array);
  982             end_line(ip1->forloop_body);
  983             skip_comment = true;
  984             indent_in();
  985             pp_free(t1);
  986             pprint(ip1->forloop_body->nexti, pc->target_break, NO_PPRINT_FLAGS);
  987             indent_out();
  988             indent(SPACEOVER);
  989             fprintf(prof_fp, "}");
  990             end_line(pc->target_break);
  991             skip_comment = true;
  992             pc = pc->target_break;
  993         }
  994             break;
  995 
  996         case Op_K_switch:
  997             ip1 = pc + 1;
  998             fprintf(prof_fp, "%s (", op2str(pc->opcode));
  999             pprint(pc->nexti, ip1->switch_start, NO_PPRINT_FLAGS);
 1000             t1 = pp_pop();
 1001             fprintf(prof_fp, "%s) {\n", t1->pp_str);
 1002             if (pc->comment)
 1003                 print_comment(pc->comment, 0);
 1004             pp_free(t1);
 1005             pprint(ip1->switch_start, ip1->switch_end, NO_PPRINT_FLAGS);
 1006             indent(SPACEOVER);
 1007             fprintf(prof_fp, "}\n");
 1008             if (ip1->switch_end->comment)
 1009                 print_comment(ip1->switch_end->comment, 0);
 1010             pc = pc->target_break;
 1011             break;
 1012 
 1013         case Op_K_case:
 1014         case Op_K_default:
 1015             indent(pc->stmt_start->exec_count);
 1016             if (pc->opcode == Op_K_case) {
 1017                 t1 = pp_pop();
 1018                 fprintf(prof_fp, "%s %s:", op2str(pc->opcode), t1->pp_str);
 1019                 pp_free(t1);
 1020             } else
 1021                 fprintf(prof_fp, "%s:", op2str(pc->opcode));
 1022 
 1023             indent_in();
 1024             if (pc->comment != NULL) {
 1025                 if (pc->comment->memory->comment_type == EOL_COMMENT)
 1026                     fprintf(prof_fp, "\t%s", pc->comment->memory->stptr);
 1027                 else {
 1028                     fprintf(prof_fp, "\n");
 1029                     print_comment(pc->comment, indent_level);
 1030                 }
 1031             } else
 1032                 fprintf(prof_fp, "\n");
 1033             pprint(pc->stmt_start->nexti, pc->stmt_end->nexti, NO_PPRINT_FLAGS);
 1034             indent_out();
 1035             break;
 1036 
 1037         case Op_K_if:
 1038             fprintf(prof_fp, "%s (", op2str(pc->opcode));
 1039             pprint(pc->nexti, pc->branch_if, NO_PPRINT_FLAGS);
 1040             t1 = pp_pop();
 1041             fprintf(prof_fp, "%s) {", t1->pp_str);
 1042             pp_free(t1);
 1043 
 1044             ip1 = pc->branch_if;
 1045             if (ip1->exec_count > 0)
 1046                 fprintf(prof_fp, " # %ld", ip1->exec_count);
 1047             ip1 = end_line(ip1);
 1048             indent_in();
 1049             if (pc->comment != NULL)
 1050                 print_comment(pc->comment, indent_level);
 1051             pprint(ip1->nexti, pc->branch_else, NO_PPRINT_FLAGS);
 1052             indent_out();
 1053             pc = pc->branch_else;
 1054             if (pc->nexti->opcode == Op_no_op) {    /* no following else */
 1055                 indent(SPACEOVER);
 1056                 fprintf(prof_fp, "}");
 1057                 if (pc->nexti->nexti->opcode != Op_comment
 1058                     || pc->nexti->nexti->memory->comment_type == BLOCK_COMMENT)
 1059                     fprintf(prof_fp, "\n");
 1060                 /* else
 1061                     It will be printed at the top. */
 1062             }
 1063             /*
 1064              * See next case; turn off the flag so that the
 1065              * following else is correctly indented.
 1066              */
 1067             flags &= ~IN_ELSE_IF;
 1068             break;
 1069 
 1070         case Op_K_else:
 1071             /*
 1072              * If possible, chain else-if's together on the
 1073              * same line.
 1074              *
 1075              * See awkgram.y:mk_condition to understand
 1076              * what is being checked here.
 1077              *
 1078              * Op_exec_count follows Op_K_else, check the
 1079              * opcode of the following instruction.
 1080              * Additionally, check that the subsequent if
 1081              * terminates where this else does; in that case
 1082              * it's ok to compact the if to follow the else.
 1083              */
 1084 
 1085             fprintf(prof_fp, "} %s ", op2str(pc->opcode));
 1086             if (pc->nexti->nexti->opcode == Op_K_if
 1087                 && pc->branch_end == pc->nexti->nexti->branch_else->lasti) {
 1088                 pprint(pc->nexti, pc->branch_end, IN_ELSE_IF);
 1089             } else {
 1090                 fprintf(prof_fp, "{");
 1091                 end_line(pc);
 1092                 skip_comment = true;
 1093                 indent_in();
 1094                 if (pc->comment != NULL)
 1095                     print_comment(pc->comment, indent_level);
 1096                 pprint(pc->nexti, pc->branch_end, NO_PPRINT_FLAGS);
 1097                 indent_out();
 1098                 indent(SPACEOVER);
 1099                 fprintf(prof_fp, "}");
 1100                 end_line(pc->branch_end);
 1101                 skip_comment = true;
 1102             }
 1103             /*
 1104              * Don't do end_line() here, we get multiple blank lines after
 1105              * the final else in a chain of else-ifs since they all point
 1106              * to the same branch_end.
 1107              */
 1108             pc = pc->branch_end;
 1109             break;
 1110 
 1111         case Op_cond_exp:
 1112         {
 1113             NODE *f, *t, *cond;
 1114             size_t len;
 1115             INSTRUCTION *qm_comment = NULL, *colon_comment = NULL;
 1116 
 1117             qm_comment = pc->comment;
 1118 
 1119             pprint(pc->nexti, pc->branch_if, NO_PPRINT_FLAGS);
 1120             ip1 = pc->branch_if;
 1121             pprint(ip1->nexti, pc->branch_else, NO_PPRINT_FLAGS);
 1122             ip1 = pc->branch_else->nexti;
 1123 
 1124             pc = ip1->nexti;
 1125             colon_comment = pc->comment;
 1126             assert(pc->opcode == Op_cond_exp);
 1127             pprint(pc->nexti, pc->branch_end, NO_PPRINT_FLAGS);
 1128 
 1129             f = pp_pop();
 1130             t = pp_pop();
 1131             cond = pp_pop();
 1132 
 1133             /*
 1134              * This stuff handles comments that come after a ?, :, or both.
 1135              * Allowing newlines after ? and : is a gawk extension.
 1136              * Theoretically this is fragile, since ?: expressions can be nested.
 1137              * In practice, it's not, since if there was a comment following ? or :
 1138              * in the original code, then it wasn't nested.
 1139              */
 1140 
 1141             len = f->pp_len + t->pp_len + cond->pp_len + 12;
 1142             if (qm_comment == NULL && colon_comment == NULL) {
 1143                 // easy case
 1144                 emalloc(str, char *, len, "pprint");
 1145                 sprintf(str, "%s ? %s : %s", cond->pp_str, t->pp_str, f->pp_str);
 1146             } else if (qm_comment != NULL && colon_comment != NULL) {
 1147                 check_indent_level();
 1148                 len += qm_comment->memory->stlen +      // comments
 1149                     colon_comment->memory->stlen +
 1150                     2 * (indent_level + 1) + 3 +        // indentation
 1151                     t->pp_len + 6;
 1152                 emalloc(str, char *, len, "pprint");
 1153                 sprintf(str,
 1154                     "%s ? %s"   // cond ? comment
 1155                     "%.*s   %s" // indent true-part
 1156                     " : %s"     // : comment
 1157                     "%.*s   %s",    // indent false-part
 1158                     cond->pp_str,   // condition
 1159                     qm_comment->memory->stptr,  // comment
 1160                     (int) (indent_level + 1), tabs,     // indent
 1161                     t->pp_str,          // true part
 1162                     colon_comment->memory->stptr,   // comment
 1163                     (int) (indent_level + 1), tabs,     // indent
 1164                     f->pp_str           // false part
 1165                     );
 1166             } else if (qm_comment != NULL) {
 1167                 check_indent_level();
 1168                 len += qm_comment->memory->stlen +  // comment
 1169                     1 * (indent_level + 1) + 3 +    // indentation
 1170                     t->pp_len + 3;
 1171                 emalloc(str, char *, len, "pprint");
 1172                 sprintf(str,
 1173                     "%s ? %s"   // cond ? comment
 1174                     "%.*s   %s" // indent true-part
 1175                     " : %s",    // : false-part
 1176                     cond->pp_str,   // condition
 1177                     qm_comment->memory->stptr,  // comment
 1178                     (int) (indent_level + 1), tabs,     // indent
 1179                     t->pp_str,          // true part
 1180                     f->pp_str           // false part
 1181                     );
 1182             } else {
 1183                 check_indent_level();
 1184                 len += colon_comment->memory->stlen +       // comment
 1185                     1 * (indent_level + 1) + 3 +        // indentation
 1186                     t->pp_len + 3;
 1187                 emalloc(str, char *, len, "pprint");
 1188                 sprintf(str,
 1189                     "%s ? %s"   // cond ? true-part
 1190                     " : %s"     // : comment
 1191                     "%.*s   %s",    // indent false-part
 1192                     cond->pp_str,           // condition
 1193                     t->pp_str,          // true part
 1194                     colon_comment->memory->stptr,   // comment
 1195                     (int) (indent_level + 1), tabs,     // indent
 1196                     f->pp_str           // false part
 1197                     );
 1198             }
 1199 
 1200             pp_free(cond);
 1201             pp_free(t);
 1202             pp_free(f);
 1203             pp_push(Op_cond_exp, str, CAN_FREE, pc->comment);
 1204             pc = pc->branch_end;
 1205         }
 1206             break;
 1207 
 1208         case Op_exec_count:
 1209             if (flags == NO_PPRINT_FLAGS)
 1210                 indent(pc->exec_count);
 1211             break;
 1212 
 1213         case Op_comment:
 1214             print_comment(pc, 0);
 1215             break;
 1216 
 1217         case Op_list:
 1218             break;
 1219 
 1220         default:
 1221             cant_happen();
 1222         }
 1223 
 1224         if (pc == endp)
 1225             break;
 1226     }
 1227 }
 1228 
 1229 /* end_line --- end pretty print line with new line or on-line comment  */
 1230 
 1231 INSTRUCTION *
 1232 end_line(INSTRUCTION *ip)
 1233 {
 1234     INSTRUCTION *ret = ip;
 1235 
 1236     if (ip->nexti->opcode == Op_comment
 1237         && ip->nexti->memory->comment_type == EOL_COMMENT) {
 1238         fprintf(prof_fp, "\t");
 1239         print_comment(ip->nexti, -1);
 1240         ret = ip->nexti;
 1241     }
 1242     else
 1243         fprintf(prof_fp, "\n");
 1244 
 1245     return ret;
 1246 }
 1247 
 1248 /* pp_string_fp --- pretty print a string to the fp */
 1249 
 1250 /*
 1251  * This routine concentrates string pretty printing in one place,
 1252  * so that it can be called from multiple places within gawk.
 1253  */
 1254 
 1255 void
 1256 pp_string_fp(Func_print print_func, FILE *fp, const char *in_str,
 1257         size_t len, int delim, bool breaklines)
 1258 {
 1259     char *s = pp_string(in_str, len, delim);
 1260     int count;
 1261     size_t slen;
 1262     const char *str = (const char *) s;
 1263 #define BREAKPOINT  70 /* arbitrary */
 1264 
 1265     slen = strlen(str);
 1266     for (count = 0; slen > 0; slen--, str++) {
 1267         print_func(fp, "%c", *str);
 1268         if (++count >= BREAKPOINT && breaklines) {
 1269             print_func(fp, "%c\n%c", delim, delim);
 1270             count = 0;
 1271         }
 1272     }
 1273     efree(s);
 1274 }
 1275 
 1276 
 1277 /* just_dump --- dump the profile and function stack and keep going */
 1278 
 1279 static void
 1280 just_dump(int signum)
 1281 {
 1282     extern INSTRUCTION *code_block;
 1283 
 1284     dump_prog(code_block);
 1285     dump_funcs();
 1286     dump_fcall_stack(prof_fp);
 1287     fflush(prof_fp);
 1288     signal(signum, just_dump);  /* for OLD Unix systems ... */
 1289 }
 1290 
 1291 /* dump_and_exit --- dump the profile, the function stack, and exit */
 1292 
 1293 static void
 1294 dump_and_exit(int signum)
 1295 {
 1296     just_dump(signum);
 1297     final_exit(EXIT_FAILURE);
 1298 }
 1299 
 1300 /* print_lib_list --- print a list of all libraries loaded */
 1301 
 1302 static void
 1303 print_lib_list(FILE *prof_fp)
 1304 {
 1305     SRCFILE *s;
 1306     static bool printed_header = false;
 1307     const char *indent = "";
 1308     bool found = false;
 1309 
 1310     if (do_profile)
 1311         indent = "\t";
 1312 
 1313     for (s = srcfiles->next; s != srcfiles; s = s->next) {
 1314         if (s->stype == SRC_EXTLIB) {
 1315             if (do_profile && ! printed_header) {
 1316                 printed_header = true;
 1317                 fprintf(prof_fp, _("%s# Loaded extensions (-l and/or @load)\n\n"), indent);
 1318             }
 1319             found = true;
 1320             fprintf(prof_fp, "%s@load \"%s\"", indent, s->src);
 1321             if (s->comment != NULL) {
 1322                 fprintf(prof_fp, "\t");
 1323                 print_comment(s->comment, indent_level + 1);
 1324             } else
 1325                 fprintf(prof_fp, "\n");
 1326         }
 1327     }
 1328     if (found)  /* we found some */
 1329         fprintf(prof_fp, "\n");
 1330 }
 1331 
 1332 /* print_include_list --- print a list of all files included */
 1333 
 1334 static void
 1335 print_include_list(FILE *prof_fp)
 1336 {
 1337     SRCFILE *s;
 1338     static bool printed_header = false;
 1339     bool found = false;
 1340 
 1341     if (do_profile)
 1342         return;
 1343 
 1344     for (s = srcfiles->next; s != srcfiles; s = s->next) {
 1345         if (s->stype == SRC_INC) {
 1346             if (! printed_header) {
 1347                 printed_header = true;
 1348                 fprintf(prof_fp, _("\n# Included files (-i and/or @include)\n\n"));
 1349             }
 1350             found = true;
 1351             fprintf(prof_fp, "# @include \"%s\"", s->src);
 1352             if (s->comment != NULL) {
 1353                 fprintf(prof_fp, "\t");
 1354                 print_comment(s->comment, indent_level + 1);
 1355             } else
 1356                 fprintf(prof_fp, "\n");
 1357         }
 1358     }
 1359     if (found)  /* we found some */
 1360         fprintf(prof_fp, "\n");
 1361 }
 1362 
 1363 /* print_comment --- print comment text with proper indentation */
 1364 
 1365 static void
 1366 print_comment(INSTRUCTION* pc, long in)
 1367 {
 1368     char *text;
 1369     size_t count;
 1370     bool after_newline = false;
 1371 
 1372     count = pc->memory->stlen;
 1373     text = pc->memory->stptr;
 1374 
 1375     if (in >= 0)
 1376         indent(in);    /* is this correct? Where should comments go?  */
 1377     for (; count > 0; count--, text++) {
 1378         if (after_newline) {
 1379             indent(in);
 1380             after_newline = false;
 1381         }
 1382         putc(*text, prof_fp);
 1383         after_newline = (*text == '\n');
 1384     }
 1385 
 1386     if (pc->comment) {
 1387         // chaining should only be two deep
 1388         assert(pc->comment->comment == NULL);
 1389         // if first was EOL comment, next must be block comment,
 1390         // it needs to be indented.
 1391         if (pc->memory->comment_type == EOL_COMMENT)
 1392             in++;
 1393         print_comment(pc->comment, in);
 1394     }
 1395 }
 1396 
 1397 /* dump_prog --- dump the program */
 1398 
 1399 /*
 1400  * XXX: I am not sure it is right to have the strings in the dump
 1401  * be translated, but I'll leave it alone for now.
 1402  */
 1403 
 1404 void
 1405 dump_prog(INSTRUCTION *code)
 1406 {
 1407     time_t now;
 1408 
 1409     (void) time(& now);
 1410     /* \n on purpose, with \n in ctime() output */
 1411     if (do_profile)
 1412         fprintf(prof_fp, _("\t# gawk profile, created %s\n"), ctime(& now));
 1413     print_lib_list(prof_fp);
 1414     pprint(code, NULL, NO_PPRINT_FLAGS);
 1415     print_include_list(prof_fp);
 1416 }
 1417 
 1418 /* prec_level --- return the precedence of an operator, for paren tests */
 1419 
 1420 static int
 1421 prec_level(int type)
 1422 {
 1423     switch (type) {
 1424     case Op_push_lhs:
 1425     case Op_push_param:
 1426     case Op_push_array:
 1427     case Op_push:
 1428     case Op_push_i:
 1429     case Op_push_re:
 1430     case Op_match_rec:
 1431     case Op_subscript:
 1432     case Op_subscript_lhs:
 1433     case Op_func_call:
 1434     case Op_K_delete_loop:
 1435     case Op_builtin:
 1436         return 16;
 1437 
 1438     case Op_field_spec:
 1439     case Op_field_spec_lhs:
 1440         return 15;
 1441 
 1442     case Op_preincrement:
 1443     case Op_predecrement:
 1444     case Op_postincrement:
 1445     case Op_postdecrement:
 1446         return 14;
 1447 
 1448     case Op_exp:
 1449     case Op_exp_i:
 1450         return 13;
 1451 
 1452     case Op_unary_minus:
 1453     case Op_unary_plus:
 1454     case Op_not:
 1455         return 12;
 1456 
 1457     case Op_times:
 1458     case Op_times_i:
 1459     case Op_quotient:
 1460     case Op_quotient_i:
 1461     case Op_mod:
 1462     case Op_mod_i:
 1463         return 11;
 1464 
 1465     case Op_plus:
 1466     case Op_plus_i:
 1467     case Op_minus:
 1468     case Op_minus_i:
 1469         return 10;
 1470 
 1471     case Op_concat:
 1472     case Op_assign_concat:
 1473         return 9;
 1474 
 1475     case Op_equal:
 1476     case Op_notequal:
 1477     case Op_greater:
 1478     case Op_less:
 1479     case Op_leq:
 1480     case Op_geq:
 1481         return 8;
 1482 
 1483     case Op_match:
 1484     case Op_nomatch:
 1485         return 7;
 1486 
 1487     case Op_K_getline:
 1488     case Op_K_getline_redir:
 1489         return 6;
 1490 
 1491     case Op_in_array:
 1492         return 5;
 1493 
 1494     case Op_and:
 1495         return 4;
 1496 
 1497     case Op_or:
 1498         return 3;
 1499 
 1500     case Op_cond_exp:
 1501         return 2;
 1502 
 1503     case Op_assign:
 1504     case Op_assign_times:
 1505     case Op_assign_quotient:
 1506     case Op_assign_mod:
 1507     case Op_assign_plus:
 1508     case Op_assign_minus:
 1509     case Op_assign_exp:
 1510         return 1;
 1511 
 1512     default:
 1513         return 0;
 1514     }
 1515 }
 1516 
 1517 /* is_scalar --- return true if scalar, false otherwise */
 1518 
 1519 static bool
 1520 is_scalar(int type)
 1521 {
 1522     switch (type) {
 1523     case Op_push_lhs:
 1524     case Op_push_param:
 1525     case Op_push_array:
 1526     case Op_push:
 1527     case Op_push_i:
 1528     case Op_push_re:
 1529     case Op_subscript:
 1530     case Op_subscript_lhs:
 1531     case Op_func_call:
 1532     case Op_builtin:
 1533     case Op_field_spec:
 1534     case Op_field_spec_lhs:
 1535     case Op_preincrement:
 1536     case Op_predecrement:
 1537     case Op_postincrement:
 1538     case Op_postdecrement:
 1539     case Op_unary_minus:
 1540     case Op_unary_plus:
 1541     case Op_not:
 1542         return true;
 1543 
 1544     default:
 1545         return false;
 1546     }
 1547 }
 1548 
 1549 /* is_binary --- return true if type represents a binary operator */
 1550 
 1551 static bool
 1552 is_binary(int type)
 1553 {
 1554     switch (type) {
 1555     case Op_geq:
 1556     case Op_leq:
 1557     case Op_greater:
 1558     case Op_less:
 1559     case Op_notequal:
 1560     case Op_equal:
 1561     case Op_exp:
 1562     case Op_times:
 1563     case Op_quotient:
 1564     case Op_mod:
 1565     case Op_plus:
 1566     case Op_minus:
 1567     case Op_exp_i:
 1568     case Op_times_i:
 1569     case Op_quotient_i:
 1570     case Op_mod_i:
 1571     case Op_plus_i:
 1572     case Op_minus_i:
 1573     case Op_concat:
 1574     case Op_assign_concat:
 1575     case Op_match:
 1576     case Op_nomatch:
 1577     case Op_assign:
 1578     case Op_assign_times:
 1579     case Op_assign_quotient:
 1580     case Op_assign_mod:
 1581     case Op_assign_plus:
 1582     case Op_assign_minus:
 1583     case Op_assign_exp:
 1584     case Op_cond_exp:
 1585     case Op_and:
 1586     case Op_or:
 1587     case Op_in_array:
 1588     case Op_K_getline_redir:    /* sometimes */
 1589     case Op_K_getline:
 1590         return true;
 1591 
 1592     default:
 1593         return false;
 1594     }
 1595 }
 1596 
 1597 /* pp_parenthesize --- parenthesize an expression in stack */
 1598 
 1599 static void
 1600 pp_parenthesize(NODE *sp)
 1601 {
 1602     char *p = sp->pp_str;
 1603     size_t len = sp->pp_len;
 1604 
 1605     if (p[0] == '(')    // already parenthesized
 1606         return;
 1607 
 1608     emalloc(p, char *, len + 3, "pp_parenthesize");
 1609     *p = '(';
 1610     memcpy(p + 1, sp->pp_str, len);
 1611     p[len + 1] = ')';
 1612     p[len + 2] = '\0';
 1613     if ((sp->flags & CAN_FREE) != 0)
 1614         efree(sp->pp_str);
 1615     sp->pp_str = p;
 1616     sp->pp_len += 2;
 1617     sp->flags |= CAN_FREE;
 1618 }
 1619 
 1620 /* parenthesize --- parenthesize two nodes relative to parent node type */
 1621 
 1622 static void
 1623 parenthesize(int type, NODE *left, NODE *right)
 1624 {
 1625     int rprec = prec_level(right->type);
 1626     int lprec = prec_level(left->type);
 1627     int prec = prec_level(type);
 1628 
 1629     if (lprec < prec)
 1630         pp_parenthesize(left);
 1631     if (rprec < prec)
 1632         pp_parenthesize(right);
 1633 }
 1634 
 1635 /* pp_string --- pretty format a string or regular regex constant */
 1636 
 1637 char *
 1638 pp_string(const char *in_str, size_t len, int delim)
 1639 {
 1640     return pp_string_or_typed_regex(in_str, len, delim, false);
 1641 }
 1642 
 1643 /* pp_typed_regex --- pretty format a hard regex constant */
 1644 
 1645 static char *
 1646 pp_typed_regex(const char *in_str, size_t len, int delim)
 1647 {
 1648     return pp_string_or_typed_regex(in_str, len, delim, true);
 1649 }
 1650 
 1651 /* pp_string_or_typed_regex --- pretty format a string, regex, or typed regex constant */
 1652 
 1653 char *
 1654 pp_string_or_typed_regex(const char *in_str, size_t len, int delim, bool typed_regex)
 1655 {
 1656     static char str_escapes[] = "\a\b\f\n\r\t\v\\";
 1657     static char str_printables[] = "abfnrtv\\";
 1658     static char re_escapes[] = "\a\b\f\n\r\t\v";
 1659     static char re_printables[] = "abfnrtv";
 1660     char *escapes;
 1661     char *printables;
 1662     char *cp;
 1663     int i;
 1664     const unsigned char *str = (const unsigned char *) in_str;
 1665     size_t ofre, osiz;
 1666     char *obuf, *obufout;
 1667 
 1668     assert(delim == '"' || delim == '/');
 1669 
 1670     if (delim == '/') {
 1671         escapes = re_escapes;
 1672         printables = re_printables;
 1673     } else {
 1674         escapes = str_escapes;
 1675         printables = str_printables;
 1676     }
 1677 
 1678 /* make space for something l big in the buffer */
 1679 #define chksize(l)  if ((l) > ofre) { \
 1680         long olen = obufout - obuf; \
 1681         erealloc(obuf, char *, osiz * 2, "pp_string"); \
 1682         obufout = obuf + olen; \
 1683         ofre += osiz; \
 1684         osiz *= 2; \
 1685     } ofre -= (l)
 1686 
 1687     /* initial size; 3 for delim + terminating null, 1 for @ */
 1688     osiz = len + 3 + 1 + (typed_regex == true);
 1689     emalloc(obuf, char *, osiz, "pp_string");
 1690     obufout = obuf;
 1691     ofre = osiz - 1;
 1692 
 1693     if (typed_regex)
 1694         *obufout++ = '@';
 1695 
 1696     *obufout++ = delim;
 1697     for (; len > 0; len--, str++) {
 1698         chksize(2);     /* make space for 2 chars */
 1699         if (delim != '/' && *str == delim) {
 1700             *obufout++ = '\\';
 1701             *obufout++ = delim;
 1702         } else if (*str == '\0') {
 1703             *obufout++ = '\\';
 1704             *obufout++ = '0';
 1705             chksize(2); /* need 2 more chars for this case */
 1706             *obufout++ = '0';
 1707             *obufout++ = '0';
 1708         } else if ((cp = strchr(escapes, *str)) != NULL) {
 1709             i = cp - escapes;
 1710             *obufout++ = '\\';
 1711             *obufout++ = printables[i];
 1712         /* NB: Deliberate use of lower-case versions. */
 1713         } else if (isascii(*str) && isprint(*str)) {
 1714             *obufout++ = *str;
 1715             ofre += 1;  /* used 1 less than expected */
 1716         } else {
 1717             size_t len;
 1718 
 1719             chksize(8);     /* total available space is 10 */
 1720 
 1721             sprintf(obufout, "\\%03o", *str & 0xff);
 1722             len = strlen(obufout);
 1723             ofre += (10 - len);  /* adjust free space count */
 1724             obufout += len;
 1725         }
 1726     }
 1727     chksize(2);
 1728     *obufout++ = delim;
 1729     *obufout = '\0';
 1730     return obuf;
 1731 #undef chksize
 1732 }
 1733 
 1734 /* pp_number --- pretty format a number */
 1735 
 1736 char *
 1737 pp_number(NODE *n)
 1738 {
 1739     char *str;
 1740 
 1741     assert((n->flags & NUMCONSTSTR) != 0);
 1742     emalloc(str, char *, n->stlen + 1, "pp_number");
 1743     strcpy(str, n->stptr);
 1744     return str;
 1745 }
 1746 
 1747 /* pp_node --- pretty format a node */
 1748 
 1749 char *
 1750 pp_node(NODE *n)
 1751 {
 1752     if ((n->flags & NUMBER) != 0)
 1753         return pp_number(n);
 1754     return pp_string(n->stptr, n->stlen, '"');
 1755 }
 1756 
 1757 /* pp_list --- pretty print a list, with surrounding characters and separator */
 1758 
 1759 static NODE **pp_args = NULL;
 1760 static int npp_args;
 1761 
 1762 static char *
 1763 pp_list(int nargs, const char *paren, const char *delim)
 1764 {
 1765     NODE *r;
 1766     char *str, *s;
 1767     size_t len;
 1768     size_t delimlen;
 1769     int i;
 1770     INSTRUCTION *comment = NULL;
 1771 
 1772     if (pp_args == NULL) {
 1773         npp_args = nargs;
 1774         emalloc(pp_args, NODE **, (nargs + 2) * sizeof(NODE *), "pp_list");
 1775     } else if (nargs > npp_args) {
 1776         npp_args = nargs;
 1777         erealloc(pp_args, NODE **, (nargs + 2) * sizeof(NODE *), "pp_list");
 1778     }
 1779 
 1780     delimlen = strlen(delim);
 1781     if (nargs == 0)
 1782         len = 2;
 1783     else {
 1784         len = -delimlen;
 1785         for (i = 1; i <= nargs; i++) {
 1786             r = pp_args[i] = pp_pop();
 1787             len += r->pp_len + delimlen;
 1788             if (r->pp_comment != NULL) {
 1789                 comment = (INSTRUCTION *) r->pp_comment;
 1790                 len += comment->memory->stlen + indent_level + 1;   // comment\n ident
 1791             }
 1792         }
 1793         if (paren != NULL) {
 1794             assert(strlen(paren) == 2);
 1795             len += 2;
 1796         }
 1797     }
 1798     comment = NULL;
 1799 
 1800     emalloc(str, char *, len + 1, "pp_list");
 1801     s = str;
 1802     if (paren != NULL)
 1803         *s++ = paren[0];
 1804 
 1805     for (i = nargs; i > 0; i--) {
 1806         // argument
 1807         r = pp_args[i];
 1808         memcpy(s, r->pp_str, r->pp_len);
 1809         s += r->pp_len;
 1810 
 1811         // delimiter
 1812         if (i > 1 && delimlen > 0) {
 1813             memcpy(s, delim, delimlen);
 1814             s += delimlen;
 1815         }
 1816 
 1817         // comment if any
 1818         if (r->pp_comment != NULL) {
 1819             check_indent_level();
 1820             comment = (INSTRUCTION *) r->pp_comment;
 1821             memcpy(s, comment->memory->stptr, comment->memory->stlen);
 1822             s += comment->memory->stlen;
 1823             memcpy(s, tabs, indent_level + 1);
 1824             s += indent_level + 1;
 1825         }
 1826         pp_free(r);
 1827     }
 1828 
 1829     if (paren != NULL)
 1830         *s++ = paren[1];
 1831     *s = '\0';
 1832     return str;
 1833 }
 1834 
 1835 /* is_unary_minus --- return true if string starts with unary minus */
 1836 
 1837 static bool
 1838 is_unary_minus(const char *str)
 1839 {
 1840     return str[0] == '-' && str[1] != '-';
 1841 }
 1842 
 1843 /* pp_concat --- handle concatenation and correct parenthesizing of expressions */
 1844 
 1845 static char *
 1846 pp_concat(int nargs)
 1847 {
 1848     NODE *r;
 1849     char *str, *s;
 1850     size_t len;
 1851     static const size_t delimlen = 1;   /* " " */
 1852     int i;
 1853     int pl_l, pl_r;
 1854 
 1855     if (pp_args == NULL) {
 1856         npp_args = nargs;
 1857         emalloc(pp_args, NODE **, (nargs + 2) * sizeof(NODE *), "pp_concat");
 1858     } else if (nargs > npp_args) {
 1859         npp_args = nargs;
 1860         erealloc(pp_args, NODE **, (nargs + 2) * sizeof(NODE *), "pp_concat");
 1861     }
 1862 
 1863     /*
 1864      * items are on the stack in reverse order that they
 1865      * will be printed so pop them off backwards.
 1866      */
 1867 
 1868     len = -delimlen;
 1869     for (i = nargs; i >= 1; i--) {
 1870         r = pp_args[i] = pp_pop();
 1871         len += r->pp_len + delimlen + 2;
 1872     }
 1873 
 1874     emalloc(str, char *, len + 1, "pp_concat");
 1875     s = str;
 1876 
 1877     /* now copy in */
 1878     for (i = 1; i < nargs; i++) {
 1879         r = pp_args[i];
 1880 
 1881         if (r->pp_str[0] != '(') {
 1882             pl_l = prec_level(pp_args[i]->type);
 1883             pl_r = prec_level(pp_args[i+1]->type);
 1884 
 1885             if (i >= 2 && is_unary_minus(r->pp_str)) {
 1886                 *s++ = '(';
 1887                 memcpy(s, r->pp_str, r->pp_len);
 1888                 s += r->pp_len;
 1889                 *s++ = ')';
 1890             } else if (is_scalar(pp_args[i]->type) && is_scalar(pp_args[i+1]->type)) {
 1891                 memcpy(s, r->pp_str, r->pp_len);
 1892                 s += r->pp_len;
 1893             } else if (pl_l <= pl_r || is_scalar(pp_args[i+1]->type)) {
 1894                 *s++ = '(';
 1895                 memcpy(s, r->pp_str, r->pp_len);
 1896                 s += r->pp_len;
 1897                 *s++ = ')';
 1898             } else {
 1899                 memcpy(s, r->pp_str, r->pp_len);
 1900                 s += r->pp_len;
 1901             }
 1902         } else {
 1903             memcpy(s, r->pp_str, r->pp_len);
 1904             s += r->pp_len;
 1905         }
 1906 
 1907         if (i < nargs) {
 1908             *s++ = ' ';
 1909         }
 1910     }
 1911 
 1912     pl_l = prec_level(pp_args[nargs-1]->type);
 1913     pl_r = prec_level(pp_args[nargs]->type);
 1914     r = pp_args[nargs];
 1915     if (r->pp_str[0] == '(') {
 1916         memcpy(s, r->pp_str, r->pp_len);
 1917         s += r->pp_len;
 1918     } else if (is_unary_minus(r->pp_str) || ((pl_l >= pl_r && ! is_scalar(pp_args[nargs]->type)))) {
 1919         *s++ = '(';
 1920         memcpy(s, r->pp_str, r->pp_len);
 1921         s += r->pp_len;
 1922         *s++ = ')';
 1923     } else {
 1924         memcpy(s, r->pp_str, r->pp_len);
 1925         s += r->pp_len;
 1926     }
 1927 
 1928     for (i = nargs; i >= 1; i--) {
 1929         pp_free(pp_args[i]);
 1930     }
 1931 
 1932     *s = '\0';
 1933     return str;
 1934 }
 1935 
 1936 /* pp_group3 --- string together up to 3 strings */
 1937 
 1938 static char *
 1939 pp_group3(const char *s1, const char *s2, const char *s3)
 1940 {
 1941     size_t len1, len2, len3, l;
 1942     char *str, *s;
 1943 
 1944     len1 = strlen(s1);
 1945     len2 = strlen(s2);
 1946     len3 = strlen(s3);
 1947     l = len1 + len2 + len3 + 1;
 1948     emalloc(str, char *, l, "pp_group3");
 1949     s = str;
 1950     if (len1 > 0) {
 1951         memcpy(s, s1, len1);
 1952         s += len1;
 1953     }
 1954     if (len2 > 0) {
 1955         memcpy(s, s2, len2);
 1956         s += len2;
 1957     }
 1958     if (len3 > 0) {
 1959         memcpy(s, s3, len3);
 1960         s += len3;
 1961     }
 1962     *s = '\0';
 1963     return str;
 1964 }
 1965 
 1966 /* pp_func --- pretty print a function */
 1967 
 1968 int
 1969 pp_func(INSTRUCTION *pc, void *data ATTRIBUTE_UNUSED)
 1970 {
 1971     int j;
 1972     static bool first = true;
 1973     NODE *func;
 1974     int pcount;
 1975     INSTRUCTION *fp;
 1976 
 1977     if (first) {
 1978         first = false;
 1979         if (do_profile)
 1980             fprintf(prof_fp, _("\n\t# Functions, listed alphabetically\n"));
 1981     }
 1982 
 1983     pp_namespace_list(pc[3].nexti);
 1984 
 1985     fp = pc->nexti->nexti;
 1986     func = pc->func_body;
 1987     fprintf(prof_fp, "\n");
 1988 
 1989     /* print any function comment */
 1990     if (pc->comment != NULL)
 1991         print_comment(pc->comment, -1); /* -1 ==> don't indent */
 1992 
 1993     indent(pc->nexti->exec_count);
 1994     
 1995     bool malloced = false;
 1996     char *name = adjust_namespace(func->vname, & malloced);
 1997     fprintf(prof_fp, "%s %s(", op2str(Op_K_function), name);
 1998     if (malloced)
 1999         free(name);
 2000     pcount = func->param_cnt;
 2001     func_params = func->fparms;
 2002     for (j = 0; j < pcount; j++) {
 2003         fprintf(prof_fp, "%s", func_params[j].param);
 2004         if (j < pcount - 1)
 2005             fprintf(prof_fp, ", ");
 2006     }
 2007     if (fp->opcode == Op_comment
 2008         && fp->memory->comment_type == EOL_COMMENT) {
 2009         fprintf(prof_fp, ")");
 2010         fp = end_line(fp);
 2011     } else
 2012         fprintf(prof_fp, ")\n");
 2013     if (do_profile)
 2014         indent(0);
 2015     fprintf(prof_fp, "{\n");
 2016     indent_in();
 2017     pprint(fp, NULL, NO_PPRINT_FLAGS);  /* function body */
 2018     indent_out();
 2019     if (do_profile)
 2020         indent(0);
 2021     fprintf(prof_fp, "}\n");
 2022     return 0;
 2023 }
 2024 
 2025 /* redir2str --- convert a redirection type into a printable value */
 2026 
 2027 const char *
 2028 redir2str(int redirtype)
 2029 {
 2030     static const char *const redirtab[] = {
 2031         "",
 2032         " > ",  /* redirect_output */
 2033         " >> ", /* redirect_append */
 2034         " | ",  /* redirect_pipe */
 2035         " | ",  /* redirect_pipein */
 2036         " < ",  /* redirect_input */
 2037         " |& ", /* redirect_twoway */
 2038     };
 2039 
 2040     if (redirtype < 0 || redirtype > redirect_twoway)
 2041         fatal(_("redir2str: unknown redirection type %d"), redirtype);
 2042     return redirtab[redirtype];
 2043 }
 2044 
 2045 /* pp_namespace --- print @namespace directive */
 2046 
 2047 static void
 2048 pp_namespace(const char *name, INSTRUCTION *comment)
 2049 {
 2050     // Don't print the initial `@namespace "awk"' unless
 2051     // @namespace was used at some point in the program
 2052     if (! namespace_changed)
 2053         return;
 2054 
 2055     if (strcmp(current_namespace, name) == 0)
 2056         return;
 2057 
 2058     // don't need to free current_namespace, it comes from
 2059     // info saved in Op_namespace instructions.
 2060     current_namespace = name;
 2061 
 2062     if (do_profile)
 2063         indent(SPACEOVER);
 2064 
 2065     fprintf(prof_fp, "@namespace \"%s\"", name);
 2066 
 2067     if (comment != NULL) {
 2068         putc('\t', prof_fp);
 2069         print_comment(comment, 0);
 2070         putc('\n', prof_fp);
 2071     } else
 2072         fprintf(prof_fp, "\n\n");
 2073 }
 2074 
 2075 /* pp_namespace_list --- print the list, back to front, using recursion */
 2076 
 2077 static void
 2078 pp_namespace_list(INSTRUCTION *list)
 2079 {
 2080     if (list == NULL)
 2081         return;
 2082 
 2083     pp_namespace_list(list->nexti);
 2084     pp_namespace(list->ns_name, list->comment);
 2085 }
 2086 
 2087 /* adjust_namespace --- remove leading namespace or add leading awk:: */
 2088 
 2089 static char *
 2090 adjust_namespace(char *name, bool *malloced)
 2091 {
 2092     *malloced = false;
 2093 
 2094     // unadorned name from symbol table, add awk:: if not in awk:: n.s.
 2095     if (strchr(name, ':') == NULL &&
 2096         current_namespace != awk_namespace &&   // can be equal if namespace never changed
 2097         strcmp(current_namespace, "awk") != 0 &&
 2098         ! is_all_upper(name)) {
 2099         char *buf;
 2100         size_t len = 5 + strlen(name) + 1;
 2101 
 2102         emalloc(buf, char *, len, "adjust_namespace");
 2103         sprintf(buf, "awk::%s", name);
 2104         *malloced = true;
 2105 
 2106         return buf;
 2107     }
 2108 
 2109     // qualifed name, remove <ns>:: if in that n.s.
 2110     size_t len = strlen(current_namespace);
 2111 
 2112     if (strncmp(current_namespace, name, len) == 0) {
 2113         char *ret = name + len + 2;
 2114 
 2115         return ret;
 2116     }
 2117 
 2118     return name;
 2119 }