/** * completion_path: print candidate path list. * * @param[in] dbpath dbpath directory * @param[in] prefix prefix of primary key */ void completion_path(const char *dbpath, const char *prefix) { GFIND *gp; const char *localprefix = "./"; DBOP *dbop = dbop_open(NULL, 1, 0600, DBOP_RAW); const char *path; int prefix_length; int target = GPATH_SOURCE; int flags = (match_part == MATCH_PART_LAST) ? MATCH_LAST : MATCH_FIRST; if (dbop == NULL) die("cannot open temporary file."); if (prefix && *prefix == 0) /* In the case global -c '' */ prefix = NULL; prefix_length = (prefix == NULL) ? 0 : strlen(prefix); if (oflag) target = GPATH_BOTH; if (Oflag) target = GPATH_OTHER; if (iflag || getconfb("icase_path")) flags |= IGNORE_CASE; #if _WIN32 || __DJGPP__ else if (!Mflag) flags |= IGNORE_CASE; #endif gp = gfind_open(dbpath, localprefix, target); while ((path = gfind_read(gp)) != NULL) { path++; /* skip '.'*/ if (prefix == NULL) { dbop_put(dbop, path + 1, ""); } else if (match_part == MATCH_PART_ALL) { const char *p = path; while ((p = locatestring(p, prefix, flags)) != NULL) { dbop_put(dbop, p, ""); p += prefix_length; } } else { const char *p = locatestring(path, prefix, flags); if (p != NULL) { dbop_put(dbop, p, ""); } } } gfind_close(gp); for (path = dbop_first(dbop, NULL, NULL, DBOP_KEY); path != NULL; path = dbop_next(dbop)) { fputs(path, stdout); fputc('\n', stdout); } dbop_close(dbop); }
/** * gfind_open: start iterator using GPATH. * * @param[in] dbpath dbpath * @param[in] local local prefix, * if NULL specified, it assumes "./"; * @param[in] target GPATH_SOURCE: only source file, * GPATH_OTHER: only other file, * GPATH_BOTH: source file + other file * @param[in] flags GPATH_NEARSORT * @return GFIND structure */ GFIND * gfind_open(const char *dbpath, const char *local, int target, int flags) { GFIND *gfind = (GFIND *)check_calloc(sizeof(GFIND), 1); gfind->dbop = dbop_open(makepath(dbpath, dbname(GPATH), NULL), 0, 0, 0); if (gfind->dbop == NULL) die("GPATH not found."); gfind->path = NULL; gfind->prefix = check_strdup(local ? local : "./"); gfind->first = 1; gfind->eod = 0; gfind->target = target; gfind->type = GPATH_SOURCE; gfind->flags = flags; gfind->path_array = NULL; gfind->version = dbop_getversion(gfind->dbop); if (gfind->version > support_version) die("GPATH seems new format. Please install the latest GLOBAL."); else if (gfind->version < support_version) die("GPATH seems older format. Please remake tag files."); /* * Nearness sort. * In fact, this timing of sort is not good for performance. * Reconsideration is needed later. */ if (gfind->flags & GPATH_NEARSORT) { const char *path = NULL; VARRAY *varray = varray_open(sizeof(char *), 100); POOL *pool = pool_open(); while ((path = gfind_read(gfind)) != NULL) { char **a = varray_append(varray); *a = pool_strdup(pool, path, 0); } if ((nearbase = get_nearbase_path()) == NULL) die("cannot get nearbase path."); qsort(varray_assign(varray, 0, 0), varray->length, sizeof(char *), compare_nearpath); gfind->path_array = varray; gfind->pool = pool; gfind->index = 0; } return gfind; }
/** * Tag command that supports referenced tag must call this function * to decide whether or not the tag is defined. */ int defined(const char *name) { if (dbop == NULL) { const char *dbpath; /* * gtags(1) set GTAGSDBPATH to the path GTAGS exist. */ if (!(dbpath = getenv("GTAGSDBPATH"))) dbpath = "."; dbop = dbop_open(makepath(dbpath, "GTAGS", NULL), 0, 0, 0); if (dbop == NULL) die("'GTAGS' not found."); } if (dbop_get(dbop, name)) return 1; return 0; }
/* * gfind_open: start iterator using GPATH. * * i) dbpath dbpath * i) local local prefix * if NULL specified, it assumes "./"; * i) target GPATH_SOURCE: only source file * GPATH_OTHER: only other file * GPATH_BOTH: source file + other file * r) GFIND structure */ GFIND * gfind_open(const char *dbpath, const char *local, int target) { GFIND *gfind = (GFIND *)check_calloc(sizeof(GFIND), 1); gfind->dbop = dbop_open(makepath(dbpath, dbname(GPATH), NULL), 0, 0, 0); if (gfind->dbop == NULL) die("GPATH not found."); gfind->path = NULL; gfind->prefix = check_strdup(local ? local : "./"); gfind->first = 1; gfind->eod = 0; gfind->target = target; gfind->type = GPATH_SOURCE; gfind->version = dbop_getversion(gfind->dbop); if (gfind->version > support_version) die("GPATH seems new format. Please install the latest GLOBAL."); else if (gfind->version < support_version) die("GPATH seems older format. Please remake tag files."); return gfind; }
/* * gpath_open: open gpath tag file * * i) dbpath GTAGSDBPATH * i) mode 0: read only * 1: create * 2: modify * r) 0: normal * -1: error */ int gpath_open(const char *dbpath, int mode) { if (opened > 0) { if (mode != _mode) die("duplicate open with different mode."); opened++; return 0; } /* * We create GPATH just first time. */ _mode = mode; if (mode == 1 && created) mode = 0; dbop = dbop_open(makepath(dbpath, dbname(GPATH), NULL), mode, 0644, 0); if (dbop == NULL) return -1; if (mode == 1) { dbop_putversion(dbop, create_version); _nextkey = 1; } else { int format_version; const char *path = dbop_get(dbop, NEXTKEY); if (path == NULL) die("nextkey not found in GPATH."); _nextkey = atoi(path); format_version = dbop_getversion(dbop); if (format_version > support_version) die("GPATH seems new format. Please install the latest GLOBAL."); else if (format_version < support_version) die("GPATH seems older format. Please remake tag files."); } opened++; return 0; }
/** * gtags_open: open global tag. * * @param[in] dbpath dbpath directory * @param[in] root root directory (needed when compact format) * @param[in] db #GTAGS, #GRTAGS, #GSYMS * @param[in] mode #GTAGS_READ: read only <br> * #GTAGS_CREATE: create tag <br> * #GTAGS_MODIFY: modify tag * @param[in] flags #GTAGS_COMPACT: compact format * @return #GTOP structure * * @note when error occurred, @NAME{gtags_open()} doesn't return. */ GTOP * gtags_open(const char *dbpath, const char *root, int db, int mode, int flags) { GTOP *gtop; char tagfile[MAXPATHLEN]; int dbmode; gtop = (GTOP *)check_calloc(sizeof(GTOP), 1); gtop->db = db; gtop->mode = mode; gtop->openflags = flags; /* * Open tag file allowing duplicate records. */ switch (gtop->mode) { case GTAGS_READ: dbmode = 0; break; case GTAGS_CREATE: dbmode = 1; break; case GTAGS_MODIFY: dbmode = 2; break; default: assert(0); } /* * GRTAGS and GSYMS are virtual tag file. They are included in a real GRTAGS file. * In fact, GSYMS doesn't exist now. * * GRTAGS: tags which belongs to GRTAGS, and are defined in GTAGS. * GSYMS: tags which belongs to GRTAGS, and is not defined in GTAGS. */ strlimcpy(tagfile, makepath(dbpath, dbname(db == GSYMS ? GRTAGS : db), NULL), sizeof(tagfile)); gtop->dbop = dbop_open(tagfile, dbmode, 0644, DBOP_DUP|DBOP_SORTED_WRITE); if (gtop->dbop == NULL) { if (dbmode == 1) die("cannot make %s.", dbname(db)); die("%s not found.", dbname(db)); } if (gtop->mode == GTAGS_READ && db != GTAGS) { const char *gtags = makepath(dbpath, dbname(GTAGS), NULL); int format_version; gtop->gtags = dbop_open(gtags, 0, 0, 0); if (gtop->gtags == NULL) die("GTAGS not found."); format_version = dbop_getversion(gtop->dbop); if (format_version > upper_bound_version) die("%s seems new format. Please install the latest GLOBAL.", gtags); else if (format_version < lower_bound_version) die("%s seems older format. Please remake tag files.", gtags); } if (gtop->mode == GTAGS_CREATE) { /* * Decide format. */ gtop->format = 0; gtop->format_version = new_format_version; /* * GRTAGS and GSYSM always use compact format. * GTAGS uses compact format only when the -c option specified. */ if (gtop->db == GRTAGS || gtop->db == GSYMS || gtop->openflags & GTAGS_COMPACT) { gtop->format |= GTAGS_COMPACT; gtop->format |= GTAGS_COMPLINE; } else { /* standard format */ gtop->format |= GTAGS_COMPRESS; } gtop->format |= GTAGS_COMPNAME; if (gtop->format & GTAGS_COMPACT) dbop_putoption(gtop->dbop, COMPACTKEY, NULL); if (gtop->format & GTAGS_COMPRESS) { dbop_putoption(gtop->dbop, COMPRESSKEY, DEFAULT_ABBREVIATION); abbrev_open(DEFAULT_ABBREVIATION); } if (gtop->format & GTAGS_COMPLINE) dbop_putoption(gtop->dbop, COMPLINEKEY, NULL); if (gtop->format & GTAGS_COMPNAME) dbop_putoption(gtop->dbop, COMPNAMEKEY, NULL); dbop_putversion(gtop->dbop, gtop->format_version); } else { /* * recognize format version of GTAGS. 'format version record' * is saved as a META record in GTAGS and GRTAGS. * if 'format version record' is not found, it's assumed * version 1. */ const char *p; /* * check format version. */ gtop->format_version = dbop_getversion(gtop->dbop); if (gtop->format_version > upper_bound_version) die("%s seems new format. Please install the latest GLOBAL.", tagfile); else if (gtop->format_version < lower_bound_version) die("%s seems older format. Please remake tag files.", tagfile); gtop->format = 0; if (dbop_getoption(gtop->dbop, COMPACTKEY) != NULL) gtop->format |= GTAGS_COMPACT; if ((p = dbop_getoption(gtop->dbop, COMPRESSKEY)) != NULL) { abbrev_open(p); gtop->format |= GTAGS_COMPRESS; } if (dbop_getoption(gtop->dbop, COMPLINEKEY) != NULL) gtop->format |= GTAGS_COMPLINE; if (dbop_getoption(gtop->dbop, COMPNAMEKEY) != NULL) gtop->format |= GTAGS_COMPNAME; } if (gpath_open(dbpath, dbmode) < 0) { if (dbmode == 1) die("cannot create GPATH."); else die("GPATH not found."); } if (gtop->mode != GTAGS_READ) gtop->sb = strbuf_open(0); /* This buffer is used for working area. */ /* * Stuff for compact format. */ if (gtop->format & GTAGS_COMPACT) { assert(root != NULL); strlimcpy(gtop->root, root, sizeof(gtop->root)); if (gtop->mode != GTAGS_READ) gtop->path_hash = strhash_open(HASHBUCKETS); } return gtop; }
int decide_tag_by_context(const char *tag, const char *file, int lineno) { STRBUF *sb = NULL; char path[MAXPATHLEN], s_fid[MAXFIDLEN]; const char *tagline, *p; DBOP *dbop; int db = GSYMS; int iscompline = 0; if (normalize(file, get_root_with_slash(), cwd, path, sizeof(path)) == NULL) die("'%s' is out of source tree.", file); /* * get file id */ if (gpath_open(dbpath, 0) < 0) die("GPATH not found."); if ((p = gpath_path2fid(path, NULL)) == NULL) die("path name in the context is not found."); strlimcpy(s_fid, p, sizeof(s_fid)); gpath_close(); /* * read btree records directly to avoid the overhead. */ dbop = dbop_open(makepath(dbpath, dbname(GTAGS), NULL), 0, 0, 0); if (dbop == NULL) die("cannot open GTAGS."); if (dbop_getoption(dbop, COMPLINEKEY)) iscompline = 1; tagline = dbop_first(dbop, tag, NULL, 0); if (tagline) { db = GTAGS; for (; tagline; tagline = dbop_next(dbop)) { /* * examine whether the definition record include the context. */ p = locatestring(tagline, s_fid, MATCH_AT_FIRST); if (p != NULL && *p == ' ') { for (p++; *p && *p != ' '; p++) ; if (*p++ != ' ' || !isdigit(*p)) die("Impossible! decide_tag_by_context(1)"); /* * Standard format n <blank> <image>$ * Compact format d,d,d,d$ */ if (!iscompline) { /* Standard format */ if (atoi(p) == lineno) { db = GRTAGS; goto finish; } } else { /* Compact format */ int n, cur, last = 0; do { if (!isdigit(*p)) die("Impossible! decide_tag_by_context(2)"); NEXT_NUMBER(p); cur = last + n; if (cur == lineno) { db = GRTAGS; goto finish; } last = cur; if (*p == '-') { if (!isdigit(*++p)) die("Impossible! decide_tag_by_context(3)"); NEXT_NUMBER(p); cur = last + n; if (lineno >= last && lineno <= cur) { db = GRTAGS; goto finish; } last = cur; } if (*p) { if (*p == ',') p++; else die("Impossible! decide_tag_by_context(4)"); } } while (*p); } } } } finish: dbop_close(dbop); if (db == GSYMS && getenv("GTAGSLIBPATH")) { char libdbpath[MAXPATHLEN]; char *libdir = NULL, *nextp = NULL; sb = strbuf_open(0); strbuf_puts(sb, getenv("GTAGSLIBPATH")); for (libdir = strbuf_value(sb); libdir; libdir = nextp) { if ((nextp = locatestring(libdir, PATHSEP, MATCH_FIRST)) != NULL) *nextp++ = 0; if (!gtagsexist(libdir, libdbpath, sizeof(libdbpath), 0)) continue; if (!strcmp(dbpath, libdbpath)) continue; dbop = dbop_open(makepath(libdbpath, dbname(GTAGS), NULL), 0, 0, 0); if (dbop == NULL) continue; tagline = dbop_first(dbop, tag, NULL, 0); dbop_close(dbop); if (tagline != NULL) { db = GTAGS; break; } } strbuf_close(sb); } return db; }
void parsefile(char *const *argv, const char *cwd, const char *root, const char *dbpath, int db) { int count = 0; int file_count = 0; STRBUF *sb = strbuf_open(0); char *langmap; const char *plugin_parser, *av; char path[MAXPATHLEN]; struct parsefile_data data; if (db == GRTAGS + GSYMS) data.target = TARGET_REF|TARGET_SYM; else data.target = 1 << db; data.extractmethod = getconfb("extractmethod"); if (getconfs("langmap", sb)) langmap = check_strdup(strbuf_value(sb)); else langmap = NULL; strbuf_reset(sb); if (getconfs("gtags_parser", sb)) plugin_parser = strbuf_value(sb); else plugin_parser = NULL; data.cv = convert_open(type, format, root, cwd, dbpath, stdout); if (gpath_open(dbpath, 0) < 0) die("GPATH not found."); if (data.target == TARGET_REF || data.target == TARGET_SYM) { data.dbop = dbop_open(makepath(dbpath, dbname(GTAGS), NULL), 0, 0, 0); if (data.dbop == NULL) die("%s not found.", dbname(GTAGS)); } else { data.dbop = NULL; } data.fid = NULL; parser_init(langmap, plugin_parser); if (langmap != NULL) free(langmap); if (*argv && file_list) args_open_both(argv, file_list); else if (*argv) args_open(argv); else if (file_list) args_open_filelist(file_list); else args_open_nop(); while ((av = args_read()) != NULL) { /* * convert the path into relative to the root directory of source tree. */ if (normalize(av, get_root_with_slash(), cwd, path, sizeof(path)) == NULL) if (!qflag) fprintf(stderr, "'%s' is out of source tree.\n", path + 2); /* * Memorize the file id of the path. This is used in put_syms(). */ { static char s_fid[MAXFIDLEN]; const char *p = gpath_path2fid(path, NULL); if (!p) { if (!qflag) fprintf(stderr, "'%s' not found in GPATH.\n", path + 2); continue; } strlimcpy(s_fid, p, sizeof(s_fid)); data.fid = s_fid; } if (!test("f", makepath(root, path, NULL))) { if (test("d", NULL)) { if (!qflag) fprintf(stderr, "'%s' is a directory.\n", av); } else { if (!qflag) fprintf(stderr, "'%s' not found.\n", av); } continue; } if (lflag && !locatestring(path, localprefix, MATCH_AT_FIRST)) continue; data.count = 0; parse_file(path, 0, put_syms, &data); count += data.count; file_count++; } args_close(); parser_exit(); /* * Settlement */ if (data.dbop != NULL) dbop_close(data.dbop); gpath_close(); convert_close(data.cv); strbuf_close(sb); if (vflag) { print_count(count); fprintf(stderr, " (no index used).\n"); } }
int main(int argc, char **argv) { char dbpath[MAXPATHLEN]; char cwd[MAXPATHLEN]; STRBUF *sb = strbuf_open(0); int optchar; int option_index = 0; STATISTICS_TIME *tim; while ((optchar = getopt_long(argc, argv, "cd:f:iuIn:oOqvwse", long_options, &option_index)) != EOF) { switch (optchar) { case 0: /* already flags set */ break; case OPT_CONFIG: show_config = 1; if (optarg) config_name = optarg; break; case OPT_GTAGSCONF: gtagsconf = optarg; break; case OPT_GTAGSLABEL: gtagslabel = optarg; break; case OPT_PATH: do_path = 1; if (!strcmp("absolute", optarg)) convert_type = PATH_ABSOLUTE; else if (!strcmp("relative", optarg)) convert_type = PATH_RELATIVE; else if (!strcmp("through", optarg)) convert_type = PATH_THROUGH; else die("Unknown path type."); break; case OPT_SINGLE_UPDATE: iflag++; single_update = optarg; break; case OPT_ENCODE_PATH: if (strlen(optarg) > 255) die("too many encode chars."); if (strchr(optarg, '/') || strchr(optarg, '.')) die("cannot encode '/' and '.' in the path."); set_encode_chars((unsigned char *)optarg); break; case 'c': cflag++; break; case 'd': dump_target = optarg; break; case 'f': file_list = optarg; break; case 'i': iflag++; break; case 'u': uflag++; iflag++; break; case 'I': Iflag++; break; case 'o': /* * Though the -o(--omit-gsyms) was removed, this code * is left for compatibility. */ break; case 'O': Oflag++; break; case 'q': qflag++; setquiet(); break; case 'w': wflag++; break; case 'v': vflag++; setverbose(); break; default: usage(); break; } } if (gtagsconf) { char path[MAXPATHLEN]; if (realpath(gtagsconf, path) == NULL) die("%s not found.", gtagsconf); set_env("GTAGSCONF", path); } if (gtagslabel) { set_env("GTAGSLABEL", gtagslabel); } if (qflag) vflag = 0; if (show_version) version(NULL, vflag); if (show_help) help(); argc -= optind; argv += optind; /* If dbpath is specified, -O(--objdir) option is ignored. */ if (argc > 0) Oflag = 0; if (show_config) { if (config_name) printconf(config_name); else fprintf(stdout, "%s\n", getconfline()); exit(0); } else if (do_path) { /* * This is the main body of path filter. * This code extract path name from tag line and * replace it with the relative or the absolute path name. * * By default, if we are in src/ directory, the output * should be converted like follws: * * main 10 ./src/main.c main(argc, argv)\n * main 22 ./libc/func.c main(argc, argv)\n * v * main 10 main.c main(argc, argv)\n * main 22 ../libc/func.c main(argc, argv)\n * * Similarly, the --path=absolute option specified, then * v * main 10 /prj/xxx/src/main.c main(argc, argv)\n * main 22 /prj/xxx/libc/func.c main(argc, argv)\n */ STRBUF *ib = strbuf_open(MAXBUFLEN); CONVERT *cv; char *ctags_x; if (argc < 3) die("gtags --path: 3 arguments needed."); cv = convert_open(convert_type, FORMAT_CTAGS_X, argv[0], argv[1], argv[2], stdout); while ((ctags_x = strbuf_fgets(ib, stdin, STRBUF_NOCRLF)) != NULL) convert_put(cv, ctags_x); convert_close(cv); strbuf_close(ib); exit(0); } else if (dump_target) { /* * Dump a tag file. */ DBOP *dbop = NULL; const char *dat = 0; int is_gpath = 0; char* target_file = NULL; if (!test("f", dump_target)) { target_file = strchr(dump_target, ':'); if (target_file == NULL) die("file '%s' not found", dump_target); *target_file++ = 0; //move to the next char, which starts the target file. if (!test("f", dump_target)) { die("file '%s' not found.", dump_target); } } if ((dbop = dbop_open(dump_target, 0, 0, DBOP_RAW)) == NULL) die("file '%s' is not a tag file.", dump_target); /* * The file which has a NEXTKEY record is GPATH. */ if (dbop_get(dbop, NEXTKEY)) is_gpath = 1; if (target_file && !is_gpath) { die("dump target_file can only be used with GPATH"); } if (target_file) { dat = dbop_get(dbop, target_file); if (dat == NULL) { die("target_file %s not found in GPATH", target_file); } time_t t = gpath_mtime(dbop, target_file); printf("%d\n", t); } else { for (dat = dbop_first(dbop, NULL, NULL, 0); dat != NULL; dat = dbop_next(dbop)) { const char *flag = is_gpath ? dbop_getflag(dbop) : ""; if (*flag) if (is_gpath) { time_t t = gpath_mtime(dbop, dbop->lastkey); printf("%s\t%s\t%s\t%s\n", dbop->lastkey, dat, flag, ctime(&t)); } else printf("%s\t%s\t%s\n", dbop->lastkey, dat, flag); else printf("%s\t%s\n", dbop->lastkey, dat); } } dbop_close(dbop); exit(0); } else if (Iflag) { if (!usable("mkid")) die("mkid not found."); } /* * If 'gtags.files' exists, use it as a file list. * If the file_list other than "-" is given, it must be readable file. */ if (file_list == NULL && test("f", GTAGSFILES)) file_list = GTAGSFILES; if (file_list && strcmp(file_list, "-")) { if (test("d", file_list)) die("'%s' is a directory.", file_list); else if (!test("f", file_list)) die("'%s' not found.", file_list); else if (!test("r", file_list)) die("'%s' is not readable.", file_list); } /* * Regularize the path name for single updating (--single-update). */ if (single_update) { static char regular_path_name[MAXPATHLEN]; char *p = single_update; if (!test("f", p)) die("'%s' not found.", p); if (isabspath(p)) die("--single-update requires relative path name."); if (!(p[0] == '.' && p[1] == '/')) { snprintf(regular_path_name, MAXPATHLEN, "./%s", p); p = regular_path_name; } single_update = p; } if (!getcwd(cwd, MAXPATHLEN)) die("cannot get current directory."); canonpath(cwd); /* * Decide directory (dbpath) in which gtags make tag files. * * Gtags create tag files at current directory by default. * If dbpath is specified as an argument then use it. * If the -i option specified and both GTAGS and GRTAGS exists * at one of the candidate directories then gtags use existing * tag files. */ if (iflag) { if (argc > 0) realpath(*argv, dbpath); else if (!gtagsexist(cwd, dbpath, MAXPATHLEN, vflag)) strlimcpy(dbpath, cwd, sizeof(dbpath)); } else { if (argc > 0) realpath(*argv, dbpath); else if (Oflag) { char *objdir = getobjdir(cwd, vflag); if (objdir == NULL) die("Objdir not found."); strlimcpy(dbpath, objdir, sizeof(dbpath)); } else strlimcpy(dbpath, cwd, sizeof(dbpath)); } if (iflag && (!test("f", makepath(dbpath, dbname(GTAGS), NULL)) || !test("f", makepath(dbpath, dbname(GRTAGS), NULL)) || !test("f", makepath(dbpath, dbname(GPATH), NULL)))) { if (wflag) warning("GTAGS, GRTAGS or GPATH not found. -i option ignored."); iflag = 0; } if (!test("d", dbpath)) die("directory '%s' not found.", dbpath); if (vflag) fprintf(stderr, "[%s] Gtags started.\n", now()); /* * load configuration file. */ openconf(); if (getconfb("extractmethod")) extractmethod = 1; strbuf_reset(sb); if (getconfs("langmap", sb)) langmap = check_strdup(strbuf_value(sb)); strbuf_reset(sb); if (getconfs("gtags_parser", sb)) gtags_parser = check_strdup(strbuf_value(sb)); /* * initialize parser. */ if (vflag && gtags_parser) fprintf(stderr, " Using plug-in parser.\n"); parser_init(langmap, gtags_parser); if (vflag && file_list) fprintf(stderr, " Using '%s' as a file list.\n", file_list); /* * Start statistics. */ init_statistics(); /* * 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); print_statistics(statistics); exit(0); } /* * create GTAGS and GRTAGS */ createtags(dbpath, cwd); /* * create idutils index. */ if (Iflag) { tim = statistics_time_start("Time of creating ID"); if (vflag) fprintf(stderr, "[%s] Creating indexes for idutils.\n", now()); strbuf_reset(sb); strbuf_puts(sb, "mkid"); if (vflag) strbuf_puts(sb, " -v"); strbuf_sprintf(sb, " --file='%s/ID'", dbpath); 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)); if (chmod(makepath(dbpath, "ID", NULL), 0644) < 0) die("cannot chmod ID file."); statistics_time_end(tim); } if (vflag) fprintf(stderr, "[%s] Done.\n", now()); closeconf(); strbuf_close(sb); print_statistics(statistics); return 0; }
int main(int argc, char **argv) { char dbpath[MAXPATHLEN]; char cwd[MAXPATHLEN]; STRBUF *sb = strbuf_open(0); int optchar; int option_index = 0; STATISTICS_TIME *tim; /* * Setup GTAGSCONF and GTAGSLABEL environment variable * according to the --gtagsconf and --gtagslabel option. */ preparse_options(argc, argv); /* * Get the project root directory. */ if (!vgetcwd(cwd, MAXPATHLEN)) die("cannot get current directory."); canonpath(cwd); /* * Load configuration file. */ openconf(cwd); configuration(); setenv_from_config(); { char *env = getenv("GTAGS_OPTIONS"); if (env && *env) argv = prepend_options(&argc, argv, env); } logging_arguments(argc, argv); while ((optchar = getopt_long(argc, argv, "cd:f:iIn:oOqvwse", long_options, &option_index)) != EOF) { switch (optchar) { case 0: /* already flags set */ break; case OPT_CONFIG: show_config = 1; if (optarg) config_name = optarg; break; case OPT_GTAGSCONF: case OPT_GTAGSLABEL: /* These options are already parsed in preparse_options() */ break; case OPT_SINGLE_UPDATE: iflag++; single_update = optarg; break; case OPT_ACCEPT_DOTFILES: set_accept_dotfiles(); break; case 'c': cflag++; break; case 'd': dump_target = optarg; break; case 'f': file_list = optarg; break; case 'i': iflag++; break; case 'I': Iflag++; break; case 'o': /* * Though the -o(--omit-gsyms) was removed, this code * is left for compatibility. */ break; case 'O': Oflag++; break; case 'q': qflag++; setquiet(); break; case 'w': wflag++; break; case 'v': vflag++; setverbose(); break; default: usage(); break; } } if (qflag) vflag = 0; if (show_version) version(NULL, vflag); if (show_help) help(); argc -= optind; argv += optind; /* If dbpath is specified, -O(--objdir) option is ignored. */ if (argc > 0) Oflag = 0; if (show_config) { openconf(setupdbpath(0) == 0 ? get_root() : NULL); if (config_name) printconf(config_name); else fprintf(stdout, "%s\n", getconfline()); exit(0); } else if (dump_target) { /* * Dump a tag file. */ DBOP *dbop = NULL; const char *dat = 0; int is_gpath = 0; if (!test("f", dump_target)) die("file '%s' not found.", dump_target); if ((dbop = dbop_open(dump_target, 0, 0, DBOP_RAW)) == NULL) die("file '%s' is not a tag file.", dump_target); /* * The file which has a NEXTKEY record is GPATH. */ if (dbop_get(dbop, NEXTKEY)) is_gpath = 1; for (dat = dbop_first(dbop, NULL, NULL, 0); dat != NULL; dat = dbop_next(dbop)) { const char *flag = is_gpath ? dbop_getflag(dbop) : ""; if (*flag) printf("%s\t%s\t%s\n", dbop->lastkey, dat, flag); else printf("%s\t%s\n", dbop->lastkey, dat); } dbop_close(dbop); exit(0); } else if (Iflag) { #define REQUIRED_MKID_VERSION "4.5" char *p; if (!usable("mkid")) die("mkid not found."); if (read_first_line("mkid --version", sb)) die("mkid cannot executed."); p = strrchr(strbuf_value(sb), ' '); if (p == NULL) die("invalid version string of mkid: %s", strbuf_value(sb)); switch (check_version(p + 1, REQUIRED_MKID_VERSION) #ifdef _WIN32 || strcmp(p + 1, "3.2.99") == 0 #endif ) { case 1: break; /* OK */ case 0: die("mkid version %s or later is required.", REQUIRED_MKID_VERSION); default: die("invalid version string of mkid: %s", strbuf_value(sb)); } } /* * If 'gtags.files' exists, use it as a file list. * If the file_list other than "-" is given, it must be readable file. */ if (file_list == NULL && test("f", GTAGSFILES)) file_list = GTAGSFILES; if (file_list && strcmp(file_list, "-")) { if (test("d", file_list)) die("'%s' is a directory.", file_list); else if (!test("f", file_list)) die("'%s' not found.", file_list); else if (!test("r", file_list)) die("'%s' is not readable.", file_list); } /* * Regularize the path name for single updating (--single-update). */ if (single_update) { static char regular_path_name[MAXPATHLEN]; char *p = single_update; if (!test("f", p)) die("'%s' not found.", p); #if _WIN32 || __DJGPP__ for (; *p; p++) if (*p == '\\') *p = '/'; p = single_update; #define LOCATEFLAG MATCH_AT_FIRST|IGNORE_CASE #else #define LOCATEFLAG MATCH_AT_FIRST #endif if (isabspath(p)) { char *q = locatestring(p, cwd, LOCATEFLAG); if (q && *q == '/') snprintf(regular_path_name, MAXPATHLEN, "./%s", q + 1); else die("path '%s' is out of the project.", p); } else { if (p[0] == '.' && p[1] == '/') snprintf(regular_path_name, MAXPATHLEN, "%s", p); else snprintf(regular_path_name, MAXPATHLEN, "./%s", p); } single_update = regular_path_name; } /* * Decide directory (dbpath) in which gtags make tag files. * * Gtags create tag files at current directory by default. * If dbpath is specified as an argument then use it. * If the -i option specified and both GTAGS and GRTAGS exists * at one of the candidate directories then gtags use existing * tag files. */ if (iflag) { if (argc > 0) realpath(*argv, dbpath); else if (!gtagsexist(cwd, dbpath, MAXPATHLEN, vflag)) strlimcpy(dbpath, cwd, sizeof(dbpath)); } else { if (argc > 0) realpath(*argv, dbpath); else if (Oflag) { char *objdir = getobjdir(cwd, vflag); if (objdir == NULL) die("Objdir not found."); strlimcpy(dbpath, objdir, sizeof(dbpath)); } else strlimcpy(dbpath, cwd, sizeof(dbpath)); } if (iflag && (!test("f", makepath(dbpath, dbname(GTAGS), NULL)) || !test("f", makepath(dbpath, dbname(GRTAGS), NULL)) || !test("f", makepath(dbpath, dbname(GPATH), NULL)))) { if (wflag) warning("GTAGS, GRTAGS or GPATH not found. -i option ignored."); iflag = 0; } if (!test("d", dbpath)) die("directory '%s' not found.", dbpath); if (vflag) fprintf(stderr, "[%s] Gtags started.\n", now()); /* * initialize parser. */ if (vflag && gtags_parser) fprintf(stderr, " Using plug-in parser.\n"); parser_init(langmap, gtags_parser); if (vflag && file_list) fprintf(stderr, " Using '%s' as a file list.\n", file_list); /* * Start statistics. */ init_statistics(); /* * 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); print_statistics(statistics); exit(0); } /* * create GTAGS and GRTAGS */ createtags(dbpath, cwd); /* * create idutils index. */ if (Iflag) { FILE *op; GFIND *gp; const char *path; tim = statistics_time_start("Time of creating ID"); if (vflag) fprintf(stderr, "[%s] Creating indexes for idutils.\n", now()); strbuf_reset(sb); /* * Since idutils stores the value of PWD in ID file, we need to * force idutils to follow our style. */ #if _WIN32 || __DJGPP__ strbuf_puts(sb, "mkid --files0-from=-"); #else strbuf_sprintf(sb, "PWD=%s mkid --files0-from=-", quote_shell(cwd)); #endif if (vflag) strbuf_puts(sb, " -v"); strbuf_sprintf(sb, " --file=%s/ID", quote_shell(dbpath)); if (vflag) { #ifdef __DJGPP__ if (is_unixy()) /* test for 4DOS as well? */ #endif strbuf_puts(sb, " 1>&2"); } else { strbuf_puts(sb, " >" NULL_DEVICE); #ifdef __DJGPP__ if (is_unixy()) /* test for 4DOS as well? */ #endif strbuf_puts(sb, " 2>&1"); } if (debug) fprintf(stderr, "executing mkid like: %s\n", strbuf_value(sb)); op = popen(strbuf_value(sb), "w"); if (op == NULL) die("cannot execute '%s'.", strbuf_value(sb)); gp = gfind_open(dbpath, NULL, GPATH_BOTH); while ((path = gfind_read(gp)) != NULL) { fputs(path, op); fputc('\0', op); } gfind_close(gp); if (pclose(op) != 0) die("terminated abnormally '%s' (errno = %d).", strbuf_value(sb), errno); if (test("f", makepath(dbpath, "ID", NULL))) if (chmod(makepath(dbpath, "ID", NULL), 0644) < 0) die("cannot chmod ID file."); statistics_time_end(tim); } if (vflag) fprintf(stderr, "[%s] Done.\n", now()); closeconf(); strbuf_close(sb); print_statistics(statistics); return 0; }