📄 etags.c
字号:
a tag, one should also consult the tags file FILE after\n\ checking the current file.");#endif#ifdef CTAGS puts ("-B, --backward-search\n\ Write the search commands for the tag entries using '?', the\n\ backward-search command.\n\-F, --forward-search\n\ Write the search commands for the tag entries using '/', the\n\ forward-search command.\n\-u, --update\n\ Update the tag entries for the given files, leaving tag\n\ entries for other files in place. Currently, this is\n\ implemented by deleting the existing entries for the given\n\ files and then rewriting the new entries at the end of the\n\ tags file. It is often faster to simply rebuild the entire\n\ tag file than to use this.\n\-v, --vgrind\n\ Generates an index of items intended for human consumption,\n\ similar to the output of vgrind. The index is sorted, and\n\ gives the page number of each item.\n\-x, --cxref\n\ Like --vgrind, but in the style of cxref, rather than vgrind.\n\ The output uses line numbers instead of page numbers, but\n\ beyond that the differences are cosmetic; try both to see\n\ which you like.\n\-w, --no-warn\n\ Suppress warning messages about entries defined in multiple\n\ files.");#endif puts ("-V, --version\n\ Print the version of the program.\n\-H, --help\n\ Print this help message."); exit (0);}voidmain (argc, argv) int argc; char *argv[];{ char cmd[100]; int i; unsigned int nincluded_files = 0; char **included_files = (char **) alloca (argc * sizeof (char *)); char *this_file;#ifdef VMS char got_err; extern char *gfnames (); extern char *massage_name ();#endif progname = argv[0];#ifndef CTAGS emacs_tags_format = 1;#else emacs_tags_format = 0;#endif /* * If etags, always find typedefs and structure tags. Why not? * Also default is to find macro constants. */ if (emacs_tags_format) typedefs = typedefs_and_cplusplus = constantypedefs = 1; for (;;) { int opt; opt = getopt_long (argc, argv, "aCdDo:StTi:BFuvxwVH", longopts, 0); if (opt == EOF) break; switch (opt) { case '\0': /* If getopt returns '\0', then it has already processed a long-named option. We should do nothing. */ break; /* Common options. */ case 'a': append_to_tagfile++; break; case 'C': cplusplus = 1; break; case 'd': constantypedefs = 1; break; case 'D': constantypedefs = 0; break; case 'o': if (outfile) { fprintf (stderr, "%s: -o flag may only be given once\n", progname); goto usage; } outfile = optarg; break; case 'S': noindentypedefs++; break; case 't': typedefs++; break; case 'T': typedefs++; typedefs_and_cplusplus++; break; case 'V': print_version (); break; case 'H': print_help (); break; /* Etags options */ case 'i': if (!emacs_tags_format) goto usage; included_files[nincluded_files++] = optarg; break; /* Ctags options. */ case 'B': searchar = '?'; if (emacs_tags_format) goto usage; break; case 'F': searchar = '/'; if (emacs_tags_format) goto usage; break; case 'u': update++; if (emacs_tags_format) goto usage; break; case 'v': vgrind_style++; /*FALLTHRU*/ case 'x': cxref_style++; if (emacs_tags_format) goto usage; break; case 'w': no_warnings++; if (emacs_tags_format) goto usage; break; default: goto usage; } } if (optind == argc) { fprintf (stderr, "%s: No input files specified.\n", progname); usage: fprintf (stderr, "%s: Try '%s --help' for a complete list of options.\n", progname, progname); exit (BAD); } if (outfile == 0) { outfile = emacs_tags_format ? "TAGS" : "tags"; } init (); /* set up boolean "functions" */ initbuffer (&lb); initbuffer (&lb1); initbuffer (&filename_lb); /* * loop through files finding functions */ if (emacs_tags_format) { if (streq (outfile, "-")) outf = stdout; else outf = fopen (outfile, append_to_tagfile ? "a" : "w"); if (!outf) { perror (outfile); exit (1); } }#ifdef VMS argc -= optind; argv += optind; while (gfnames (&argc, &argv, &got_err) != NULL) { if (got_err) { error ("Can't find file %s\n", this_file); argc--, argv++; } else { this_file = massage_name (this_file);#if 0 } } /* solely to balance out the ifdef'd parens above */#endif#else for (; optind < argc; optind++) { this_file = argv[optind]; if (1) {#endif /* Input file named "-" means read file names from stdin and use them. */ if (streq (this_file, "-")) { while (!feof (stdin)) { (void) readline (&filename_lb, stdin); if (strlen (filename_lb.buffer) > 0) process_file (filename_lb.buffer); } } else process_file (this_file); } } if (emacs_tags_format) { while (nincluded_files-- > 0) fprintf (outf, "\f\n%s,include\n", *included_files++); (void) fclose (outf); exit (0); } if (cxref_style) { put_entries (head); exit (GOOD); } if (update) { /* update cannot be set under VMS, so we may assume that argc and argv have not been munged. */ for (i = optind; i < argc; i++) { sprintf (cmd, "mv %s OTAGS;fgrep -v '\t%s\t' OTAGS >%s;rm OTAGS", outfile, argv[i], outfile); (void) system (cmd); } append_to_tagfile++; } outf = fopen (outfile, append_to_tagfile ? "a" : "w"); if (outf == NULL) { perror (outfile); exit (GOOD); } put_entries (head); (void) fclose (outf); if (update) { sprintf (cmd, "sort %s -o %s", outfile, outfile); (void) system (cmd); } exit (GOOD);}/* * This routine is called on each file argument. */voidprocess_file (file) char *file;{ struct stat stat_buf; stat (file, &stat_buf);#ifndef S_ISREG#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)#endif#if !defined(S_ISLNK) && defined(S_IFLNK)#define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)#endif if (!S_ISREG(stat_buf.st_mode)#ifdef S_ISLNK && !S_ISLNK(stat_buf.st_mode)#endif ) { fprintf (stderr, "Skipping %s: it is not a regular file.\n", file); return; } if (streq (file, outfile) && !streq (outfile, "-")) { fprintf (stderr, "Skipping inclusion of %s in self.\n", file); return; } if (emacs_tags_format) { char *cp = rindex (file, '/'); if (cp) ++cp; else cp = file; } find_entries (file); if (emacs_tags_format) { fprintf (outf, "\f\n%s,%d\n", file, total_size_of_entries (head)); put_entries (head); free_tree (head); head = NULL; }}/* * This routine sets up the boolean psuedo-functions which work * by seting boolean flags dependent upon the corresponding character * Every char which is NOT in that string is not a white char. Therefore, * all of the array "_wht" is set to FALSE, and then the elements * subscripted by the chars in "white" are set to TRUE. Thus "_wht" * of a char is TRUE if it is the string "white", else FALSE. */voidinit (){ reg char *sp; reg int i; for (i = 0; i < 0177; i++) { _wht[i] = _etk[i] = _itk[i] = _btk[i] = FALSE; _gd[i] = TRUE; } for (sp = white; *sp; sp++) _wht[*sp] = TRUE; for (sp = endtk; *sp; sp++) _etk[*sp] = TRUE; for (sp = intk; *sp; sp++) _itk[*sp] = TRUE; for (sp = begtk; *sp; sp++) _btk[*sp] = TRUE; for (sp = notgd; *sp; sp++) _gd[*sp] = FALSE; _wht[0] = _wht['\n']; _etk[0] = _etk['\n']; _btk[0] = _btk['\n']; _itk[0] = _itk['\n']; _gd[0] = _gd['\n'];}/* * This routine opens the specified file and calls the function * which finds the function and type definitions. */voidfind_entries (file) char *file;{ char *cp; void prolog_funcs (); inf = fopen (file, "r"); if (inf == NULL) { perror (file); return; } curfile = savestr (file); cp = rindex (file, '.'); header_file = (cp && (streq (cp + 1, "h"))); /* .tex, .aux or .bbl implies LaTeX source code */ if (cp && (streq (cp + 1, "tex") || streq (cp + 1, "aux") || streq (cp + 1, "bbl"))) { TEX_funcs (inf); goto close_and_return; } /* .l or .el or .lisp (or .cl or .clisp or ...) implies lisp source code */ if (cp && (streq (cp + 1, "l") || streq (cp + 1, "el") || streq (cp + 1, "lsp") || streq (cp + 1, "lisp") || streq (cp + 1, "cl") || streq (cp + 1, "clisp"))) { L_funcs (inf); goto close_and_return; } /* .scm or .sm or .scheme or ... implies scheme source code */ if (cp && (streq (cp + 1, "sm") || streq (cp + 1, "scm") || streq (cp + 1, "scheme") || streq (cp + 1, "t") || streq (cp + 1, "sch") || streq (cp + 1, "SM") || streq (cp + 1, "SCM") /* The `SCM' or `scm' prefix with a version number */ || (cp[-1] == 'm' && cp[-2] == 'c' && cp[-3] == 's' && string_numeric_p (cp + 1)) || (cp[-1] == 'M' && cp[-2] == 'C' && cp[-3] == 'S' && string_numeric_p (cp + 1)))) { Scheme_funcs (inf); fclose (inf); return; } /* Assume that ".s" or ".a" is assembly code. -wolfgang. */ if (cp && (cp[1] == 's' || cp[1] == 'a') && cp[2] == '\0') { Asm_funcs (inf); fclose (inf); return; } /* .C or .H or .cxx or .hxx or .cc: a C++ file */ if (cp && (streq (cp + 1, "C") || streq (cp + 1, "H") || streq (cp + 1, "cxx") || streq (cp + 1, "hxx") || streq (cp + 1, "cc"))) { C_entries (C_PLPL); /* C++ */ goto close_and_return; } /* .cs or .hs: a C* file */ if (cp && (cp[1] == 'c' || cp[1] == 'h') && cp[2] == 's' && cp[3] == '\0') { C_entries (C_STAR); goto close_and_return; } /* .pl implies prolog source code */ if (cp && !strcmp (cp + 1, "pl")) { prolog_funcs (inf); goto close_and_return; } /* .p or .pas: a Pascal file */ if (cp && (streq (cp + 1, "p") || streq (cp + 1, "pas"))) { PAS_funcs (inf); goto close_and_return; } /* if not a .c or .h or .y file, try fortran */ else if (cp && ((cp[1] != 'c' && cp[1] != 'h' && cp[1] != 'y') || (cp[1] != 0 && cp[2] != 0))) { if (PF_funcs (inf) != 0) goto close_and_return; rewind (inf); /* no fortran tags found, try C */ } C_entries (cplusplus ? C_PLPL : 0);close_and_return: (void) fclose (inf);}/* Nonzero if string STR is composed of digits. */intstring_numeric_p (str) char *str;{ while (*str) { if (*str < '0' || *str > '9') return 0; } return 1;}/* Record a tag. *//* Should take a TOKEN* instead!! */voidpfnote (name, is_func, rewritten, linestart, linelen, lno, cno) char *name; /* tag name */ logical is_func; /* function or type name? */ logical rewritten; /* tag different from text of definition? */ char *linestart; int linelen; int lno; long cno;{ register char *fp; register NODE *np; char tem[51]; char c; np = (NODE *) malloc (sizeof (NODE)); if (np == NULL) { if (!emacs_tags_format) { /* It's okay to output early in etags -- it only disrupts the * character count of the tag entries, which is no longer used * by tags.el anyway. */ error ("too many entries to sort"); } put_entries (head); free_tree (head); head = NULL; np = xnew (1, NODE); } /* If ctags mode, change name "main" to M<thisfilename>. */ if (!emacs_tags_format && !cxref_style && streq (name, "main")) { fp = rindex (curfile, '/'); name = concat ("M", fp == 0 ? curfile : fp + 1, ""); fp = rindex (name, '.'); if (fp && fp[1] != '\0' && fp[2] == '\0') *fp = 0; rewritten = TRUE; } np->name = savestr (name); np->file = curfile; np->is_func = is_func; np->rewritten = rewritten; np->lno = lno; /* UNCOMMENT THE +1 HERE: */ np->cno = cno /* + 1 */ ; /* our char numbers are 0-base; emacs's are 1-base */ np->left = np->right = 0; if (emacs_tags_format) { c = linestart[linelen]; linestart[linelen] = 0; } else if (cxref_style == 0) { sprintf (tem, strlen (linestart) < 50 ? "%s$" : "%.50s", linestart); linestart = tem; } np->pat = savestr (linestart); if (emacs_tags_format) { linestart[linelen] = c; } add_node (np, &head);}/* * free_tree () * recurse on left children, iterate on right children. */void
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -