📄 trerules.c
字号:
temp_call != NULL && strcmp(temp_call->name, last_identifier()) != 0; prev_call = temp_call, temp_call = temp_call->next) ; /* Ignore if have already seen a call to this function. */ if (temp_call == NULL) { CALL *call; if ((call = (CALL *)malloc(sizeof *call)) == NULL) fatal(F_MEMORY); /* Add this call to the call list for the current function definition. */ if (prev_call == NULL) current_function->calls = call; else prev_call->next = call; call->next = NULL; /* Attach buffers containing function name and file name to call structure. */ if ((call->name = (char *)malloc(strlen(last_identifier()) + 1)) == NULL) fatal(F_MEMORY); strcpy(call->name, last_identifier());#if CALL_LOCATION if ((call->file = (char *)malloc(strlen(mod_name()) + 1)) == NULL) fatal(F_MEMORY); strcpy(call->file, mod_name()); /* Line on which call is made. */ call->line = lineno();#endif }}/* Return pointer to root of primary call tree. Order of which function name to use for root: -rfunc, "main", then first function.*/static FUNCTION *get_root(void){ char *root_name; FUNCTION *function; /* If root function name not specified on command line, try "main". */ if ((root_name = str_option(ROOT_FUNC_OPT_CHAR)) == NULL) function = lookup_function(functions, root_name = "main"); else /* If root from cmd line does not exist, print warning and try "main". */ if ((function = lookup_function(functions, root_name)) == NULL) { warn(W_FUNC_NOT_FOUND, root_name, "main"); function = lookup_function(functions, root_name = "main"); } /* If neither root from cmd line or "main" exists, use first function. */ if (function == NULL) { warn(W_FUNC_NOT_FOUND, root_name, functions->name); function = functions; } return function;}/* Print call tree (or subtree) whose root is pointed to by argument. */static void print_calls(FUNCTION *calling){ CALL *call; /* Push this function on call stack in order to be able to detect recursion. */ push_call(calling); /* Print the part of the call tree for this function. */ print_call_line(calling); /* Mark this function definition as being visited so that call trees can be subsequently printed for unvisited functions. */ calling->visited = TRUE; /* Recursively print subtree for each function that is called from within this function. */ for (call = calling->calls; call != NULL; call = call->next) { /* Dummy function structure with no calls for undefined or recursive functions. */ static FUNCTION function = { NULL, NULL, NULL }; FUNCTION *called; /* If function not defined, just print function name (no calls). */ if ((called = lookup_function(functions, call->name)) == NULL) { function.name = call->name; called = &function; print_calls(called); } /* If recursive function call, just print function name with note. */ else if (recursive_call(called)) { function.name = call->name; called = &function; print_calls(called); fprintf(out_fp, " (recursive)"); } else /* Normal case. Recursively print function with any calls. */ print_calls(called); } /* Pop this function from the call stack. */ pop_call();}/* Print the part of the call tree for this function--a single line. In left margin, print file name within which this function is defined. Right justify so that if name is too big for the margin, truncation occurs on the left so that some path information may be lost but the file name is still visible. If no margin at all for printing file name, also do not print spaces between it and the horizontal line made up from characters from the chosen graphical character set. The function name is printed at the end of the line.*/static void print_call_line(FUNCTION *calling){ unsigned file_len; fprintf(out_fp, "\n%*s", file_width, calling->file == NULL ? "" : &calling->file[file_width < (file_len = strlen(calling->file)) ? file_len - file_width : 0]); if (file_width > 0) fprintf(out_fp, " "); print_tree_line(stack); fprintf(out_fp, "%s", calling->name);}/* Print the horizontal line for the function at the top of the call stack. Together, the horizontal lines for each call make up the call tree. The tree is drawn with the graphical characters in turn_char, horz_char, t_char, and vert_char.*/static void print_tree_line(FRAME *frame){ if (frame->next != NULL) { print_tree_line(frame->next); if (frame->last_call) if (stack == frame) print_indent(turn_char, horz_char); else print_indent(' ', ' '); else if (stack == frame) print_indent(t_char, horz_char); else print_indent(vert_char, ' '); }}/* Push function onto call stack. */static void push_call(FUNCTION *function){ FRAME *frame; if ((frame = (FRAME *)malloc(sizeof *frame)) == NULL) fatal(F_MEMORY); frame->function = function; frame->next = stack; stack = frame; /* Is this last call of the function within which this function is called? */ frame->last_call = is_last_call(frame, function->name);}/* Return whether the function whos call is represented by this frame is the last call of the function within which it is called.*/static BOOLEAN is_last_call(FRAME *frame, char *name){ BOOLEAN last_call = FALSE; if (frame->next != NULL) { CALL *call; for (call = frame->next->function->calls; call != NULL && strcmp(call->name, name) != 0; call = call->next) ; if (call == NULL) fatal(F_INTERNAL); if (call->next == NULL) last_call = TRUE; } return last_call;}/* Pop function off of top of call stack. */static void pop_call(void){ FRAME *new_top; if (stack == NULL) fatal(F_INTERNAL); new_top = stack->next; free(stack); stack = new_top;}/* Return whether this function is being called recursively--is already on the call stack.*/static BOOLEAN recursive_call(FUNCTION *function){ FRAME *frame; for (frame = stack; frame != NULL && frame->function != function; frame = frame->next) ; return frame != NULL;}/* Print table of contents containing function definitions, organized by file (module). In comparison with a book's table of contents, a file is a chapter and a function is a heading under that chapter.*/static void print_toc(void){ FUNCTION *function; char *file = ""; fprintf(out_fp, "\n\nTable of Contents\n\n"); for (function = functions; function != NULL; function = function->next) { unsigned i; /* Only print file name if different than last one. */ if (strcmp(file, function->file) != 0) fprintf(out_fp, "%s\n", (file = function->file)); /* Indent function name. */ for (i = 0; i < TOC_INDENT; ++i) fputc(' ', out_fp); fprintf(out_fp, "%s", function->name); /* Print dots between file name and line number. */ print_toc_dots(function->name); fprintf(out_fp, "%6u\n", function->line); }}/* Print dots presumably between function name and line number. */static void print_toc_dots(char *name){ int columns_to_fill; int dot_spaces; unsigned i; columns_to_fill = DOT_SPACES_RIGHT_MARGIN - (TOC_INDENT + strlen(name)); dot_spaces = columns_to_fill / 2; /* Print extra space so that dots for each function line up with each other. */ if (columns_to_fill % 2 == 1) fputc(' ', out_fp); for (i = 0; i < dot_spaces; ++i) fprintf(out_fp, " .");}/* Return how the first string compares with the string where the second argument points.*/static int cmpstr(const char *key, const char * const *element){ return strcmp(key, *element);}/* Return whether the argument is the name of a function in the standard library.*/static BOOLEAN library_call(char *name){ /* (If you add names to this array, insert them alphabetically so that the binary search continues to work correctly.) */ static const char * const library[] = { "abort", "abs", "acos", "asctime", "asin", "assert", "atan", "atan2", "atexit", "atof", "atoi", "atol", "bsearch", "calloc", "ceil", "clearerr", "clock", "cos", "cosh", "ctime", "difftime", "div", "exit", "exp", "fabs", "fclose", "feof", "ferror", "fflush", "fgetc", "fgetpos", "fgets", "floor", "fmod", "fopen", "fprintf", "fputc", "fputs", "fread", "free", "freopen", "frexp", "fscanf", "fseek", "fsetpos", "ftell", "fwrite", "getc", "getchar", "getenv", "gets", "gmtime", "isalnum", "isalpha", "iscntrl", "isdigit", "isgraph", "islower", "isprint", "ispunct", "isspace", "isupper", "isxdigit", "labs", "ldexp", "ldiv", "localeconv", "localtime", "log", "log10", "longjmp", "malloc", "mblen", "mbstowcs", "mbtowc", "memchr", "memcmp", "memcpy", "memmove", "memset", "mktime", "modf", "perror", "pow", "printf", "putc", "putchar", "puts", "qsort", "raise", "rand", "realloc", "remove", "rename", "rewind", "scanf", "setbuf", "setjmp", "setlocale", "setvbuf", "signal", "sin", "sinh", "sprintf", "sqrt", "srand", "sscanf", "strcat", "strchr", "strcmp", "strcoll", "strcpy", "strcspn", "strerror", "strftime", "strlen", "strncat", "strncmp", "strncpy", "strpbrk", "strrchr", "strspn", "strstr", "strtod", "strtok", "strtol", "strtoul", "strxfrm", "system", "tan", "tanh", "time", "tmpfile", "tmpname", "tolower", "toupper", "ungetc", "va_arg", "va_end", "va_start", "vfprintf", "vprintf", "vsprintf", "wcstombs", "wctomb", }; return bsearch(name, library, DIM_OF(library), sizeof library[0], (int (*)(const void *, const void *))cmpstr) != NULL;}/* Print one level of indention for the call tree. The left_most_char is printed followed by N pad_char's, where N is the value of the global variable, indention.*/static void print_indent(int left_most_char, int pad_char){ unsigned i; fputc(left_most_char, out_fp); for (i = 1; i < indention; ++i) fputc(pad_char, out_fp);}/* Return whether the function whos name is the second argument is the name of a function in the linked list whos head is pointed to by the first argument.*/static FUNCTION *lookup_function(FUNCTION *head, char *name){ FUNCTION *function; for (function = head; function != NULL && strcmp(function->name, name) != 0; function = function->next) ; return function;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -