/* * normalize: normalize path name * * i) path path name * i) root root of project (must be end with a '/') * i) cwd current directory * o) result normalized path name * i) size size of the result * r) ==NULL: error * !=NULL: result */ char * normalize(const char *path, const char *root, const char *cwd, char *result, const int size) { char *p, abs[MAXPATHLEN]; if (normalize_pathname(path, result, size) == NULL) goto toolong; if (isabspath(path)) { if (strlen(result) > MAXPATHLEN) goto toolong; strcpy(abs, result); } else { if (rel2abs(result, cwd, abs, sizeof(abs)) == NULL) goto toolong; } /* * Remove the root part of path and insert './'. * rootdir /a/b/ * path /a/b/c/d.c -> c/d.c -> ./c/d.c */ p = locatestring(abs, root, MATCH_AT_FIRST); if (p == NULL) return NULL; strlimcpy(result, "./", size); strlimcpy(result + 2, p, size - 2); return result; toolong: die("path name is too long."); }
/** * usable: check if command is executable or not. * * @param[in] command * @return ==NULL: not found. <br> * !=NULL: absolute path of @a command. */ char * usable(const char *command) { STRBUF *sb; char *p; const char *dir; static char path[MAXPATHLEN]; #if defined(_WIN32) || defined(__DJGPP__) int i, lim = sizeof(suffix)/sizeof(char *); #endif if (isabspath(command) || locatestring(command, "./", MATCH_AT_FIRST) || locatestring(command, "../", MATCH_AT_FIRST)) { if (test("fx", command)) { strlimcpy(path, command, sizeof(path)); return path; } return NULL; } /* * If found in BINDIR then use it. */ if (test("fx", makepath(BINDIR, command, NULL))) { strlimcpy(path, makepath(BINDIR, command, NULL), sizeof(path)); return path; } /* * Locate the command for each path in PATH. */ *path = 0; /* Don't use fixed length buffer for environment variable * because it brings buffer overflow. */ sb = strbuf_open(0); strbuf_puts(sb, getenv("PATH")); p = strbuf_value(sb); while (p) { dir = p; if ((p = locatestring(p, PATHSEP, MATCH_FIRST)) != NULL) *p++ = 0; if (test("fx", makepath(dir, command, NULL))) { strlimcpy(path, makepath(dir, command, NULL), sizeof(path)); goto finish; } #if defined(_WIN32) || defined(__DJGPP__) for (i = 0; i < lim; i++) if (test("f", makepath(dir, command, suffix[i]))) { strlimcpy(path, makepath(dir, command, suffix[i]), sizeof(path)); goto finish; } #endif } finish: strbuf_close(sb); return *path ? path : NULL; }
char * path_test(const char *file, unsigned int test) { char *cp, *ep; char *s, *p; unsigned int len, exelen; if (!file) return NULL; if (isabspath(file)) { if (file_test(file, test)) return Estrdup(file); return NULL; } cp = getenv("PATH"); if (!cp) return Estrdup(file); exelen = strlen(file); s = NULL; ep = cp; for (; ep; cp = ep + 1) { ep = strchr(cp, ':'); len = (ep) ? (unsigned int)(ep - cp) : strlen(cp); if (len == 0) continue; p = EREALLOC(char, s, len + exelen + 2); if (!p) break; s = p; memcpy(s, cp, len); s[len] = '/'; memcpy(s + len + 1, file, exelen + 1); if (file_test(s, test)) return s; } Efree(s); return NULL; }
/* 该函数用于安全的打开文件 2013-12-09 16:15 */ FILE * fileio::safeopen(const char *fname, const char *status) { TYPE_FILENAME cfn = gloab::g_filepoint.getfilename(); TYPE_FILENAME fn = fname; FILE *fp; fp = inopen(fname, status); if(!fp && !isabspath(fname) && cfn != ""){ strprocess::killfbspace(cfn); TYPE_FILENAME pp = getparent(cfn); if(pp != ""){ fn = pp+fname; fp = inopen(fn, status); } } if(fp){ // gloab::g_filepoint.set(fn); return fp; } errorprocess::showerr(ERR_HAVANO_FILE, fname); return NULL; }
/** * @details * normalize: normalize path name * * @param[in] path path name * @param[in] root root of project (@STRONG{must be end with a '/'}) * @param[in] cwd current directory * @param[out] result normalized path name * @param[in] size size of the @a result * @return ==NULL: error <br> * !=NULL: @a result * * @note Calls die() if the result path name is too long (#MAXPATHLEN). */ char * normalize(const char *path, const char *root, const char *cwd, char *result, const int size) { char *p, abs[MAXPATHLEN]; if (normalize_pathname(path, result, size) == NULL) goto toolong; if (isabspath(path)) { if (strlen(result) > MAXPATHLEN) goto toolong; strcpy(abs, result); } else { if (rel2abs(result, cwd, abs, sizeof(abs)) == NULL) goto toolong; } /* * Remove the root part of path and insert './'. * rootdir /a/b/ * path /a/b/c/d.c -> c/d.c -> ./c/d.c */ p = locatestring(abs, root, MATCH_AT_FIRST); if (p == NULL) { p = locatestring(root, abs, MATCH_AT_FIRST); /* * abs == /usr/src should be considered to be equal to root == /usr/src/. */ if (p && !strcmp(p, "/")) result[0] = '\0'; else return NULL; } strlimcpy(result, "./", size); strlimcpy(result + 2, p, size - 2); return result; toolong: die("path name is too long."); }
JL_DLLEXPORT void *jl_load_dynamic_library(const char *modname, unsigned flags, int throw_err) { char path[PATHBUF]; int i; uv_stat_t stbuf; void *handle; int abspath; // number of extensions to try — if modname already ends with the // standard extension, then we don't try adding additional extensions int n_extensions = endswith_extension(modname) ? 1 : N_EXTENSIONS; /* this branch returns handle of libjulia */ if (modname == NULL) { #ifdef _OS_WINDOWS_ if (!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCWSTR)(uintptr_t)(&jl_load_dynamic_library), (HMODULE*)&handle)) { jl_error("could not load base module"); } #else Dl_info info; if (!dladdr((void*)(uintptr_t)&jl_load_dynamic_library, &info) || !info.dli_fname) jl_error("could not load base module"); handle = dlopen(info.dli_fname, RTLD_NOW); #endif goto done; } abspath = isabspath(modname); /* this branch permutes all base paths in DL_LOAD_PATH with all extensions note: skip when !jl_base_module to avoid UndefVarError(:DL_LOAD_PATH), and also skip for absolute paths */ if (!abspath && jl_base_module != NULL) { jl_array_t *DL_LOAD_PATH = (jl_array_t*)jl_get_global(jl_base_module, jl_symbol("DL_LOAD_PATH")); if (DL_LOAD_PATH != NULL) { size_t j; for (j = 0; j < jl_array_len(DL_LOAD_PATH); j++) { char *dl_path = jl_string_data(jl_array_ptr_data(DL_LOAD_PATH)[j]); size_t len = strlen(dl_path); if (len == 0) continue; for (i=0; i < n_extensions; i++) { const char *ext = extensions[i]; path[0] = '\0'; if (dl_path[len-1] == PATHSEPSTRING[0]) snprintf(path, PATHBUF, "%s%s%s", dl_path, modname, ext); else snprintf(path, PATHBUF, "%s" PATHSEPSTRING "%s%s", dl_path, modname, ext); handle = jl_dlopen(path, flags); if (handle) goto done; // bail out and show the error if file actually exists if (jl_stat(path, (char*)&stbuf) == 0) goto notfound; } } } } // now fall back and look in default library paths, for all extensions for(i=0; i < n_extensions; i++) { const char *ext = extensions[i]; path[0] = '\0'; snprintf(path, PATHBUF, "%s%s", modname, ext); handle = jl_dlopen(path, flags); if (handle) goto done; } notfound: if (throw_err) { const char * reason = jl_dlerror(); jl_errorf("could not load library \"%s\"\n%s", modname, reason); } return NULL; done: return handle; }
/** * openconf: load configuration file. * * @param[in] rootdir Project root directory * * Globals used (output): * confline: specified entry */ void openconf(const char *rootdir) { STRBUF *sb; if (opened) return; opened = 1; /* * if config file not found then return default value. */ if (!(config_path = configpath(rootdir))) confline = check_strdup(""); /* * if it is not an absolute path then assumed config value itself. */ else if (!isabspath(config_path)) { confline = check_strdup(config_path); if (!locatestring(confline, ":", MATCH_FIRST)) die("GTAGSCONF must be absolute path name."); } /* * else load value from config file. */ else { if (test("d", config_path)) die("config file '%s' is a directory.", config_path); if (!test("f", config_path)) die("config file '%s' not found.", config_path); if (!test("r", config_path)) die("config file '%s' is not readable.", config_path); if ((config_label = getenv("GTAGSLABEL")) == NULL) config_label = "default"; if (!(fp = fopen(config_path, "r"))) die("cannot open '%s'.", config_path); ib = strbuf_open(MAXBUFLEN); sb = strbuf_open(0); includelabel(fp, sb, config_label, 0); confline = check_strdup(strbuf_value(sb)); strbuf_close(ib); strbuf_close(sb); fclose(fp); } /* * make up required variables. */ sb = strbuf_open(0); strbuf_puts(sb, confline); strbuf_unputc(sb, ':'); if (!getconfs("langmap", NULL)) { strbuf_puts(sb, ":langmap="); strbuf_puts(sb, quote_chars(DEFAULTLANGMAP, ':')); } if (!getconfs("skip", NULL)) { strbuf_puts(sb, ":skip="); strbuf_puts(sb, DEFAULTSKIP); } strbuf_unputc(sb, ':'); strbuf_putc(sb, ':'); confline = check_strdup(strbuf_value(sb)); strbuf_close(sb); trim(confline); return; }
td_file * td_engine_get_file(td_engine *engine, const char *input_path, td_get_file_mode mode) { unsigned int hash; int slot; td_file *chain; td_file *f; int path_len; char path[1024]; const char *out_path; size_t input_path_len = strlen(input_path); if (input_path_len >= sizeof(path)) td_croak("path too long: %s", input_path); if (TD_COPY_STRING == mode) { if (isabspath(input_path)) { strcpy(path, input_path); } else { snprintf(path, sizeof path, "%s%s", cwd, input_path); } sanitize_path(path, sizeof(path), input_path_len); hash = (unsigned int) djb2_hash(path); out_path = path; } else { hash = (unsigned int) djb2_hash(input_path); out_path = input_path; } td_mutex_lock_or_die(engine->lock); slot = (int) (hash % engine->file_hash_size); chain = engine->file_hash[slot]; while (chain) { if (chain->hash == hash && 0 == strcmp(out_path, chain->path)) { td_mutex_unlock_or_die(engine->lock); return chain; } chain = chain->bucket_next; } ++engine->stats.file_count; f = td_page_alloc(&engine->alloc, sizeof(td_file)); memset(f, 0, sizeof(td_file)); f->path_len = path_len = (int) strlen(out_path); if (TD_COPY_STRING == mode) f->path = td_page_strdup(&engine->alloc, out_path, path_len); else f->path = out_path; f->hash = hash; f->name = find_basename(f->path, path_len); f->bucket_next = engine->file_hash[slot]; f->signer = engine->default_signer; f->stat_dirty = 1; f->signature_dirty = 1; f->frozen_relstring_index = ~(0u); engine->file_hash[slot] = f; td_mutex_unlock_or_die(engine->lock); return f; }
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; }
int main(int argc, char **argv) { const char *av = NULL; int db; int optchar; int option_index = 0; int status = 0; /* * get path of following directories. * o current directory * o root of source tree * o dbpath directory * * if GTAGS not found, exit with an error message. */ status = setupdbpath(0); if (status == 0) { cwd = get_cwd(); root = get_root(); dbpath = get_dbpath(); } /* * Setup GTAGSCONF and GTAGSLABEL environment variable * according to the --gtagsconf and --gtagslabel option. */ preparse_options(argc, argv); /* * Open configuration file. */ openconf(root); setenv_from_config(); logging_arguments(argc, argv); while ((optchar = getopt_long(argc, argv, "acde:EifFgGIlL:MnoOpPqrsS:tTuvVx", long_options, &option_index)) != EOF) { switch (optchar) { case 0: break; case 'a': aflag++; break; case 'c': cflag++; setcom(optchar); break; case 'd': dflag++; break; case 'e': av = optarg; break; case 'E': Gflag = 0; break; case 'f': fflag++; xflag++; setcom(optchar); break; case 'F': Tflag = 0; break; case 'g': gflag++; setcom(optchar); break; case 'G': Gflag++; break; case 'i': iflag++; break; case 'I': Iflag++; setcom(optchar); break; case 'l': Sflag++; scope = "."; break; case 'L': file_list = optarg; break; case 'M': Mflag++; iflag = 0; break; case 'n': nflag++; if (optarg) { if (!strcmp(optarg, "sort")) nofilter |= SORT_FILTER; else if (!strcmp(optarg, "path")) nofilter |= PATH_FILTER; } else { nofilter = BOTH_FILTER; } break; case 'o': oflag++; break; case 'O': Oflag++; break; case 'p': pflag++; setcom(optchar); break; case 'P': Pflag++; setcom(optchar); break; case 'q': qflag++; setquiet(); break; case 'r': rflag++; break; case 's': sflag++; break; case 'S': Sflag++; scope = optarg; break; case 't': tflag++; break; case 'T': Tflag++; break; case 'u': uflag++; setcom(optchar); break; case 'v': vflag++; setverbose(); break; case 'V': Vflag++; break; case 'x': xflag++; break; case OPT_USE_COLOR: if (optarg) { if (!strcmp(optarg, "never")) use_color = 0; else if (!strcmp(optarg, "always")) use_color = 1; else if (!strcmp(optarg, "auto")) use_color = 2; else die_with_code(2, "unknown color type."); } else { use_color = 2; } break; case OPT_ENCODE_PATH: encode_chars = optarg; break; case OPT_FROM_HERE: { char *p = optarg; const char *usage = "usage: global --from-here=lineno:path."; context_lineno = p; while (*p && isdigit(*p)) p++; if (*p != ':') die_with_code(2, usage); *p++ = '\0'; if (!*p) die_with_code(2, usage); context_file = p; } break; case OPT_GTAGSCONF: case OPT_GTAGSLABEL: /* These options are already parsed in preparse_options() */ break; case OPT_MATCH_PART: if (!strcmp(optarg, "first")) match_part = MATCH_PART_FIRST; else if (!strcmp(optarg, "last")) match_part = MATCH_PART_LAST; else if (!strcmp(optarg, "all")) match_part = MATCH_PART_ALL; else die_with_code(2, "unknown part type for the --match-part option."); break; case OPT_PATH_CONVERT: 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_PATH_STYLE: path_style = optarg; break; case OPT_RESULT: if (!strcmp(optarg, "ctags-x")) format = FORMAT_CTAGS_X; else if (!strcmp(optarg, "ctags-xid")) format = FORMAT_CTAGS_XID; else if (!strcmp(optarg, "ctags")) format = FORMAT_CTAGS; else if (!strcmp(optarg, "ctags-mod")) format = FORMAT_CTAGS_MOD; else if (!strcmp(optarg, "path")) format = FORMAT_PATH; else if (!strcmp(optarg, "grep")) format = FORMAT_GREP; else if (!strcmp(optarg, "cscope")) format = FORMAT_CSCOPE; else die_with_code(2, "unknown format type for the --result option."); break; case OPT_SINGLE_UPDATE: single_update = optarg; break; default: usage(); break; } } if (qflag) vflag = 0; if (show_version) version(av, vflag); if (show_help) help(); if (dbpath == NULL) die_with_code(-status, gtags_dbpath_error); /* * decide format. * The --result option is given to priority more than the -t and -x option. */ if (format == 0) { if (tflag) { /* ctags format */ format = FORMAT_CTAGS; } else if (xflag) { /* print details */ format = FORMAT_CTAGS_X; } else { /* print just a file name */ format = FORMAT_PATH; } } /* * GTAGSBLANKENCODE will be used in less(1). */ switch (format) { case FORMAT_CTAGS_X: case FORMAT_CTAGS_XID: if (encode_chars == NULL && getenv("GTAGSBLANKENCODE")) encode_chars = " \t"; break; } if (encode_chars) { if (strlen(encode_chars) > 255) die("too many encode chars."); if (strchr(encode_chars, '/') || strchr(encode_chars, '.')) warning("cannot encode '/' and '.' in the path. Ignored."); set_encode_chars((unsigned char *)encode_chars); } if (getenv("GTAGSTHROUGH")) Tflag++; if (use_color) { #if defined(_WIN32) && !defined(__CYGWIN__) if (!(getenv("ANSICON") || LoadLibrary("ANSI32.dll")) && use_color == 2) use_color = 0; #endif if (use_color == 2 && !isatty(1)) use_color = 0; if (Vflag) use_color = 0; } argc -= optind; argv += optind; /* * Path filter */ if (do_path) { /* * This code is needed for globash.rc. * 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 follows: * * 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-convert=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("global --path-convert: 3 arguments needed."); cv = convert_open(convert_type, FORMAT_CTAGS_X, argv[0], argv[1], argv[2], stdout, NOTAGS); while ((ctags_x = strbuf_fgets(ib, stdin, STRBUF_NOCRLF)) != NULL) convert_put(cv, ctags_x); convert_close(cv); strbuf_close(ib); exit(0); } /* * At first, we pickup pattern from -e option. If it is not found * then use argument which is not option. */ if (!av) { av = *argv; /* * global -g pattern [files ...] * av argv */ if (gflag && av) argv++; } if (single_update) { if (command == 0) { uflag++; command = 'u'; } else if (command != 'u') { ; /* ignored */ } } /* * only -c, -u, -P and -p allows no argument. */ if (!av) { switch (command) { case 'c': case 'u': case 'p': case 'P': break; case 'f': if (file_list) break; default: usage(); break; } } /* * -u and -p cannot have any arguments. */ if (av) { switch (command) { case 'u': case 'p': usage(); default: break; } } if (tflag) xflag = 0; if (nflag > 1) nosource = 1; /* to keep compatibility */ if (print0) set_print0(); if (cflag && match_part == 0) match_part = MATCH_PART_ALL; /* * remove leading blanks. */ if (!Iflag && !gflag && av) for (; *av == ' ' || *av == '\t'; av++) ; if (cflag && !Pflag && av && isregex(av)) die_with_code(2, "only name char is allowed with -c option."); /* * print dbpath or rootdir. */ if (pflag) { fprintf(stdout, "%s\n", (rflag) ? root : dbpath); exit(0); } /* * incremental update of tag files. */ if (uflag) { STRBUF *sb = strbuf_open(0); char *gtags_path = usable("gtags"); if (!gtags_path) die("gtags command not found."); if (chdir(root) < 0) die("cannot change directory to '%s'.", root); #if defined(_WIN32) && !defined(__CYGWIN__) /* * Get around CMD.EXE's weird quoting rules by sticking another * perceived whitespace in front (also works with Take Command). */ strbuf_putc(sb, ';'); #endif strbuf_puts(sb, quote_shell(gtags_path)); strbuf_puts(sb, " -i"); if (vflag) strbuf_puts(sb, " -v"); if (single_update) { if (!isabspath(single_update)) { static char regular_path_name[MAXPATHLEN]; if (rel2abs(single_update, cwd, regular_path_name, sizeof(regular_path_name)) == NULL) die("rel2abs failed."); single_update = regular_path_name; } strbuf_puts(sb, " --single-update "); strbuf_puts(sb, quote_shell(single_update)); } strbuf_putc(sb, ' '); strbuf_puts(sb, quote_shell(dbpath)); if (system(strbuf_value(sb))) exit(1); strbuf_close(sb); exit(0); } /* * decide tag type. */ if (context_file) { if (isregex(av)) die_with_code(2, "regular expression is not allowed with the --from-here option."); db = decide_tag_by_context(av, context_file, atoi(context_lineno)); } else { if (dflag) db = GTAGS; else if (rflag && sflag) db = GRTAGS + GSYMS; else db = (rflag) ? GRTAGS : ((sflag) ? GSYMS : GTAGS); } /* * complete function name */ if (cflag) { if (Iflag) completion_idutils(dbpath, root, av); else if (Pflag) completion_path(dbpath, av); else completion(dbpath, root, av, db); exit(0); } /* * make local prefix. * local prefix must starts with './' and ends with '/'. */ if (Sflag) { STRBUF *sb = strbuf_open(0); static char buf[MAXPATHLEN]; const char *path = scope; /* * normalize the path of scope directory. */ if (!test("d", path)) die("'%s' not found or not a directory.", scope); if (!isabspath(path)) path = makepath(cwd, path, NULL); if (realpath(path, buf) == NULL) die("cannot get real path of '%s'.", scope); if (!in_the_project(buf)) die("'%s' is out of the source project.", scope); scope = buf; /* * make local prefix. */ strbuf_putc(sb, '.'); if (strcmp(root, scope) != 0) { const char *p = scope + strlen(root); if (*p != '/') strbuf_putc(sb, '/'); strbuf_puts(sb, p); } strbuf_putc(sb, '/'); localprefix = check_strdup(strbuf_value(sb)); strbuf_close(sb); #ifdef DEBUG fprintf(stderr, "root=%s\n", root); fprintf(stderr, "cwd=%s\n", cwd); fprintf(stderr, "localprefix=%s\n", localprefix); #endif } /* * convert the file-list path into an absolute path. */ if (file_list && strcmp(file_list, "-") && !isabspath(file_list)) { static char buf[MAXPATHLEN]; if (realpath(file_list, buf) == NULL) die("'%s' not found.", file_list); file_list = buf; } /* * decide path conversion type. */ if (nofilter & PATH_FILTER) type = PATH_THROUGH; else if (aflag) type = PATH_ABSOLUTE; else type = PATH_RELATIVE; if (path_style) { if (!strcmp(path_style, "relative")) type = PATH_RELATIVE; else if (!strcmp(path_style, "absolute")) type = PATH_ABSOLUTE; else if (!strcmp(path_style, "through")) type = PATH_THROUGH; else if (!strcmp(path_style, "shorter")) type = PATH_SHORTER; else if (!strcmp(path_style, "abslib")) { type = PATH_RELATIVE; abslib++; } else die("invalid path style."); } /* * exec lid(idutils). */ if (Iflag) { chdir(root); idutils(av, dbpath); } /* * search pattern (regular expression). */ else if (gflag) { chdir(root); grep(av, argv, dbpath); } /* * locate paths including the pattern. */ else if (Pflag) { chdir(root); pathlist(av, dbpath); } /* * parse source files. */ else if (fflag) { chdir(root); parsefile(argv, cwd, root, dbpath, db); } /* * tag search. */ else { tagsearch(av, cwd, root, dbpath, db); } return 0; }