diff options
Diffstat (limited to 'profile.c')
-rw-r--r-- | profile.c | 425 |
1 files changed, 365 insertions, 60 deletions
@@ -3,7 +3,7 @@ */ /* - * Copyright (C) 1999-2017 the Free Software Foundation, Inc. + * Copyright (C) 1999-2018 the Free Software Foundation, Inc. * * This file is part of GAWK, the GNU implementation of the * AWK Programming Language. @@ -37,14 +37,18 @@ static char *pp_typed_regex(const char *in_str, size_t len, int delim); static bool is_binary(int type); static bool is_scalar(int type); static int prec_level(int type); -static void pp_push(int type, char *s, int flag); +static void pp_push(int type, char *s, int flag, INSTRUCTION *comment); static NODE *pp_pop(void); static void print_comment(INSTRUCTION *pc, long in); const char *redir2str(int redirtype); +static void pp_namespace(const char *name, INSTRUCTION *comment); +static void pp_namespace_list(INSTRUCTION *list); +static char *adjust_namespace(char *name, bool *malloced); #define pp_str vname #define pp_len sub.nodep.reserved #define pp_next rnode +#define pp_comment sub.nodep.x.cmnt #define DONT_FREE 1 #define CAN_FREE 2 @@ -60,6 +64,15 @@ static FILE *prof_fp; /* where to send the profile */ static long indent_level = 0; +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"; +static const size_t tabs_len = sizeof(tabs) - 1; + +#define check_indent_level() \ + if (indent_level + 1 > tabs_len) \ + /* We're allowed to be snarky, occasionally. */ \ + fatal(_("Program indentation level too deep. Consider refactoring your code")); + + #define SPACEOVER 0 #define NO_PPRINT_FLAGS 0 @@ -159,7 +172,7 @@ indent_out(void) /* pp_push --- push a pretty printed string onto the stack */ static void -pp_push(int type, char *s, int flag) +pp_push(int type, char *s, int flag, INSTRUCTION *comment) { NODE *n; getnode(n); @@ -168,6 +181,7 @@ pp_push(int type, char *s, int flag) n->flags = flag; n->type = type; n->pp_next = pp_stack; + n->pp_comment = comment; pp_stack = n; } @@ -225,22 +239,29 @@ pprint(INSTRUCTION *startp, INSTRUCTION *endp, int flags) switch (pc->opcode) { case Op_rule: /* - * Rules are three instructions long. + * Rules are four instructions long. * See append_rule in awkgram.y. * The first has the Rule Op Code, nexti etc. * The second, (pc + 1) has firsti and lasti: * the first/last ACTION instructions for this rule. * The third has first_line and last_line: * the first and last source line numbers. + * The fourth holds the namespace name if there is one. + * (there should be one if we're in this file) + * This can actually be a list in reverse order if + * there were several @namespace directives one + * after the other. */ source = pc->source_file; rule = pc->in_rule; + pp_namespace_list(pc[3].nexti); + if (rule != Rule) { /* Allow for pre-non-rule-block comment */ - if (pc->nexti != (pc +1)->firsti + if (pc->nexti != (pc+1)->firsti && pc->nexti->opcode == Op_comment - && pc->nexti->memory->comment_type == FULL_COMMENT) + && pc->nexti->memory->comment_type == BLOCK_COMMENT) print_comment(pc->nexti, -1); ip1 = (pc + 1)->firsti; ip2 = (pc + 1)->lasti; @@ -302,9 +323,9 @@ pprint(INSTRUCTION *startp, INSTRUCTION *endp, int flags) case Op_push_i: m = pc->memory; if (m == Nnull_string) /* optional return or exit value; don't print 0 or "" */ - pp_push(pc->opcode, m->stptr, DONT_FREE); + pp_push(pc->opcode, m->stptr, DONT_FREE, pc->comment); else if ((m->flags & NUMBER) != 0) - pp_push(pc->opcode, pp_number(m), CAN_FREE); + pp_push(pc->opcode, pp_number(m), CAN_FREE, pc->comment); else { str = pp_string(m->stptr, m->stlen, '"'); if ((m->flags & INTLSTR) != 0) { @@ -312,13 +333,13 @@ pprint(INSTRUCTION *startp, INSTRUCTION *endp, int flags) str = pp_group3("_", tmp, ""); efree(tmp); } - pp_push(pc->opcode, str, CAN_FREE); + pp_push(pc->opcode, str, CAN_FREE, pc->comment); } break; case Op_store_var: if (pc->initval != NULL) - pp_push(Op_push_i, pp_node(pc->initval), CAN_FREE); + pp_push(Op_push_i, pp_node(pc->initval), CAN_FREE, pc->comment); /* fall through */ case Op_store_sub: case Op_assign_concat: @@ -331,15 +352,18 @@ pprint(INSTRUCTION *startp, INSTRUCTION *endp, int flags) m = pc->memory; switch (m->type) { case Node_param_list: - pp_push(pc->opcode, func_params[m->param_cnt].param, DONT_FREE); + pp_push(pc->opcode, func_params[m->param_cnt].param, DONT_FREE, pc->comment); break; case Node_var: case Node_var_new: case Node_var_array: - if (m->vname != NULL) - pp_push(pc->opcode, m->vname, DONT_FREE); - else + if (m->vname != NULL) { + bool malloced = false; + char *name = adjust_namespace(m->vname, & malloced); + + pp_push(pc->opcode, name, malloced ? CAN_FREE : DONT_FREE, pc->comment); + } else fatal(_("internal error: %s with null vname"), nodetype2str(m->type)); break; @@ -390,7 +414,7 @@ cleanup: str = pp_group3(t1->pp_str, tmp, ""); efree(tmp); pp_free(t1); - pp_push(pc->opcode, str, CAN_FREE); + pp_push(pc->opcode, str, CAN_FREE, pc->comment); break; case Op_and: @@ -399,10 +423,24 @@ cleanup: t2 = pp_pop(); t1 = pp_pop(); parenthesize(pc->opcode, t1, t2); - str = pp_group3(t1->pp_str, op2str(pc->opcode), t2->pp_str); + if (pc->comment == NULL) + str = pp_group3(t1->pp_str, op2str(pc->opcode), t2->pp_str); + else { + check_indent_level(); + + size_t len = strlen(t1->pp_str) + + strlen(op2str(pc->opcode)) + strlen(t2->pp_str) // foo && bar + + indent_level + 1 // indent + + pc->comment->memory->stlen + 3; // tab comment + + emalloc(str, char *, len, "pprint"); + sprintf(str, "%s%s%s%.*s %s", t1->pp_str, op2str(pc->opcode), + pc->comment->memory->stptr, + (int) (indent_level + 1), tabs, t2->pp_str); + } pp_free(t1); pp_free(t2); - pp_push(pc->opcode, str, CAN_FREE); + pp_push(pc->opcode, str, CAN_FREE, pc->comment); pc = pc->target_jmp; break; @@ -424,14 +462,14 @@ cleanup: str = pp_group3(t1->pp_str, op2str(pc->opcode), tmp); efree(tmp); pp_free(t1); - pp_push(pc->opcode, str, CAN_FREE); + pp_push(pc->opcode, str, CAN_FREE, pc->comment); break; case Op_parens: t1 = pp_pop(); str = pp_group3("(", t1->pp_str, ")"); pp_free(t1); - pp_push(pc->opcode, str, CAN_FREE); + pp_push(pc->opcode, str, CAN_FREE, pc->comment); break; case Op_plus: @@ -452,7 +490,7 @@ cleanup: str = pp_group3(t1->pp_str, op2str(pc->opcode), t2->pp_str); pp_free(t1); pp_free(t2); - pp_push(pc->opcode, str, CAN_FREE); + pp_push(pc->opcode, str, CAN_FREE, pc->comment); break; case Op_preincrement: @@ -465,7 +503,7 @@ cleanup: else str = pp_group3(t1->pp_str, op2str(pc->opcode), ""); pp_free(t1); - pp_push(pc->opcode, str, CAN_FREE); + pp_push(pc->opcode, str, CAN_FREE, pc->comment); break; case Op_field_spec: @@ -483,7 +521,7 @@ cleanup: /* optypes table (eval.c) includes space after ! */ str = pp_group3(op2str(pc->opcode), t1->pp_str, ""); pp_free(t1); - pp_push(pc->opcode, str, CAN_FREE); + pp_push(pc->opcode, str, CAN_FREE, pc->comment); break; case Op_assign: @@ -498,7 +536,7 @@ cleanup: str = pp_group3(t2->pp_str, op2str(pc->opcode), t1->pp_str); pp_free(t2); pp_free(t1); - pp_push(pc->opcode, str, CAN_FREE); + pp_push(pc->opcode, str, CAN_FREE, pc->comment); break; case Op_store_field: @@ -515,7 +553,7 @@ cleanup: case Op_concat: str = pp_concat(pc->expr_count); - pp_push(Op_concat, str, CAN_FREE); + pp_push(Op_concat, str, CAN_FREE, pc->comment); break; case Op_K_delete: @@ -560,7 +598,7 @@ cleanup: pp_free(t2); } pp_free(t1); - pp_push(Op_in_array, str, CAN_FREE); + pp_push(Op_in_array, str, CAN_FREE, pc->comment); } break; @@ -595,7 +633,7 @@ cleanup: tmp = pp_list(pc->expr_count, "()", ", "); str = pp_group3(fname, tmp, ""); efree(tmp); - pp_push(Op_sub_builtin, str, CAN_FREE); + pp_push(Op_sub_builtin, str, CAN_FREE, pc->comment); } break; @@ -603,9 +641,10 @@ cleanup: case Op_ext_builtin: { const char *fname; - if (pc->opcode == Op_builtin) - fname = getfname(pc->builtin); - else + if (pc->opcode == Op_builtin) { + bool prepend_awk = (current_namespace != awk_namespace && strcmp(current_namespace, "awk") != 0); + fname = getfname(pc->builtin, prepend_awk); + } else fname = (pc + 1)->func_name; if (fname != NULL) { if (pc->expr_count > 0) { @@ -614,7 +653,7 @@ cleanup: efree(tmp); } else str = pp_group3(fname, "()", ""); - pp_push(Op_builtin, str, CAN_FREE); + pp_push(Op_builtin, str, CAN_FREE, pc->comment); } else fatal(_("internal error: builtin with null fname")); } @@ -624,7 +663,8 @@ cleanup: case Op_K_printf: case Op_K_print_rec: if (pc->opcode == Op_K_print_rec) - tmp = pp_group3(" ", op2str(Op_field_spec), "0"); + // instead of `print $0', just `print' + tmp = strdup(""); else if (pc->redir_type != 0) tmp = pp_list(pc->expr_count, "()", ", "); else { @@ -660,7 +700,7 @@ cleanup: assert((pc->memory->flags & REGEX) != 0); str = pp_typed_regex(pc->memory->stptr, pc->memory->stlen, '/'); } - pp_push(pc->opcode, str, CAN_FREE); + pp_push(pc->opcode, str, CAN_FREE, pc->comment); } break; @@ -692,7 +732,7 @@ cleanup: efree(restr); } pp_free(t1); - pp_push(pc->opcode, str, CAN_FREE); + pp_push(pc->opcode, str, CAN_FREE, pc->comment); } break; @@ -720,15 +760,16 @@ cleanup: pp_free(t2); } else str = tmp; - pp_push(pc->opcode, str, CAN_FREE); + pp_push(pc->opcode, str, CAN_FREE, pc->comment); break; case Op_indirect_func_call: case Op_func_call: { - char *fname = pc->func_name; char *pre; int pcount; + bool malloced = false; + char *fname = adjust_namespace(pc->func_name, & malloced); if (pc->opcode == Op_indirect_func_call) pre = "@"; @@ -745,7 +786,10 @@ cleanup: t1 = pp_pop(); /* indirect var */ pp_free(t1); } - pp_push(pc->opcode, str, CAN_FREE); + + pp_push(pc->opcode, str, CAN_FREE, pc->comment); + if (malloced) + efree((void *) fname); } break; @@ -786,7 +830,7 @@ cleanup: str = pp_group3(t1->pp_str, ", ", t2->pp_str); pp_free(t1); pp_free(t2); - pp_push(Op_line_range, str, CAN_FREE); + pp_push(Op_line_range, str, CAN_FREE, pc->comment); pc = ip1->condpair_right; break; @@ -820,13 +864,34 @@ cleanup: indent(SPACEOVER); t1 = pp_pop(); fprintf(prof_fp, "} %s (%s)", op2str(Op_K_while), t1->pp_str); + if (pc->comment) + fprintf(prof_fp, "\t%s", pc->comment->memory->stptr); + else { + end_line(pc->target_break); + skip_comment = true; + } pp_free(t1); - end_line(pc->target_break); - skip_comment = true; pc = pc->target_break; break; case Op_K_for: + { + INSTRUCTION *comment1 = NULL, *comment2 = NULL; + + if (pc->comment != NULL) { + comment1 = pc->comment; + pc->comment = NULL; + if (comment1 != NULL && comment1->comment != NULL) { + comment2 = comment1->comment; + comment1->comment = NULL; + } + if (comment2 == NULL && comment1->memory->comment_type == FOR_COMMENT) { + comment2 = comment1; + comment2->memory->comment_type = EOL_COMMENT; + comment1 = NULL; + } + } + ip1 = pc + 1; indent(ip1->forloop_body->exec_count); fprintf(prof_fp, "%s (", op2str(pc->opcode)); @@ -834,12 +899,19 @@ cleanup: /* If empty for looop header, print it a little more nicely. */ if ( pc->nexti->opcode == Op_no_op && ip1->forloop_cond == pc->nexti - && pc->target_continue->opcode == Op_jmp) { + && pc->target_continue->opcode == Op_jmp + && comment1 == NULL && comment2 == NULL) { fprintf(prof_fp, ";;"); } else { pprint(pc->nexti, ip1->forloop_cond, IN_FOR_HEADER); fprintf(prof_fp, "; "); + if (comment1 != NULL) { + print_comment(comment1, 0); + indent(ip1->forloop_body->exec_count); + indent(1); + } + if (ip1->forloop_cond->opcode == Op_no_op && ip1->forloop_cond->nexti == ip1->forloop_body) fprintf(prof_fp, "; "); @@ -850,6 +922,12 @@ cleanup: pp_free(t1); } + if (comment2 != NULL) { + print_comment(comment2, 0); + indent(ip1->forloop_body->exec_count); + indent(1); + } + pprint(pc->target_continue, pc->target_break, IN_FOR_HEADER); } fprintf(prof_fp, ") {"); @@ -863,6 +941,7 @@ cleanup: end_line(pc->target_break); skip_comment = true; pc = pc->target_break; + } break; case Op_K_arrayfor: @@ -901,10 +980,14 @@ cleanup: pprint(pc->nexti, ip1->switch_start, NO_PPRINT_FLAGS); t1 = pp_pop(); fprintf(prof_fp, "%s) {\n", t1->pp_str); + if (pc->comment) + print_comment(pc->comment, 0); pp_free(t1); pprint(ip1->switch_start, ip1->switch_end, NO_PPRINT_FLAGS); indent(SPACEOVER); fprintf(prof_fp, "}\n"); + if (ip1->switch_end->comment) + print_comment(ip1->switch_end->comment, 0); pc = pc->target_break; break; @@ -914,13 +997,20 @@ cleanup: if (pc->opcode == Op_K_case) { t1 = pp_pop(); fprintf(prof_fp, "%s %s:", op2str(pc->opcode), t1->pp_str); - pc = end_line(pc); pp_free(t1); - } else { + } else fprintf(prof_fp, "%s:", op2str(pc->opcode)); - pc = end_line(pc); - } + indent_in(); + if (pc->comment != NULL) { + if (pc->comment->memory->comment_type == EOL_COMMENT) + fprintf(prof_fp, "\t%s", pc->comment->memory->stptr); + else { + fprintf(prof_fp, "\n"); + print_comment(pc->comment, indent_level); + } + } else + fprintf(prof_fp, "\n"); pprint(pc->stmt_start->nexti, pc->stmt_end->nexti, NO_PPRINT_FLAGS); indent_out(); break; @@ -937,6 +1027,8 @@ cleanup: fprintf(prof_fp, " # %ld", ip1->exec_count); ip1 = end_line(ip1); indent_in(); + if (pc->comment != NULL) + print_comment(pc->comment, indent_level); pprint(ip1->nexti, pc->branch_else, NO_PPRINT_FLAGS); indent_out(); pc = pc->branch_else; @@ -944,7 +1036,7 @@ cleanup: indent(SPACEOVER); fprintf(prof_fp, "}"); if (pc->nexti->nexti->opcode != Op_comment - || pc->nexti->nexti->memory->comment_type == FULL_COMMENT) + || pc->nexti->nexti->memory->comment_type == BLOCK_COMMENT) fprintf(prof_fp, "\n"); /* else It will be printed at the top. */ @@ -980,6 +1072,8 @@ cleanup: end_line(pc); skip_comment = true; indent_in(); + if (pc->comment != NULL) + print_comment(pc->comment, indent_level); pprint(pc->nexti, pc->branch_end, NO_PPRINT_FLAGS); indent_out(); indent(SPACEOVER); @@ -999,6 +1093,9 @@ cleanup: { NODE *f, *t, *cond; size_t len; + INSTRUCTION *qm_comment = NULL, *colon_comment = NULL; + + qm_comment = pc->comment; pprint(pc->nexti, pc->branch_if, NO_PPRINT_FLAGS); ip1 = pc->branch_if; @@ -1006,6 +1103,7 @@ cleanup: ip1 = pc->branch_else->nexti; pc = ip1->nexti; + colon_comment = pc->comment; assert(pc->opcode == Op_cond_exp); pprint(pc->nexti, pc->branch_end, NO_PPRINT_FLAGS); @@ -1013,14 +1111,77 @@ cleanup: t = pp_pop(); cond = pp_pop(); - len = f->pp_len + t->pp_len + cond->pp_len + 12; - emalloc(str, char *, len, "pprint"); - sprintf(str, "%s ? %s : %s", cond->pp_str, t->pp_str, f->pp_str); + /* + * This stuff handles comments that come after a ?, :, or both. + * Allowing newlines after ? and : is a gawk extension. + * Theoretically this is fragile, since ?: expressions can be nested. + * In practice, it's not, since if there was a comment following ? or : + * in the original code, then it wasn't nested. + */ + + len = f->pp_len + t->pp_len + cond->pp_len + 12; + if (qm_comment == NULL && colon_comment == NULL) { + // easy case + emalloc(str, char *, len, "pprint"); + sprintf(str, "%s ? %s : %s", cond->pp_str, t->pp_str, f->pp_str); + } else if (qm_comment != NULL && colon_comment != NULL) { + check_indent_level(); + len += qm_comment->memory->stlen + // comments + colon_comment->memory->stlen + + 2 * (indent_level + 1) + 3 + // indentation + t->pp_len + 6; + emalloc(str, char *, len, "pprint"); + sprintf(str, + "%s ? %s" // cond ? comment + "%.*s %s" // indent true-part + " : %s" // : comment + "%.*s %s", // indent false-part + cond->pp_str, // condition + qm_comment->memory->stptr, // comment + (int) (indent_level + 1), tabs, // indent + t->pp_str, // true part + colon_comment->memory->stptr, // comment + (int) (indent_level + 1), tabs, // indent + f->pp_str // false part + ); + } else if (qm_comment != NULL) { + check_indent_level(); + len += qm_comment->memory->stlen + // comment + 1 * (indent_level + 1) + 3 + // indentation + t->pp_len + 3; + emalloc(str, char *, len, "pprint"); + sprintf(str, + "%s ? %s" // cond ? comment + "%.*s %s" // indent true-part + " : %s", // : false-part + cond->pp_str, // condition + qm_comment->memory->stptr, // comment + (int) (indent_level + 1), tabs, // indent + t->pp_str, // true part + f->pp_str // false part + ); + } else { + check_indent_level(); + len += colon_comment->memory->stlen + // comment + 1 * (indent_level + 1) + 3 + // indentation + t->pp_len + 3; + emalloc(str, char *, len, "pprint"); + sprintf(str, + "%s ? %s" // cond ? true-part + " : %s" // : comment + "%.*s %s", // indent false-part + cond->pp_str, // condition + t->pp_str, // true part + colon_comment->memory->stptr, // comment + (int) (indent_level + 1), tabs, // indent + f->pp_str // false part + ); + } pp_free(cond); pp_free(t); pp_free(f); - pp_push(Op_cond_exp, str, CAN_FREE); + pp_push(Op_cond_exp, str, CAN_FREE, pc->comment); pc = pc->branch_end; } break; @@ -1065,7 +1226,7 @@ end_line(INSTRUCTION *ip) return ret; } -/* pp_string_fp --- printy print a string to the fp */ +/* pp_string_fp --- pretty print a string to the fp */ /* * This routine concentrates string pretty printing in one place, @@ -1124,17 +1285,59 @@ print_lib_list(FILE *prof_fp) { SRCFILE *s; static bool printed_header = false; + const char *indent = ""; + bool found = false; + + if (do_profile) + indent = "\t"; for (s = srcfiles->next; s != srcfiles; s = s->next) { if (s->stype == SRC_EXTLIB) { + if (do_profile && ! printed_header) { + printed_header = true; + fprintf(prof_fp, _("%s# Loaded extensions (-l and/or @load)\n\n"), indent); + } + found = true; + fprintf(prof_fp, "%s@load \"%s\"", indent, s->src); + if (s->comment != NULL) { + fprintf(prof_fp, "\t"); + print_comment(s->comment, indent_level + 1); + } else + fprintf(prof_fp, "\n"); + } + } + if (found) /* we found some */ + fprintf(prof_fp, "\n"); +} + +/* print_include_list --- print a list of all files included */ + +static void +print_include_list(FILE *prof_fp) +{ + SRCFILE *s; + static bool printed_header = false; + bool found = false; + + if (do_profile) + return; + + for (s = srcfiles->next; s != srcfiles; s = s->next) { + if (s->stype == SRC_INC) { if (! printed_header) { printed_header = true; - fprintf(prof_fp, _("\t# Loaded extensions (-l and/or @load)\n\n")); + fprintf(prof_fp, _("\n# Included files (-i and/or @include)\n\n")); } - fprintf(prof_fp, "\t@load \"%s\"\n", s->src); + found = true; + fprintf(prof_fp, "# @include \"%s\"", s->src); + if (s->comment != NULL) { + fprintf(prof_fp, "\t"); + print_comment(s->comment, indent_level + 1); + } else + fprintf(prof_fp, "\n"); } } - if (printed_header) /* we found some */ + if (found) /* we found some */ fprintf(prof_fp, "\n"); } @@ -1158,8 +1361,17 @@ print_comment(INSTRUCTION* pc, long in) after_newline = false; } putc(*text, prof_fp); - if (*text == '\n') - after_newline = true; + after_newline = (*text == '\n'); + } + + if (pc->comment) { + // chaining should only be two deep + assert(pc->comment->comment == NULL); + // if first was EOL comment, next must be block comment, + // it needs to be indented. + if (pc->memory->comment_type == EOL_COMMENT) + in++; + print_comment(pc->comment, in); } } @@ -1181,6 +1393,7 @@ dump_prog(INSTRUCTION *code) fprintf(prof_fp, _("\t# gawk profile, created %s\n"), ctime(& now)); print_lib_list(prof_fp); pprint(code, NULL, NO_PPRINT_FLAGS); + print_include_list(prof_fp); } /* prec_level --- return the precedence of an operator, for paren tests */ @@ -1535,6 +1748,7 @@ pp_list(int nargs, const char *paren, const char *delim) size_t len; size_t delimlen; int i; + INSTRUCTION *comment = NULL; if (pp_args == NULL) { npp_args = nargs; @@ -1552,12 +1766,17 @@ pp_list(int nargs, const char *paren, const char *delim) for (i = 1; i <= nargs; i++) { r = pp_args[i] = pp_pop(); len += r->pp_len + delimlen; + if (r->pp_comment != NULL) { + comment = (INSTRUCTION *) r->pp_comment; + len += comment->memory->stlen + indent_level + 1; // comment\n ident + } } if (paren != NULL) { assert(strlen(paren) == 2); len += 2; } } + comment = NULL; emalloc(str, char *, len + 1, "pp_list"); s = str; @@ -1573,6 +1792,14 @@ pp_list(int nargs, const char *paren, const char *delim) memcpy(s, delim, delimlen); s += delimlen; } + if (r->pp_comment != NULL) { + check_indent_level(); + comment = (INSTRUCTION *) r->pp_comment; + memcpy(s, comment->memory->stptr, comment->memory->stlen); + s += comment->memory->stlen; + memcpy(s, tabs, indent_level + 1); + s += indent_level + 1; + } r = pp_args[i]; memcpy(s, r->pp_str, r->pp_len); s += r->pp_len; @@ -1731,18 +1958,23 @@ pp_func(INSTRUCTION *pc, void *data ATTRIBUTE_UNUSED) fprintf(prof_fp, _("\n\t# Functions, listed alphabetically\n")); } + pp_namespace_list(pc[3].nexti); + fp = pc->nexti->nexti; func = pc->func_body; fprintf(prof_fp, "\n"); /* print any function comment */ - if (fp->opcode == Op_comment && fp->source_line == 0) { - print_comment(fp, -1); /* -1 ==> don't indent */ - fp = fp->nexti; - } + if (pc->comment != NULL) + print_comment(pc->comment, -1); /* -1 ==> don't indent */ indent(pc->nexti->exec_count); - fprintf(prof_fp, "%s %s(", op2str(Op_K_function), func->vname); + + bool malloced = false; + char *name = adjust_namespace(func->vname, & malloced); + fprintf(prof_fp, "%s %s(", op2str(Op_K_function), name); + if (malloced) + free(name); pcount = func->param_cnt; func_params = func->fparms; for (j = 0; j < pcount; j++) { @@ -1787,3 +2019,76 @@ redir2str(int redirtype) fatal(_("redir2str: unknown redirection type %d"), redirtype); return redirtab[redirtype]; } + +/* pp_namespace --- print @namespace directive */ + +static void +pp_namespace(const char *name, INSTRUCTION *comment) +{ + // Don't print the initial `@namespace "awk"' unless + // @namespace was used at some point in the program + if (! namespace_changed) + return; + + if (strcmp(current_namespace, name) == 0) + return; + + current_namespace = name; + + if (do_profile) + indent(SPACEOVER); + + fprintf(prof_fp, "@namespace \"%s\"", name); + + if (comment != NULL) { + putc('\t', prof_fp); + print_comment(comment, 0); + putc('\n', prof_fp); + } else + fprintf(prof_fp, "\n\n"); +} + +/* pp_namespace_list --- print the list, back to front, using recursion */ + +static void +pp_namespace_list(INSTRUCTION *list) +{ + if (list == NULL) + return; + + pp_namespace_list(list->nexti); + pp_namespace(list->ns_name, list->comment); +} + +/* adjust_namespace --- remove leading namespace or add leading awk:: */ + +static char * +adjust_namespace(char *name, bool *malloced) +{ + *malloced = false; + + // unadorned name from symbol table, add awk:: if not in awk:: n.s. + if (strchr(name, ':') == NULL && + current_namespace != awk_namespace && // can be equal if namespace never changed + strcmp(current_namespace, "awk") != 0) { + char *buf; + size_t len = 5 + strlen(name) + 1; + + emalloc(buf, char *, len, "adjust_namespace"); + sprintf(buf, "awk::%s", name); + *malloced = true; + + return buf; + } + + // qualifed name, remove <ns>:: if in that n.s. + size_t len = strlen(current_namespace); + + if (strncmp(current_namespace, name, len) == 0) { + char *ret = name + len + 2; + + return ret; + } + + return name; +} |