⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gtags.c

📁 代码检索工具GLOBAL源码。可用来浏览分析LINUX源码。
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2005 *	Tama Communications Corporation * * This file is part of GNU GLOBAL. * * GNU GLOBAL is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * GNU GLOBAL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA. */#ifdef HAVE_CONFIG_H#include <config.h>#endif#include <sys/types.h>#include <sys/stat.h>#include <errno.h>#include <ctype.h>#include <utime.h>#include <signal.h>#include <stdio.h>#if TIME_WITH_SYS_TIME#include <sys/time.h>#include <time.h>#else#if HAVE_SYS_TIME_H#include <sys/time.h>#else#include <time.h>#endif#endif#ifdef STDC_HEADERS#include <stdlib.h>#endif#ifdef HAVE_STRING_H#include <string.h>#else#include <strings.h>#endif#ifdef HAVE_UNISTD_H#include <unistd.h>#endif#include "getopt.h"#include "global.h"#include "const.h"struct dup_entry {	int offset;	SPLIT ptable;	int lineno;	int skip;};static void usage(void);static void help(void);void signal_setup(void);void onintr(int);static int compare_dup_entry(const void *, const void *);static void put_lines(char *, struct dup_entry *, int);int main(int, char **);int incremental(const char *, const char *);void updatetags(const char *, const char *, IDSET *, STRBUF *, int, int);void createtags(const char *, const char *, int);int printconf(const char *);void set_base_directory(const char *, const char *);void put_converting(const char *, int, int);int cflag;					/* compact format */int iflag;					/* incremental update */int Iflag;					/* make  id-utils index */int oflag;					/* suppress making GSYMS */int qflag;					/* quiet mode */int wflag;					/* warning message */int vflag;					/* verbose mode */int max_args;int show_version;int show_help;int show_config;int do_convert;int do_find;int do_sort;int do_relative;int do_absolute;int cxref;int do_expand;int gtagsconf;int gtagslabel;int other_files;int debug;int secure_mode;const char *extra_options;const char *info_string;const char *file_list;int extractmethod;int total;static voidusage(void){	if (!qflag)		fputs(usage_const, stderr);	exit(2);}static voidhelp(void){	fputs(usage_const, stdout);	fputs(help_const, stdout);	exit(0);}static struct option const long_options[] = {	{"compact", no_argument, NULL, 'c'},	{"file", required_argument, NULL, 'f'},	{"idutils", no_argument, NULL, 'I'},	{"incremental", no_argument, NULL, 'i'},	{"max-args", required_argument, NULL, 'n'},	{"omit-gsyms", no_argument, NULL, 'o'},	{"quiet", no_argument, NULL, 'q'},	{"verbose", no_argument, NULL, 'v'},	{"warning", no_argument, NULL, 'w'},	/* long name only */	{"absolute", no_argument, &do_absolute, 1},	{"config", optional_argument, &show_config, 1},	{"convert", no_argument, &do_convert, 1},	{"cxref", no_argument, &cxref, 1},	{"debug", no_argument, &debug, 1},	{"expand", required_argument, &do_expand, 1},	{"find", no_argument, &do_find, 1},	{"gtagsconf", required_argument, &gtagsconf, 1},	{"gtagslabel", required_argument, &gtagslabel, 1},	{"other", no_argument, &other_files, 1},	{"relative", no_argument, &do_relative, 1},	{"secure", no_argument, &secure_mode, 1},	{"sort", no_argument, &do_sort, 1},	{"version", no_argument, &show_version, 1},	{"help", no_argument, &show_help, 1},	{ 0 }};/* * Gtags catch signal even if the parent ignore it. */int exitflag = 0;static const char *langmap = DEFAULTLANGMAP;voidonintr(signo)	int signo;{	signo = 0;      /* to satisfy compiler */	exitflag = 1;}voidsignal_setup(void){	signal(SIGINT, onintr);	signal(SIGTERM, onintr);#ifdef SIGHUP	signal(SIGHUP, onintr);#endif#ifdef SIGQUIT	signal(SIGQUIT, onintr);#endif}/* * compare_dup_entry: compare function for sorting. */static intcompare_dup_entry(v1, v2)	const void *v1;	const void *v2;{	const struct dup_entry *e1 = v1, *e2 = v2;	int ret;	if ((ret = strcmp(e1->ptable.part[PART_PATH].start,			  e2->ptable.part[PART_PATH].start)) != 0)		return ret;	return e1->lineno - e2->lineno;}/* * put_lines: sort and print duplicate lines */static voidput_lines(lines, entries, entry_count)	char *lines;	struct dup_entry *entries;	int entry_count;{	int i;	for (i = 0; i < entry_count; i++) {		char *ctags_x = lines + entries[i].offset;		SPLIT *ptable = &entries[i].ptable;		if (split(ctags_x, 4, ptable) < 4) {			recover(ptable);			die("too small number of parts.\n'%s'", ctags_x);		}		entries[i].lineno = atoi(ptable->part[PART_LNO].start);		entries[i].skip = 0;	}	qsort(entries, entry_count, sizeof(struct dup_entry), compare_dup_entry);	for (i = 1; i < entry_count; i++) {		if (entries[i].lineno == entries[i - 1].lineno		 && strcmp(entries[i].ptable.part[PART_PATH].start,			   entries[i - 1].ptable.part[PART_PATH].start) == 0)			entries[i].skip = 1;	}	for (i = 0; i < entry_count; i++) {		recover(&entries[i].ptable);		if (!entries[i].skip)			puts(lines + entries[i].offset);	}}intmain(argc, argv)	int argc;	char *argv[];{	char root[MAXPATHLEN+1];	char dbpath[MAXPATHLEN+1];	char cwd[MAXPATHLEN+1];	STRBUF *sb = strbuf_open(0);	const char *p;	int db;	int optchar;	int option_index = 0;	while ((optchar = getopt_long(argc, argv, "cf:iIn:oqvwse", long_options, &option_index)) != EOF) {		switch (optchar) {		case 0:			p = long_options[option_index].name;			if (!strcmp(p, "expand")) {				settabs(atoi(optarg + 1));			} else if (!strcmp(p, "config")) {				if (optarg)					info_string = optarg;			} else if (gtagsconf || gtagslabel) {				char value[MAXPATHLEN+1];				const char *name = (gtagsconf) ? "GTAGSCONF" : "GTAGSLABEL";				if (gtagsconf) {					if (realpath(optarg, value) == NULL)						die("%s not found.", optarg);				} else {					strlimcpy(value, optarg, sizeof(value));				}				set_env(name, value);				gtagsconf = gtagslabel = 0;			}			break;		case 'c':			cflag++;			break;		case 'f':			file_list = optarg;			break;		case 'i':			iflag++;			break;		case 'I':			Iflag++;			break;		case 'n':			max_args = atoi(optarg);			if (max_args <= 0)				die("--max-args option requires number > 0.");			break;		case 'o':			oflag++;			break;		case 'q':			qflag++;			setquiet();			break;		case 'w':			wflag++;			break;		case 'v':			vflag++;			break;		/* for compatibility */		case 's':		case 'e':			break;		default:			usage();			break;		}	}	if (qflag)		vflag = 0;	if (show_version)		version(NULL, vflag);	if (show_help)		help();	argc -= optind;        argv += optind;	if (show_config) {		if (!info_string && argc)			info_string = argv[0];		if (info_string) {			printconf(info_string);		} else {			fprintf(stdout, "%s\n", getconfline());		}		exit(0);	} else if (do_convert) {		STRBUF *ib = strbuf_open(MAXBUFLEN);		const char *fid;		char *p, *q;		int c;		/*		 * [Job]		 *		 * Read line from stdin and replace " ./<file name> "		 * with the file number like this.		 *		 * <a href='http://xxx/global/S/ ./main.c .html#110'>main</a>\n		 *				|		 *				v		 * <a href='http://xxx/global/S/39.html#110'>main</a>\n		 *		 * If the file name is not found in GPATH, change into the path to CGI script.		 * <a href='http://xxx/global/S/ ./README .html#9'>main</a>\n		 *				|		 *				v		 * <a href='http://xxx/global/cgi-bin/global.cgi?pattern=README&amp;type=source#9'>main</a>\n		 */		if (gpath_open(".", 0) < 0)			die("GPATH not found.");		while (strbuf_fgets(ib, stdin, 0) != NULL) {			p = strbuf_value(ib);			if (!locatestring(p, "<a ", MATCH_AT_FIRST))				continue;			q = locatestring(p, "/S/ ", MATCH_FIRST);			if (q == NULL) {				printf("%s: ERROR(1): %s", progname, strbuf_value(ib));				continue;			}			/* Print just before "/S/ " and skip "/S/ ". */			for (; p < q; p++)				putc(*p, stdout);			for (; *p && *p != ' '; p++)				;			/* Extract path name. */			for (q = ++p; *q && *q != ' '; q++)				;			if (*q == '\0') {				printf("%s: ERROR(2): %s", progname, strbuf_value(ib));				continue;			}			*q++ = '\0';			/*			 * Convert path name into URL.			 * The output of 'global -xgo' may include lines about			 * files other than source code. In this case, file id			 * doesn't exist in GPATH.			 */			fid = gpath_path2fid(p);			if (fid) {				fputs("/S/", stdout);				fputs(fid, stdout);				fputs(q, stdout);			} else {				fputs("/cgi-bin/global.cgi?pattern=", stdout);				p += 2;				while ((c = (unsigned char)*p++) != '\0') {					if (isalnum(c))						putc(c, stdout);					else						printf("%%%02x", c);				}				fputs("&amp;type=source", stdout);				for (; *q && *q != '#'; q++)					;				if (*q == '\0') {					printf("%s: ERROR(2): %s", progname, strbuf_value(ib));					continue;				}				fputs(q, stdout);			}		}		gpath_close();		strbuf_close(ib);		exit(0);	} else if (do_expand) {		/*		 * The 'gtags --expand' is nearly equivalent with 'expand'.		 * We made this command to decrease dependency to external		 * command. But now, the --secure option use this command		 * positively.		 */		FILE *ip;		STRBUF *ib = strbuf_open(MAXBUFLEN);		if (argc) {			if (secure_mode) {				char buf[MAXPATHLEN+1], *path;				char rootdir[MAXPATHLEN+1];				getdbpath(cwd, root, dbpath, 0);				snprintf(rootdir, sizeof(rootdir), "%s/", root);				path = realpath(argv[0], buf);				if (path == NULL)					die("realpath(%s, buf) failed. (errno=%d).", argv[0], errno);				if (!isabspath(path))					die("realpath(3) is not compatible with BSD version.");				if (!locatestring(path, rootdir, MATCH_AT_FIRST))					die("'%s' is out of source tree.", path);			}			ip = fopen(argv[0], "r");			if (ip == NULL)				exit(1);		} else			ip = stdin;		while (strbuf_fgets(ib, ip, STRBUF_NOCRLF) != NULL)			detab(stdout, strbuf_value(ib));		strbuf_close(ib);		exit(0);	} else if (do_find) {		/*		 * This code is used by htags(1) to traverse file system.		 *		 * If the --other option is not specified, 'gtags --find'		 * read GPATH instead of traversing file. But if the option		 * is specified, it traverse file system every time.		 * It is because gtags doesn't record the paths other than		 * source file in GPATH.		 * Since it is slow, gtags should record not only source		 * files but also other files in GPATH in the future.		 * But it needs adding a new format version.		 */		const char *path;		const char *local = (argc) ? argv[0] : NULL;		for (vfind_open(local, other_files); (path = vfind_read()) != NULL; ) {			fputs(path, stdout);			fputc('\n', stdout);		}		vfind_close();		exit(0);	} else if (do_sort) {		/*		 * This code and the makedupindex() in htags(1) compose		 * a pipeline 'global -x ".*" | gtags --sort'.		 * The 'gtags --sort' is equivalent with 'sort -k 1,1 -k 3,3 -k 2,2n -u'		 * but the latter is ineffective and needs a lot of temporary		 * files when applied to a huge file. (According to circumstances,		 * hundreds of files are generated.)		 *		 * Utilizing the feature that the output of 'global -x ".*"'		 * is already sorted in alphabetical order by tag name,		 * we splited the output into relatively small unit and		 * execute sort for each unit.		 */		STRBUF *ib = strbuf_open(MAXBUFLEN);		STRBUF *sb = strbuf_open(MAXBUFLEN);		VARRAY *vb = varray_open(sizeof(struct dup_entry), 100);		char *ctags_x, prev[IDENTLEN];		prev[0] = '\0';		while ((ctags_x = strbuf_fgets(ib, stdin, STRBUF_NOCRLF)) != NULL) {			const char *tag;			struct dup_entry *entry;			SPLIT ptable;			if (split(ctags_x, 2, &ptable) < 2) {				recover(&ptable);				die("too small number of parts.\n'%s'", ctags_x);			}			tag = ptable.part[PART_TAG].start;			if (prev[0] == '\0' || strcmp(prev, tag) != 0) {				if (prev[0] != '\0') {					if (vb->length == 1)						puts(strbuf_value(sb));					else						put_lines(strbuf_value(sb),							varray_assign(vb, 0, 0),							vb->length);				}				strlimcpy(prev, tag, sizeof(prev));				strbuf_reset(sb);				varray_reset(vb);			}			entry = varray_append(vb);			entry->offset = strbuf_getlen(sb);			recover(&ptable);			strbuf_puts0(sb, ctags_x);		}		if (prev[0] != '\0') {			if (vb->length == 1)				puts(strbuf_value(sb));			else				put_lines(strbuf_value(sb),					varray_assign(vb, 0, 0), vb->length);		}		strbuf_close(ib);		strbuf_close(sb);		varray_close(vb);		exit(0);	} else if (do_relative || do_absolute) {		/*		 * 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 --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);		const char *root = argv[0];		const char *cwd = argv[1];		const char *ctags_x;		if (argc < 2)			die("do_relative: 2 arguments needed.");		set_base_directory(root, cwd);		while ((ctags_x = strbuf_fgets(ib, stdin, 0)) != NULL)			put_converting(ctags_x, do_absolute ? 1 : 0, cxref);		strbuf_close(ib);		exit(0);	} else if (Iflag) {		if (!usable("mkid"))			die("mkid not found.");	}	/*	 * If the file_list other than "-" is given, it must be readable file.	 */	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);	}	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 candedite 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			strlimcpy(dbpath, cwd, sizeof(dbpath));	}	if (iflag && (!test("f", makepath(dbpath, dbname(GTAGS), NULL)) ||		!test("f", makepath(dbpath, dbname(GPATH), NULL)))) {		if (wflag)			warning("GTAGS 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 .globalrc or /etc/gtags.conf	 */	openconf();

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -