📄 gtags.c
字号:
if (getconfb("extractmethod")) extractmethod = 1; strbuf_reset(sb); if (cflag == 0 && getconfs("format", sb) && !strcmp(strbuf_value(sb), "compact")) cflag++; /* * Pass the following information to gtags-parser(1) * using environment variable. * * o langmap * o DBPATH */ strbuf_reset(sb); if (getconfs("langmap", sb)) { const char *p = strdup(strbuf_value(sb)); if (p == NULL) die("short of memory."); langmap = p; } set_env("GTAGSLANGMAP", langmap); set_env("GTAGSDBPATH", dbpath); if (wflag) set_env("GTAGSWARNING", "1"); /* * incremental update. */ if (iflag) { /* * Version check. If existing tag files are old enough * gtagsopen() abort with error message. */ GTOP *gtop = gtags_open(dbpath, cwd, GTAGS, GTAGS_MODIFY, 0); gtags_close(gtop); /* * GPATH is needed for incremental updating. * Gtags check whether or not GPATH exist, since it may be * removed by mistake. */ if (!test("f", makepath(dbpath, dbname(GPATH), NULL))) die("Old version tag file found. Please remake it."); (void)incremental(dbpath, cwd); exit(0); } /* * create GTAGS, GRTAGS and GSYMS */ signal_setup(); total = 0; /* counting file */ for (db = GTAGS; db < GTAGLIM; db++) { if (oflag && db == GSYMS) continue; strbuf_reset(sb); /* * get parser for db. (gtags-parser by default) */ if (!getconfs(dbname(db), sb)) continue; if (!usable(strmake(strbuf_value(sb), " \t"))) die("Parser '%s' not found or not executable.", strmake(strbuf_value(sb), " \t")); if (vflag) fprintf(stderr, "[%s] Creating '%s'.\n", now(), dbname(db)); createtags(dbpath, cwd, db); strbuf_reset(sb); if (db == GTAGS) { if (getconfs("GTAGS_extra", sb)) if (system(strbuf_value(sb))) fprintf(stderr, "GTAGS_extra command failed: %s\n", strbuf_value(sb)); } else if (db == GRTAGS) { if (getconfs("GRTAGS_extra", sb)) if (system(strbuf_value(sb))) fprintf(stderr, "GRTAGS_extra command failed: %s\n", strbuf_value(sb)); } else if (db == GSYMS) { if (getconfs("GSYMS_extra", sb)) if (system(strbuf_value(sb))) fprintf(stderr, "GSYMS_extra command failed: %s\n", strbuf_value(sb)); } if (exitflag) exit(1); } /* * create id-utils index. */ if (Iflag) { if (vflag) fprintf(stderr, "[%s] Creating indexes for id-utils.\n", now()); strbuf_reset(sb); strbuf_puts(sb, "mkid"); if (vflag) strbuf_puts(sb, " -v"); if (vflag) {#ifdef __DJGPP__ if (is_unixy()) /* test for 4DOS as well? */#endif strbuf_puts(sb, " 1>&2"); } else { strbuf_puts(sb, " >/dev/null"); } if (debug) fprintf(stderr, "executing mkid like: %s\n", strbuf_value(sb)); if (system(strbuf_value(sb))) die("mkid failed: %s", strbuf_value(sb)); strbuf_reset(sb); strbuf_puts(sb, "chmod 644 "); strbuf_puts(sb, makepath(dbpath, "ID", NULL)); if (system(strbuf_value(sb))) die("chmod failed: %s", strbuf_value(sb)); } if (vflag) fprintf(stderr, "[%s] Done.\n", now()); closeconf(); strbuf_close(sb); return 0;}/* * incremental: incremental update * * i) dbpath dbpath directory * i) root root directory of source tree * r) 0: not updated, 1: updated */intincremental(dbpath, root) const char *dbpath; const char *root;{ struct stat statp; time_t gtags_mtime; STRBUF *addlist = strbuf_open(0); STRBUF *deletelist = strbuf_open(0); IDSET *deleteset; int updated = 0; int addtotal = 0; const char *path; if (vflag) { fprintf(stderr, " Tag found in '%s'.\n", dbpath); fprintf(stderr, " Incremental update.\n"); } /* * get modified time of GTAGS. */ path = makepath(dbpath, dbname(GTAGS), NULL); if (stat(path, &statp) < 0) die("stat failed '%s'.", path); gtags_mtime = statp.st_mtime; if (gpath_open(dbpath, 0) < 0) die("GPATH not found."); deleteset = idset_open(gpath_nextkey()); /* * make add list and update list. */ if (file_list) find_open_filelist(file_list, root); else find_open(NULL); while ((path = find_read()) != NULL) { const char *fid; /* a blank at the head of path means 'NOT SOURCE'. */ if (*path == ' ') continue; if (stat(path, &statp) < 0) die("stat failed '%s'.", path); if ((fid = gpath_path2fid(path)) == NULL) { strbuf_puts0(addlist, path); addtotal++; } else if (gtags_mtime < statp.st_mtime) { strbuf_puts0(addlist, path); addtotal++; idset_add(deleteset, atoi(fid)); } } find_close(); /* * make delete list. */ { char fid[32]; int i, limit = gpath_nextkey(); for (i = 1; i < limit; i++) { snprintf(fid, sizeof(fid), "%d", i); if ((path = gpath_fid2path(fid)) == NULL) continue; if (!test("f", path)) { strbuf_puts0(deletelist, path); idset_add(deleteset, i); } } } gpath_close(); if (strbuf_getlen(addlist) + strbuf_getlen(deletelist)) updated = 1; /* * execute updating. */ signal_setup(); if (updated) { int db; for (db = GTAGS; db < GTAGLIM; db++) { /* * GTAGS needed at least. */ if ((db == GRTAGS || db == GSYMS) && !test("f", makepath(dbpath, dbname(db), NULL))) continue; if (vflag) fprintf(stderr, "[%s] Updating '%s'.\n", now(), dbname(db)); updatetags(dbpath, root, deleteset, addlist, addtotal, db); if (exitflag) exit(1); } } if (strbuf_getlen(deletelist) > 0) { const char *start = strbuf_value(deletelist); const char *end = start + strbuf_getlen(deletelist); const char *p; gpath_open(dbpath, 2); for (p = start; p < end; p += strlen(p) + 1) { if (exitflag) break; gpath_delete(p); } gpath_close(); } if (exitflag) exit(1); if (updated) { int db; /* * Update modification time of tag files * because they may have no definitions. */ for (db = GTAGS; db < GTAGLIM; db++)#ifdef HAVE_UTIMES utimes(makepath(dbpath, dbname(db), NULL), NULL);#else utime(makepath(dbpath, dbname(db), NULL), NULL);#endif /* HAVE_UTIMES */ } if (vflag) { if (updated) fprintf(stderr, " Global databases have been modified.\n"); else fprintf(stderr, " Global databases are up to date.\n"); fprintf(stderr, "[%s] Done.\n", now()); } strbuf_close(addlist); strbuf_close(deletelist); idset_close(deleteset); return updated;}/* * updatetags: update tag file. * * i) dbpath directory in which tag file exist * i) root root directory of source tree * i) deleteset bit array of fid of deleted or modified files * i) addlist \0 separated list of added or modified files * i) addtotal number of files in addlist * i) db GTAGS, GRTAGS, GSYMS */voidupdatetags(dbpath, root, deleteset, addlist, addtotal, db) const char *dbpath; const char *root; IDSET *deleteset; STRBUF *addlist; int addtotal; int db;{ GTOP *gtop; STRBUF *comline = strbuf_open(0); int gflags; int path_list_max; int arg_count = 0; /* * GTAGS needed to make GRTAGS. */ if (db == GRTAGS && !test("f", makepath(dbpath, dbname(GTAGS), NULL))) die("GTAGS needed to create GRTAGS."); /* * get tag command. */ if (!getconfs(dbname(db), comline)) die("cannot get tag command. (%s)", dbname(db)); /* * determine the maximum length of the list of paths. */ path_list_max = exec_line_limit(strbuf_getlen(comline)); gtop = gtags_open(dbpath, root, db, GTAGS_MODIFY, 0); if (vflag) { char fid[32]; const char *path; int seqno = 1; int total = idset_count(deleteset); int i; for (i = 0; i < deleteset->max; i++) { if (idset_contains(deleteset, i)) { snprintf(fid, sizeof(fid), "%d", i); path = gpath_fid2path(fid); if (path == NULL) die("GPATH is corrupted."); fprintf(stderr, " [%d/%d] deleting tags of %s\n", seqno++, total, path + 2); } } } if (deleteset->max > 0) gtags_delete(gtop, deleteset); gflags = 0; if (extractmethod) gflags |= GTAGS_EXTRACTMETHOD; if (debug) gflags |= GTAGS_DEBUG; /* * If the --max-args option is not specified, we pass the parser * the source file as a lot as possible to decrease the invoking * frequency of the parser. */ { STRBUF *path_list = strbuf_open(0); const char *path = strbuf_value(addlist); const char *end = path + strbuf_getlen(addlist); int seqno = 1; while (path < end) { int pathlen = strlen(path); if (vflag) fprintf(stderr, " [%d/%d] adding tags of %s\n", seqno++, addtotal, path + 2); /* * Execute parser when path name collects enough. * Though the path_list is \0 separated list of path, * we can think its length equals to the length of * argument string because each \0 can be replaced * with a blank. */ if (strbuf_getlen(path_list)) { if (path_list_max == 0 || (max_args > 0 && arg_count >= max_args) || strbuf_getlen(path_list) + pathlen > path_list_max) { gtags_add(gtop, strbuf_value(comline), path_list, gflags); strbuf_reset(path_list); arg_count = 0; } } if (exitflag) break; /* * Add a path to the path list. */ strbuf_puts0(path_list, path); path += pathlen + 1; arg_count++; } if (strbuf_getlen(path_list)) gtags_add(gtop, strbuf_value(comline), path_list, gflags); strbuf_close(path_list); } gtags_close(gtop); strbuf_close(comline);}/* * createtags: create tags file * * i) dbpath dbpath directory * i) root root directory of source tree * i) db GTAGS, GRTAGS, GSYMS */voidcreatetags(dbpath, root, db) const char *dbpath; const char *root; int db;{ const char *path; GTOP *gtop; int flags, gflags; STRBUF *comline = strbuf_open(0); int count = 0; int arg_count = 0; STRBUF *path_list = strbuf_open(MAXPATHLEN); int path_list_max; /* * get tag command. */ if (!getconfs(dbname(db), comline)) die("cannot get tag command. (%s)", dbname(db)); /* * GTAGS needed to make GRTAGS. */ if (db == GRTAGS && !test("f", makepath(dbpath, dbname(GTAGS), NULL))) die("GTAGS needed to create GRTAGS."); /* * determine the maximum length of the list of paths. */ path_list_max = exec_line_limit(strbuf_getlen(comline)); flags = 0; /* * Compact format: * * -c: COMPACT format. * -cc: PATHINDEX format. * Ths -cc is undocumented. * In the future, it may become the standard format of GLOBAL. */ if (cflag) { flags |= GTAGS_PATHINDEX; if (cflag == 1) flags |= GTAGS_COMPACT; } if (vflag > 1) fprintf(stderr, " using tag command '%s <path>'.\n", strbuf_value(comline)); gtop = gtags_open(dbpath, root, db, GTAGS_CREATE, flags); gflags = 0; if (extractmethod) gflags |= GTAGS_EXTRACTMETHOD; if (debug) gflags |= GTAGS_DEBUG; /* * If the --max-args option is not specified, we pass the parser * the source file as a lot as possible to decrease the invoking * frequency of the parser. */ if (file_list) find_open_filelist(file_list, root); else find_open(NULL); while ((path = find_read()) != NULL) { int skip = 0; /* a blank at the head of path means 'NOT SOURCE'. */ if (*path == ' ') continue; if (exitflag) break; count++; /* * GSYMS doesn't treat asembler. */ if (db == GSYMS) { if (locatestring(path, ".s", MATCH_AT_LAST) != NULL || locatestring(path, ".S", MATCH_AT_LAST) != NULL) skip = 1; } if (vflag) { if (total) fprintf(stderr, " [%d/%d]", count, total); else fprintf(stderr, " [%d]", count); fprintf(stderr, " extracting tags of %s", path + 2); if (skip) fprintf(stderr, " (skipped)"); fputc('\n', stderr); } if (skip) continue; /* * Execute parser when path name collects enough. * Though the path_list is \0 separated list of string, * we can think its length equals to the length of * argument string because each \0 can be replaced * with a blank. */ if (strbuf_getlen(path_list)) { if (path_list_max == 0 || (max_args > 0 && arg_count >= max_args) || strbuf_getlen(path_list) + strlen(path) > path_list_max) { gtags_add(gtop, strbuf_value(comline), path_list, gflags); strbuf_reset(path_list); arg_count = 0; } } /* * Add a path to path_list. */ strbuf_puts0(path_list, path); arg_count++; } if (strbuf_getlen(path_list)) gtags_add(gtop, strbuf_value(comline), path_list, gflags); total = count; /* save total count */ find_close(); gtags_close(gtop); strbuf_close(comline); strbuf_close(path_list);}/* * printconf: print configuration data. * * i) name label of config data * r) exit code */intprintconf(name) const char *name;{ int num; int exist = 1; if (getconfn(name, &num)) fprintf(stdout, "%d\n", num); else if (getconfb(name)) fprintf(stdout, "1\n"); else { STRBUF *sb = strbuf_open(0); if (getconfs(name, sb)) fprintf(stdout, "%s\n", strbuf_value(sb)); else exist = 0; strbuf_close(sb); } return exist;}/* * put_converting: convert path into relative or absolute and print. * * i) line raw output from global(1) * i) absolute 1: absolute, 0: relative * i) cxref 1: -x format, 0: file name only */static STRBUF *abspath;static char basedir[MAXPATHLEN+1];static int start_point;voidset_base_directory(root, cwd) const char *root; const char *cwd;{ abspath = strbuf_open(MAXPATHLEN); strbuf_puts(abspath, root); strbuf_unputc(abspath, '/'); start_point = strbuf_getlen(abspath); if (strlen(cwd) > MAXPATHLEN) die("current directory name too long."); strlimcpy(basedir, cwd, sizeof(basedir)); /* leave abspath unclosed. */}voidput_converting(line, absolute, cxref) const char *line; int absolute; int cxref;{ char buf[MAXPATHLEN+1]; const char *p = line; /* * print until path name. */ if (cxref) { /* print tag name */ for (; *p && !isspace((unsigned char)*p); p++) (void)putc(*p, stdout); /* print blanks and line number */ for (; *p && *p != '.'; p++) (void)putc(*p, stdout); } if (*p++ == '\0') return; /* * make absolute path. */ strbuf_setlen(abspath, start_point); for (; *p && !isspace((unsigned char)*p); p++) strbuf_putc(abspath, *p); /* * put path with converting. */ if (absolute) { (void)fputs(strbuf_value(abspath), stdout); } else { const char *a = strbuf_value(abspath); const char *b = basedir;#if defined(_WIN32) || defined(__DJGPP__) /* skip drive char in 'c:/usr/bin' */ while (*a != '/') a++; while (*b != '/') b++;#endif if (!abs2rel(a, b, buf, sizeof(buf))) die("abs2rel failed. (path=%s, base=%s).", a, b); (void)fputs(buf, stdout); } /* * print the rest of the record. */ (void)fputs(p, stdout);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -