/** * args_read: read path From args. * * @return path (@VAR{NULL}: end of argument) */ const char * args_read(void) { const char *p; STATIC_STRBUF(sb); strbuf_clear(sb); switch (type) { case ARGS_NOP: p = NULL; break; case ARGS_ARGS: p = *argslist++; break; case ARGS_FILELIST: p = strbuf_fgets(sb, ip, STRBUF_NOCRLF); break; case ARGS_GFIND: p = gfind_read(gp); break; case ARGS_BOTH: if (*argslist != NULL) p = *argslist++; else p = strbuf_fgets(sb, ip, STRBUF_NOCRLF); break; default: die("args_read: invalid type."); } return p; }
/** * 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); }
/** * get a path from input stream. * * @note Each path name must start with @CODE{"./"}. */ static const char * getpath(void) { static const char *buff; if (!retry) { /* skip README or ChangeLog unless the -o option specified. */ do { buff = gfind_read(gp); } while (buff && gp->type == GPATH_OTHER && !other_files); } retry = 0; return buff; }
/** * 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; }
/** * makehtml: make html files * * @param[in] total number of files. */ static void makehtml(int total) { GFIND *gp; FILE *anchor_stream; const char *path; int count = 0; /* * Create anchor stream for anchor_load(). */ anchor_stream = tmpfile(); #if defined(_WIN32) && !defined(__CYGWIN__) /* * tmpfile is created in the root, which user's can't write on Vista+. * Use _tempnam and open it directly. */ if (anchor_stream == NULL) { char *name = _tempnam(tmpdir, "htags"); anchor_stream = fopen(name, "w+bD"); free(name); } #endif gp = gfind_open(dbpath, NULL, other_files ? GPATH_BOTH : GPATH_SOURCE, 0); while ((path = gfind_read(gp)) != NULL) { if (gp->type == GPATH_OTHER) fputc(' ', anchor_stream); fputs(path, anchor_stream); fputc('\n', anchor_stream); } gfind_close(gp); /* * Prepare anchor stream for anchor_load(). */ anchor_prepare(anchor_stream); /* * For each path in GPATH, convert the path into HTML file. */ gp = gfind_open(dbpath, NULL, other_files ? GPATH_BOTH : GPATH_SOURCE, 0); while ((path = gfind_read(gp)) != NULL) { char html[MAXPATHLEN]; if (gp->type == GPATH_OTHER && !other_files) continue; /* * load tags belonging to the path. * The path must be start "./". */ anchor_load(path); /* * inform the current path name to lex() function. */ save_current_path(path); count++; path += 2; /* remove './' at the head */ message(" [%d/%d] converting %s", count, total, path); snprintf(html, sizeof(html), "%s/%s/%s.%s", distpath, SRCS, path2fid(path), HTML); src2html(path, html, gp->type == GPATH_OTHER); } gfind_close(gp); }
/* * pathlist: print candidate path list. * * i) dbpath */ void pathlist(const char *pattern, const char *dbpath) { GFIND *gp; CONVERT *cv; const char *path, *p; regex_t preg; int count; int target = GPATH_SOURCE; if (oflag) target = GPATH_BOTH; if (Oflag) target = GPATH_OTHER; if (pattern) { int flags = 0; char edit[IDENTLEN]; if (!Gflag) flags |= REG_EXTENDED; if (iflag || getconfb("icase_path")) flags |= REG_ICASE; #ifdef _WIN32 flags |= REG_ICASE; #endif /* _WIN32 */ /* * We assume '^aaa' as '^/aaa'. */ if (*pattern == '^' && *(pattern + 1) != '/') { snprintf(edit, sizeof(edit), "^/%s", pattern + 1); pattern = edit; } if (regcomp(&preg, pattern, flags) != 0) die("invalid regular expression."); } if (!localprefix) localprefix = "./"; cv = convert_open(type, format, root, cwd, dbpath, stdout); count = 0; gp = gfind_open(dbpath, localprefix, target); while ((path = gfind_read(gp)) != NULL) { /* * skip localprefix because end-user doesn't see it. */ p = path + strlen(localprefix) - 1; if (pattern) { int result = regexec(&preg, p, 0, 0, 0); if ((!Vflag && result != 0) || (Vflag && result == 0)) continue; } else if (Vflag) continue; if (format == FORMAT_PATH) convert_put_path(cv, path); else convert_put_using(cv, "path", path, 1, " ", gp->dbop->lastdat); count++; } gfind_close(gp); convert_close(cv); if (pattern) regfree(&preg); if (vflag) { switch (count) { case 0: fprintf(stderr, "file not found"); break; case 1: fprintf(stderr, "1 file located"); break; default: fprintf(stderr, "%d files located", count); break; } fprintf(stderr, " (using '%s').\n", makepath(dbpath, dbname(GPATH), NULL)); } }
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; }