📄 etags.c
字号:
free_tree (node) register NODE *node;{ while (node) { register NODE *node_right = node->right; free_tree (node->left); free (node->name); free (node->pat); free ((char *) node); node = node_right; }}/* * add_node () * Adds a node to the tree of nodes. In etags mode, we don't keep * it sorted; we just keep a linear list. In ctags mode, maintain * an ordered tree, with no attempt at balancing. * * add_node is the only function allowed to add nodes, so it can * maintain state. */voidadd_node (node, cur_node_p) NODE *node, **cur_node_p;{ register int dif; register NODE *cur_node = *cur_node_p; static NODE *last_node = NULL;/* careful */ if (cur_node == NULL) { *cur_node_p = node; last_node = node; return; } if (emacs_tags_format) { /* Etags Mode */ if (!last_node) fatal ("internal error in add_node"); last_node->right = node; last_node = node; } else { /* Ctags Mode */ dif = strcmp (node->name, cur_node->name); /* * If this tag name matches an existing one, then * do not add the node, but maybe print a warning. */ if (!dif) { if (node->file == cur_node->file) { if (!no_warnings) { fprintf (stderr, "Duplicate entry in file %s, line %d: %s\n", node->file, lineno, node->name); fprintf (stderr, "Second entry ignored\n"); } return; } if (!cur_node->been_warned && !no_warnings) { fprintf (stderr, "Duplicate entry in files %s and %s: %s (Warning only)\n", node->file, cur_node->file, node->name); } cur_node->been_warned = TRUE; return; } /* Maybe refuse to add duplicate nodes. */ if (!permit_duplicates) { if (!strcmp (node->name, cur_node->name) && !strcmp (node->file, cur_node->file)) return; } /* Actually add the node */ add_node (node, dif < 0 ? &cur_node->left : &cur_node->right); }}voidput_entries (node) reg NODE *node;{ reg char *sp; if (node == NULL) return; /* Output subentries that precede this one */ put_entries (node->left); /* Output this entry */ if (emacs_tags_format) { if (node->rewritten) { fprintf (outf, "%s\177%s\001%d,%d\n", node->name, node->pat, node->lno, node->cno); } else { fprintf (outf, "%s\177%d,%d\n", node->pat, node->lno, node->cno); } } else if (!cxref_style) { fprintf (outf, "%s\t%s\t", node->name, node->file); if (node->is_func) { /* a function */ putc (searchar, outf); putc ('^', outf); for (sp = node->pat; *sp; sp++) { if (*sp == '\\' || *sp == searchar) putc ('\\', outf); putc (*sp, outf); } putc (searchar, outf); } else { /* a typedef; text pattern inadequate */ fprintf (outf, "%d", node->lno); } putc ('\n', outf); } else if (vgrind_style) fprintf (stdout, "%s %s %d\n", node->name, node->file, (node->lno + 63) / 64); else fprintf (stdout, "%-16s %3d %-16s %s\n", node->name, node->lno, node->file, node->pat); /* Output subentries that follow this one */ put_entries (node->right);}/* Length of a number's decimal representation. */intnumber_len (num) long num;{ int len = 0; if (!num) return 1; for (; num; num /= 10) ++len; return len;}/* * Return total number of characters that put_entries will output for * the nodes in the subtree of the specified node. Works only if emacs_tags_format * is set, but called only in that case. This count is irrelevant with * the new tags.el, but is still supplied for backward compatibility. */inttotal_size_of_entries (node) reg NODE *node;{ reg int total; if (node == NULL) return 0; total = 0; for (; node; node = node->right) { /* Count left subentries. */ total += total_size_of_entries (node->left); /* Count this entry */ total += strlen (node->pat) + 1; total += number_len ((long) node->lno) + 1 + number_len (node->cno) + 1; if (node->rewritten) total += 1 + strlen (node->name); /* \001name */ } return total;}/* * The C symbol tables. */Stab *C_stab, *C_PLPL_stab, *C_STAR_stab;/* * SYNOPSIS * Stab *get_C_stab (int c_ext); */#define get_C_stab(c_ext) ((c_ext&C_STAR) ? C_STAR_stab : \ c_ext ? C_PLPL_stab : \ C_stab)voidadd_keyword (stab, sym, type) Stab *stab; char *sym; enum sym_type type;{ stab_search (stab, sym, strlen (sym))->type = type;}Stab *C_create_stab (c_ext) int c_ext;{ Stab *stab; stab = stab_create (); /* C, C++ and C* */ if (c_ext & C_PLPL) add_keyword (stab, "class", st_C_struct); if (c_ext & C_STAR) add_keyword (stab, "domain", st_C_struct); add_keyword (stab, "union", st_C_struct); add_keyword (stab, "struct", st_C_struct); add_keyword (stab, "enum", st_C_enum); add_keyword (stab, "typedef", st_C_typedef); add_keyword (stab, "define", st_C_define); add_keyword (stab, "long", st_C_typespec); add_keyword (stab, "short", st_C_typespec); add_keyword (stab, "int", st_C_typespec); add_keyword (stab, "char", st_C_typespec); add_keyword (stab, "float", st_C_typespec); add_keyword (stab, "double", st_C_typespec); add_keyword (stab, "signed", st_C_typespec); add_keyword (stab, "unsigned", st_C_typespec); add_keyword (stab, "const", st_C_typespec); add_keyword (stab, "volatile", st_C_typespec); return stab;}voidC_create_stabs (){ C_stab = C_create_stab (0); C_PLPL_stab = C_create_stab (C_PLPL); C_STAR_stab = C_create_stab (C_STAR | C_PLPL);}/* * C_entries () * This routine finds functions and typedefs in C syntax and adds them * to the list. */#define CNL_SAVE_DEFINEDEF \{ \ prev_linepos = linepos; \ SET_FILEPOS (linepos, inf, charno); \ lineno++; \ charno += readline (&lb, inf); \ lp = lb.buffer; \}#define CNL \{ \ CNL_SAVE_DEFINEDEF; \ definedef = dnone; \}voidC_entries (c_ext) int c_ext; /* extension of C? */{ register int c; /* latest char read; '\0' for end of line */ register int tokoff; /* offset in line of beginning of latest token */ register int toklen; /* length of latest token */ register char *lp; /* pointer one beyond the character `c' */ logical incomm, inquote, inchar, midtoken; int level; /* current curly brace level */ char tokb[BUFSIZ]; lineno = 0; charno = 0; lp = lb.buffer; *lp = 0; definedef = dnone; gotone = midtoken = inquote = inchar = incomm = FALSE; level = 0; tydef = none; next_token_is_func = 0; C_create_stabs (); while (!feof (inf)) { c = *lp++; if (c == '\\') { /* If we're at the end of the line, the next character is a '\0'; don't skip it, because it's the thing that tells us to read the next line. */ if (*lp == 0) continue; lp++; c = ' '; } else if (incomm) { if (c == '*' && *lp == '/') { c = *lp++; incomm = FALSE; } } else if (inquote) { if (c == '"') inquote = FALSE; else if (c == '\\') c = *lp++; } else if (inchar) { if (c == '\'') inchar = FALSE; continue; } else switch (c) { case '"': inquote = TRUE; continue; case '\'': inchar = TRUE; continue; case '/': if (*lp == '*') { lp++; incomm = TRUE; } else if (c_ext && *lp == '/') { c = 0; break; } continue; case '#': if (lp == lb.buffer + 1 && definedef == dnone) definedef = dsharpseen; continue; /* * The next two are to help the strucdef state machine. * They break when they are finished, so they don't interfere * with anything else that is going on. */ case ':': if (structdef == stagseen) structdef = scolonseen; break; /* Not a struct definition when semicolon seen in non-sinbody context. */ case ';': if (structdef != snone && structdef != sinbody) { structdef = snone; (void) strcpy (structtag, "<error 1>"); } break; case '{': if (tydef == begin) { tydef = middle; } switch (structdef) { case skeyseen: /* unnamed struct */ structtag[0] = '\0'; /* FALLTHRU */ case stagseen: case scolonseen: /* named struct */ structdef = sinbody; break; } level++; continue; case '}': if (!noindentypedefs && lp == lb.buffer + 1) level = 0; /* reset level if first column */ else if (level > 0) level--; if (level == 0 && tydef == middle) { tydef = end; } if (level == 0) { structdef = snone; (void) strcpy (structtag, "<error 2>"); } continue; } if (LEVEL_OK_FOR_FUNCDEF () && !inquote && !incomm && gotone == FALSE) { if (midtoken) { if (endtoken (c)) { if (c_ext && c == ':' && *lp == ':' && intoken (*(lp + 1))) { /* * This handles :: in the middle, but not at beginning * of an identifier. */ lp += 2; toklen += 3; } else { /* The following is no longer true, now that we advance to the next line at the end of processing the character. */ /* * We've just finished lexing an identifier. * Note that if `c' is '\0', `lb' is the NEXT * line, `lp' points to the beginning of it, and * old pointers into `lb.buffer' may no longer be * valid, since `lb.buffer' may have been * reallocated. In this case (which corresponds * to an identifier followed immediately by a * newline), we re-read the line into lb1. * * This would be faster if the previous line's * buffer were always saved. */ logical is_func; char *tok_linebuf; TOKEN tok; logical bingo, tok_at_end_of_line; char *lp_tmp; /* addressable */#if 0 if (c == '\0') { getline (GET_COOKIE (prev_linepos)); tok_linebuf = lb1.buffer; tok_at_end_of_line = TRUE; tok.linestart = prev_linepos; tok.lineno = lineno - 1; } else#endif { tok_linebuf = lb.buffer; tok_at_end_of_line = FALSE; tok.linestart = linepos; tok.lineno = lineno; } tok.p = tok_linebuf + tokoff; tok.len = toklen; tok.rewritten = FALSE; lp_tmp = lp; bingo = consider_token (c, &lp_tmp, &tok, &is_func, c_ext, level); lp = lp_tmp; if (bingo) { if (GET_CHARNO (tok.linestart) != GET_CHARNO (linepos) && !tok_at_end_of_line) { /* * Resynchronize tok.p to point into the right * linebuffer. */ getline (GET_COOKIE (tok.linestart)); if (!tok.rewritten) tok.p = lb1.buffer + (tok.p - tok_linebuf); tok_linebuf = lb1.buffer; } if (structdef == sinbody && definedef == dnone && is_func) { /* function defined in C++ class body */ sprintf (tokb, "%s::%.*s", structtag[0] == '\0' ? "_anonymous_" : structtag, tok.len, tok.p); tok.rewritten = TRUE; } else { sprintf (tokb, "%.*s", tok.len, tok.p); } pfnote (tokb, is_func, tok.rewritten, tok_linebuf, tokoff + toklen + (tok_at_end_of_line ? 0 : 1), tok.lineno, GET_CHARNO (tok.linestart)); gotone = is_func; /* function */ } midtoken = FALSE; } } else if (intoken (c)) toklen++; } else if (begtoken (c)) { tokoff = lp - 1 - lb.buffer; toklen = 1; midtoken = TRUE; } } /* Detect end of line, after having handled the last token on the line. */ if (c == 0) { CNL; gotone = FALSE; } if (c == ';' && tydef == end) /* clean with typedefs */ tydef = none; }}/* * consider_token () * checks to see if the current token is at the start of a * function, or corresponds to a typedef. It updates the input * line pointer *LPP so that the '(' will be in it when it returns. * * *IS_FUNC gets TRUE iff the token is a function. * C_EXT is which language we are looking at. * * In the future we will need some way to adjust where the end of * the token is; for instance, implementing the C++ keyword * `operator' properly will adjust the end of the token to be after * whatever follows `operator'. * * Globals * structdef IN OUT * definedef IN OUT * tydef IN OUT */logicalconsider_token (c, lpp, tokp, is_func, c_ext, level) reg char c; /* IN: first char after the token */ char **lpp; /* IN OUT: *lpp points to 2nd char after the token */ reg TOKEN *tokp; /* IN */ logical *is_func; /* OUT */ int c_ext; /* IN */ int level; /* IN */{ reg char *lp = *lpp; logical firsttok; /* TRUE if have seen first token in ()'s */ Stab_entry *tokse = stab_find (get_C_stab (c_ext), tokp->p, tokp->len); enum sym_type toktype = stab_type (tokse); *is_func = TRUE; /* a function */ /* * Advance the definedef state machine. We set `gotone' for good measure; * it's redundant. */ switch (definedef)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -