Esempio n. 1
0
/*
 * Execute global(1) and write the output to the 'sb' string buffer.
 *
 *	o)	sb	output
 *	i)	com	cscope command (0-8)
 *	i)	opt	option for global(1)
 *	i)	arg	argument for global(1)
 *	r)		number of output
 */
static int
execute_command(STRBUF *sb, const int com, const int opt, const char *arg)
{
#ifdef _WIN32
#define QUOTE '"'
#else
#define QUOTE '\''
#endif
	STATIC_STRBUF(command);
	STATIC_STRBUF(ib);
	FILE *ip;
	int count = 0;

	strbuf_clear(command);
	strbuf_puts(command, global_path);
	strbuf_puts(command, " --result=cscope");
	if (opt == FROM_HERE) {
		strbuf_puts(command, " --from-here=");
		strbuf_puts(command, context);
	} else if (opt) {
		strbuf_puts(command, " -");
		strbuf_putc(command, opt);
	}
	if (ignore_case)
		strbuf_puts(command, " --ignore-case");
	strbuf_putc(command, ' ');
	strbuf_putc(command, QUOTE);
	strbuf_puts(command, arg);
	strbuf_putc(command, QUOTE);
	if (!(ip = popen(strbuf_value(command), "r")))
		die("cannot execute '%s'.", strbuf_value(command));
	if (vflag)
		fprintf(stderr, "gscope: %s\n", strbuf_value(command));
	/*
	 * Copy records with little modification.
	 */
	strbuf_clear(ib);
	while (strbuf_fgets(ib, ip, 0)) {
		count++;
		if (opt == 0) {
			strbuf_puts(sb, strbuf_value(ib));
		} else {
			char *p = strbuf_value(ib);

			/* path name */
			while (*p && *p != ' ')
				strbuf_putc(sb, *p++);
			if (*p != ' ')
				die("illegal cscope format. (%s)", strbuf_value(ib));
			strbuf_putc(sb, *p++);

			/* replace pattern with "<unknown>" or "<global>" */
			while (*p && *p != ' ')
				p++;
			if (*p != ' ')
				die("illegal cscope format. (%s)", strbuf_value(ib));
			if (com == '8')
				strbuf_puts(sb, "<global>");
			else
				strbuf_puts(sb, "<unknown>");
			strbuf_putc(sb, *p++);

			/* line number */
			while (*p && *p != ' ')
				strbuf_putc(sb, *p++);
			if (*p != ' ')
				die("illegal cscope format. (%s)", strbuf_value(ib));
			strbuf_putc(sb, *p++);

			/* line image */
			if (*p == '\n')
				strbuf_puts(sb, "<unknown>\n");
			else
				strbuf_puts(sb, p);
		}
	}
	if (pclose(ip) < 0)
		die("terminated abnormally.");
	return count;
}
Esempio n. 2
0
/**
 * execute_command
 *
 *	@param[in]	xp	xargs structure
 *	@return		!=NULL: file pointer <br>
 *			==NULL: end of argument
 *
 * This function constructs command line from the following, <br>
 *	@STRONG{command}: @CODE{xp-\>command} <br>
 *	@STRONG{argument}: each argument provider <br>
 * execute it on a pipe line, and return the file pointer.
 */
static FILE *
execute_command(XARGS *xp)
{
	int limit;
	STRBUF *comline = strbuf_open(0);
	int count = 0;
	int length;
	FILE *pipe = NULL;
	char *p, *meta_p;

#if defined(_WIN32) && !defined(__CYGWIN__)
	/*
	 * If the command starts with a quote, CMD.EXE requires the entire
	 * command line to be quoted.
	 */
	if (*xp->command == '"')
		strbuf_putc(comline, '"');
#endif
	/*
	 * Copy the part before '%s' of the command skeleton.
	 * The '%s' in the skeleton is replaced with given arguments.
	 */
	meta_p = locatestring(xp->command, "%s", MATCH_FIRST);
	if (meta_p) {
		strbuf_nputs(comline, xp->command, meta_p - xp->command);
		limit = exec_line_limit(strlen(meta_p + 2));
	} else {
		strbuf_puts(comline, xp->command);
		limit = exec_line_limit(0);
	}
	/*
	 * Append arguments as many as possible.
	 */
	switch (xp->type) {
	case XARGS_FILE:
		for (
			/* initial */
			fseek(xp->ip, xp->fptr, SEEK_SET)
			;
			/* continuation condition */
			(LT_MAX &&
				((p = (strbuf_getlen(xp->path) > 0 ?
				strbuf_value(xp->path) :
				strbuf_fgets(xp->path, xp->ip, STRBUF_NOCRLF))) != NULL))
			;
			/* preparation */
			strbuf_reset(xp->path)
		)
			APPEND_ARGUMENT(p);
		xp->fptr = ftell(xp->ip);
		break;
	case XARGS_ARGV:
		for (; LT_MAX && xp->argc > 0; xp->argc--, xp->argv++)
			APPEND_ARGUMENT(xp->argv[0])
		break;
	case XARGS_STRBUF:
		for (; LT_MAX && xp->curp < xp->endp; xp->curp += length + 1)
			APPEND_ARGUMENT(xp->curp)
		break;
	case XARGS_FIND:
		for (; LT_MAX && (p = repeat_find_read()) != NULL; repeat_find_next())
			APPEND_ARGUMENT(p)
		break;
	}
	/*
	 * Copy the left part of the command skeleton.
	 */
	if (meta_p) {
		strbuf_putc(comline, ' ');
		strbuf_puts(comline, meta_p + 2);
	}
#if defined(_WIN32) && !defined(__CYGWIN__)
	if (*xp->command == '"')
		strbuf_putc(comline, '"');
#endif
	if (count > 0) {
		pipe = popen(strbuf_value(comline), "r");
		if (pipe == NULL)
			die("cannot execute command '%s'.", strbuf_value(comline));
	}
	strbuf_close(comline);
	return pipe;
}
Esempio n. 3
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;
}
Esempio n. 4
0
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 the source project.", 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;
}
Esempio n. 5
0
/**
 * tagsearch: execute tag search
 *
 *	@param[in]	pattern		search pattern
 *	@param[in]	cwd		current directory
 *	@param[in]	root		root of source tree
 *	@param[in]	dbpath		database directory
 *	@param[in]	db		#GTAGS,#GRTAGS,#GSYMS
 */
void
tagsearch(const char *pattern, const char *cwd, const char *root, const char *dbpath, int db)
{
	int count, total = 0;
	char buffer[IDENTLEN], *p = buffer;
	char libdbpath[MAXPATHLEN];

	/*
	 * trim pattern (^<no regex>$ => <no regex>)
	 */
	if (pattern) {
		strlimcpy(p, pattern, sizeof(buffer));
		if (*p++ == '^') {
			char *q = p + strlen(p);
			if (*--q == '$') {
				*q = 0;
				if (*p == 0 || !isregex(p))
					pattern = p;
			}
		}
	}
	/*
	 * search in current source tree.
	 */
	count = search(pattern, root, cwd, dbpath, db);
	total += count;
	/*
	 * search in library path.
	 */
	if (abslib)
		type = PATH_ABSOLUTE;
	if (db == GTAGS && getenv("GTAGSLIBPATH") && (count == 0 || Tflag) && !Sflag) {
		STRBUF *sb = strbuf_open(0);
		char *libdir, *nextp = NULL;

		strbuf_puts(sb, getenv("GTAGSLIBPATH"));
		/*
		 * search for each tree in the library path.
		 */
		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;
			if (!test("f", makepath(libdbpath, dbname(db), NULL)))
				continue;
			/*
			 * search again
			 */
			count = search(pattern, libdir, cwd, libdbpath, db);
			total += count;
			if (count > 0 && !Tflag) {
				/* for verbose message */
				dbpath = libdbpath;
				break;
			}
		}
		strbuf_close(sb);
	}
	if (vflag) {
		print_count(total);
		if (!Tflag)
			fprintf(stderr, " (using '%s')", makepath(dbpath, dbname(db), NULL));
		fputs(".\n", stderr);
	}
}
Esempio n. 6
0
/**
 * idutils:  @NAME{lid}(@NAME{idutils}) pattern
 *
 *	@param[in]	pattern	@NAME{POSIX} regular expression
 *	@param[in]	dbpath	@FILE{GTAGS} directory
 */
void
idutils(const char *pattern, const char *dbpath)
{
	FILE *ip;
	CONVERT *cv;
	STRBUF *ib = strbuf_open(0);
	char encoded_pattern[IDENTLEN];
	char path[MAXPATHLEN];
	const char *lid;
	int linenum, count;
	char *p, *q, *grep;

	lid = usable("lid");
	if (!lid)
		die("lid(idutils) not found.");
	if (!test("f", makepath(dbpath, "ID", NULL)))
		die("ID file not found.");
	/*
	 * convert spaces into %FF format.
	 */
	encode(encoded_pattern, sizeof(encoded_pattern), pattern);
	/*
	 * make lid command line.
	 * Invoke lid with the --result=grep option to generate grep format.
	 */
#if _WIN32 || __DJGPP__
	strbuf_puts(ib, lid);
#else
	strbuf_sprintf(ib, "PWD=%s %s", quote_shell(root), lid);
#endif
	strbuf_sprintf(ib, " --file=%s/ID", quote_shell(dbpath));
	strbuf_puts(ib, " --separator=newline");
	if (format == FORMAT_PATH)
		strbuf_puts(ib, " --result=filenames --key=none");
	else
		strbuf_puts(ib, " --result=grep");
	if (iflag)
		strbuf_puts(ib, " --ignore-case");
	if (isregex(pattern))
		strbuf_puts(ib, " --regexp");
	strbuf_putc(ib, ' ');
	strbuf_puts(ib, quote_shell(pattern));
	if (debug)
		fprintf(stderr, "idutils: %s\n", strbuf_value(ib));
	if (!(ip = popen(strbuf_value(ib), "r")))
		die("cannot execute '%s'.", strbuf_value(ib));
	cv = convert_open(type, format, root, cwd, dbpath, stdout, NOTAGS);
	cv->tag_for_display = encoded_pattern;
	count = 0;
	strcpy(path, "./");
	while ((grep = strbuf_fgets(ib, ip, STRBUF_NOCRLF)) != NULL) {
		q = path + 2;
		/* extract path name */
		if (*grep == '/')
			die("The path in the output of lid is assumed relative.\n'%s'", grep);
		p = grep;
		while (*p && *p != ':')
			*q++ = *p++;
		*q = '\0'; 
		if ((xflag || tflag) && !*p)
			die("invalid lid(idutils) output format(1). '%s'", grep);
		p++;
		if (Sflag) {
			if (!locatestring(path, localprefix, MATCH_AT_FIRST))
				continue;
		}
		count++;
		switch (format) {
		case FORMAT_PATH:
			convert_put_path(cv, NULL, path);
			break;
		default:
			/* extract line number */
			while (*p && isspace(*p))
				p++;
			linenum = 0;
			for (linenum = 0; *p && isdigit(*p); linenum = linenum * 10 + (*p++ - '0'))
				;
			if (*p != ':')
				die("invalid lid(idutils) output format(2). '%s'", grep);
			if (linenum <= 0)
				die("invalid lid(idutils) output format(3). '%s'", grep);
			p++;
			/*
			 * print out.
			 */
			convert_put_using(cv, pattern, path, linenum, p, NULL);
			break;
		}
	}
	if (pclose(ip) != 0)
		die("terminated abnormally (errno = %d).", errno);
	convert_close(cv);
	strbuf_close(ib);
	if (vflag) {
		print_count(count);
		fprintf(stderr, " (using idutils index in '%s').\n", dbpath);
	}
}
Esempio n. 7
0
/**
 * Cpp: read C++ file and pickup tag entries.
 */
void
Cpp(const struct parser_param *param)
{
    int c, cc;
    int savelevel;
    int startclass, startthrow, startmacro, startsharp, startequal;
    char classname[MAXTOKEN];
    char completename[MAXCOMPLETENAME];
    char *completename_limit = &completename[sizeof(completename)];
    int classlevel;
    struct {
        char *classname;
        char *terminate;
        int level;
    } stack[MAXCLASSSTACK];
    const char *interested = "{}=;~";
    STRBUF *sb = strbuf_open(0);

    *classname = *completename = 0;
    stack[0].classname = completename;
    stack[0].terminate = completename;
    stack[0].level = 0;
    level = classlevel = piflevel = namespacelevel = 0;
    savelevel = -1;
    startclass = startthrow = startmacro = startsharp = startequal = 0;

    if (!opentoken(param->file))
        die("'%s' cannot open.", param->file);
    cmode = 1;			/* allow token like '#xxx' */
    crflag = 1;			/* require '\n' as a token */
    cppmode = 1;			/* treat '::' as a token */

    while ((cc = nexttoken(interested, cpp_reserved_word)) != EOF) {
        if (cc == '~' && level == stack[classlevel].level)
            continue;
        switch (cc) {
        case SYMBOL:		/* symbol	*/
            if (startclass || startthrow) {
                PUT(PARSER_REF_SYM, token, lineno, sp);
            } else if (peekc(0) == '('/* ) */) {
                if (param->isnotfunction(token)) {
                    PUT(PARSER_REF_SYM, token, lineno, sp);
                } else if (level > stack[classlevel].level || startequal || startmacro) {
                    PUT(PARSER_REF_SYM, token, lineno, sp);
                } else if (level == stack[classlevel].level && !startmacro && !startsharp && !startequal) {
                    char savetok[MAXTOKEN], *saveline;
                    int savelineno = lineno;

                    strlimcpy(savetok, token, sizeof(savetok));
                    strbuf_reset(sb);
                    strbuf_puts(sb, sp);
                    saveline = strbuf_value(sb);
                    if (function_definition(param)) {
                        /* ignore constructor */
                        if (strcmp(stack[classlevel].classname, savetok))
                            PUT(PARSER_DEF, savetok, savelineno, saveline);
                    } else {
                        PUT(PARSER_REF_SYM, savetok, savelineno, saveline);
                    }
                }
            } else {
                PUT(PARSER_REF_SYM, token, lineno, sp);
            }
            break;
        case CPP_USING:
            crflag = 0;
            /*
             * using namespace name;
             * using ...;
             */
            if ((c = nexttoken(interested, cpp_reserved_word)) == CPP_NAMESPACE) {
                if ((c = nexttoken(interested, cpp_reserved_word)) == SYMBOL) {
                    PUT(PARSER_REF_SYM, token, lineno, sp);
                } else {
                    if (param->flags & PARSER_WARNING)
                        warning("missing namespace name. [+%d %s].", lineno, curfile);
                    pushbacktoken();
                }
            } else if (c  == SYMBOL) {
                char savetok[MAXTOKEN], *saveline;
                int savelineno = lineno;

                strlimcpy(savetok, token, sizeof(savetok));
                strbuf_reset(sb);
                strbuf_puts(sb, sp);
                saveline = strbuf_value(sb);
                if ((c = nexttoken(interested, cpp_reserved_word)) == '=') {
                    PUT(PARSER_DEF, savetok, savelineno, saveline);
                } else {
                    PUT(PARSER_REF_SYM, savetok, savelineno, saveline);
                    while (c == SYMBOL) {
                        PUT(PARSER_REF_SYM, token, lineno, sp);
                        c = nexttoken(interested, cpp_reserved_word);
                    }
                }
            } else {
                pushbacktoken();
            }
            crflag = 1;
            break;
        case CPP_NAMESPACE:
            crflag = 0;
            /*
             * namespace name = ...;
             * namespace [name] { ... }
             */
            if ((c = nexttoken(interested, cpp_reserved_word)) == SYMBOL) {
                PUT(PARSER_DEF, token, lineno, sp);
                if ((c = nexttoken(interested, cpp_reserved_word)) == '=') {
                    crflag = 1;
                    break;
                }
            }
            /*
             * Namespace block doesn't have any influence on level.
             */
            if (c == '{') { /* } */
                namespacelevel++;
            } else {
                if (param->flags & PARSER_WARNING)
                    warning("missing namespace block. [+%d %s](0x%x).", lineno, curfile, c);
            }
            crflag = 1;
            break;
        case CPP_EXTERN: /* for 'extern "C"/"C++"' */
            if (peekc(0) != '"') /* " */
                continue; /* If does not start with '"', continue. */
            while ((c = nexttoken(interested, cpp_reserved_word)) == '\n')
                ;
            /*
             * 'extern "C"/"C++"' block is a kind of namespace block.
             * (It doesn't have any influence on level.)
             */
            if (c == '{') /* } */
                namespacelevel++;
            else
                pushbacktoken();
            break;
        case CPP_STRUCT:
        case CPP_CLASS:
            DBG_PRINT(level, cc == CPP_CLASS ? "class" : "struct");
            while ((c = nexttoken(NULL, cpp_reserved_word)) == CPP___ATTRIBUTE__ || c == '\n')
                if (c == CPP___ATTRIBUTE__)
                    process_attribute(param);
            if (c == SYMBOL) {
                char *saveline;
                int savelineno;
                do {
                    if (c == SYMBOL) {
                        savelineno = lineno;
                        strbuf_reset(sb);
                        strbuf_puts(sb, sp);
                        saveline = strbuf_value(sb);
                        strlimcpy(classname, token, sizeof(classname));
                    }
                    c = nexttoken(NULL, cpp_reserved_word);
                    if (c == SYMBOL)
                        PUT(PARSER_REF_SYM, classname, savelineno, saveline);
                    else if (c == '<') {
                        int templates = 1;
                        for (;;) {
                            c = nexttoken(NULL, cpp_reserved_word);
                            if (c == SYMBOL)
                                PUT(PARSER_REF_SYM, token, lineno, sp);
                            if (c == '<') {
                                if (peekc(1) == '<')
                                    throwaway_nextchar();
                                else
                                    ++templates;
                            } else if (c == '>') {
                                if (--templates == 0)
                                    break;
                            } else if (c == EOF) {
                                if (param->flags & PARSER_WARNING)
                                    warning("failed to parse template [+%d %s].", savelineno, curfile);
                                goto finish;
                            }
                        }
                        c = nexttoken(NULL, cpp_reserved_word);
                    }
                } while (c == SYMBOL || c == '\n');
                if (c == ':' || c == '{') { /* } */
                    startclass = 1;
                    PUT(PARSER_DEF, classname, savelineno, saveline);
                } else
                    PUT(PARSER_REF_SYM, classname, savelineno, saveline);
            }
            pushbacktoken();
            break;
        case '{':  /* } */
            DBG_PRINT(level, "{"); /* } */
            ++level;
            if ((param->flags & PARSER_BEGIN_BLOCK) && atfirst) {
                if ((param->flags & PARSER_WARNING) && level != 1)
                    warning("forced level 1 block start by '{' at column 0 [+%d %s].", lineno, curfile); /* } */
                level = 1;
            }
            if (startclass) {
                char *p = stack[classlevel].terminate;
                char *q = classname;

                if (++classlevel >= MAXCLASSSTACK)
                    die("class stack over flow.[%s]", curfile);
                if (classlevel > 1 && p < completename_limit)
                    *p++ = '.';
                stack[classlevel].classname = p;
                while (*q && p < completename_limit)
                    *p++ = *q++;
                stack[classlevel].terminate = p;
                stack[classlevel].level = level;
                *p++ = 0;
            }
            startclass = startthrow = 0;
            break;
        /* { */
        case '}':
            if (--level < 0) {
                if (namespacelevel > 0)
                    namespacelevel--;
                else if (param->flags & PARSER_WARNING)
                    warning("missing left '{' [+%d %s].", lineno, curfile); /* } */
                level = 0;
            }
            if ((param->flags & PARSER_END_BLOCK) && atfirst) {
                if ((param->flags & PARSER_WARNING) && level != 0)
                    /* { */
                    warning("forced level 0 block end by '}' at column 0 [+%d %s].", lineno, curfile);
                level = 0;
            }
            if (level < stack[classlevel].level)
                *(stack[--classlevel].terminate) = 0;
            /* { */
            DBG_PRINT(level, "}");
            break;
        case '=':
            /* dirty hack. Don't mimic this. */
            if (peekc(0) == '=') {
                throwaway_nextchar();
            } else {
                startequal = 1;
            }
            break;
        case ';':
            startthrow = startequal = 0;
            break;
        case '\n':
            if (startmacro && level != savelevel) {
                if (param->flags & PARSER_WARNING)
                    warning("different level before and after #define macro. reseted. [+%d %s].", lineno, curfile);
                level = savelevel;
            }
            startmacro = startsharp = 0;
            break;
        /*
         * #xxx
         */
        case SHARP_DEFINE:
        case SHARP_UNDEF:
            startmacro = 1;
            savelevel = level;
            if ((c = nexttoken(interested, cpp_reserved_word)) != SYMBOL) {
                pushbacktoken();
                break;
            }
            if (peekc(1) == '('/* ) */) {
                PUT(PARSER_DEF, token, lineno, sp);
                while ((c = nexttoken("()", cpp_reserved_word)) != EOF && c != '\n' && c != /* ( */ ')')
                    if (c == SYMBOL)
                        PUT(PARSER_REF_SYM, token, lineno, sp);
                if (c == '\n')
                    pushbacktoken();
            }  else {
                PUT(PARSER_DEF, token, lineno, sp);
            }
            break;
        case SHARP_IMPORT:
        case SHARP_INCLUDE:
        case SHARP_INCLUDE_NEXT:
        case SHARP_ERROR:
        case SHARP_LINE:
        case SHARP_PRAGMA:
        case SHARP_WARNING:
        case SHARP_IDENT:
        case SHARP_SCCS:
            while ((c = nexttoken(interested, cpp_reserved_word)) != EOF && c != '\n')
                ;
            break;
        case SHARP_IFDEF:
        case SHARP_IFNDEF:
        case SHARP_IF:
        case SHARP_ELIF:
        case SHARP_ELSE:
        case SHARP_ENDIF:
            condition_macro(param, cc);
            break;
        case SHARP_SHARP:		/* ## */
            (void)nexttoken(interested, cpp_reserved_word);
            break;
        case CPP_NEW:
            if ((c = nexttoken(interested, cpp_reserved_word)) == SYMBOL)
                PUT(PARSER_REF_SYM, token, lineno, sp);
            break;
        case CPP_ENUM:
        case CPP_UNION:
            while ((c = nexttoken(interested, cpp_reserved_word)) == CPP___ATTRIBUTE__)
                process_attribute(param);
            while (c == '\n')
                c = nexttoken(interested, cpp_reserved_word);
            if (c == SYMBOL) {
                if (peekc(0) == '{') { /* } */
                    PUT(PARSER_DEF, token, lineno, sp);
                } else {
                    PUT(PARSER_REF_SYM, token, lineno, sp);
                }
                c = nexttoken(interested, cpp_reserved_word);
            }
            while (c == '\n')
                c = nexttoken(interested, cpp_reserved_word);
            if (c == '{' /* } */ && cc == CPP_ENUM) {
                enumerator_list(param);
            } else {
                pushbacktoken();
            }
            break;
        case CPP_TEMPLATE:
        {
            int level = 0;

            while ((c = nexttoken("<>", cpp_reserved_word)) != EOF) {
                if (c == '<')
                    ++level;
                else if (c == '>') {
                    if (--level == 0)
                        break;
                } else if (c == SYMBOL) {
                    PUT(PARSER_REF_SYM, token, lineno, sp);
                }
            }
            if (c == EOF && (param->flags & PARSER_WARNING))
                warning("template <...> isn't closed. [+%d %s].", lineno, curfile);
        }
        break;
        case CPP_OPERATOR:
            while ((c = nexttoken(";{", /* } */ cpp_reserved_word)) != EOF) {
                if (c == '{') { /* } */
                    pushbacktoken();
                    break;
                } else if (c == ';') {
                    break;
                } else if (c == SYMBOL) {
                    PUT(PARSER_REF_SYM, token, lineno, sp);
                }
            }
            if (c == EOF && (param->flags & PARSER_WARNING))
                warning("'{' doesn't exist after 'operator'. [+%d %s].", lineno, curfile); /* } */
            break;
        /* control statement check */
        case CPP_THROW:
            startthrow = 1;
        case CPP_BREAK:
        case CPP_CASE:
        case CPP_CATCH:
        case CPP_CONTINUE:
        case CPP_DEFAULT:
        case CPP_DELETE:
        case CPP_DO:
        case CPP_ELSE:
        case CPP_FOR:
        case CPP_GOTO:
        case CPP_IF:
        case CPP_RETURN:
        case CPP_SWITCH:
        case CPP_TRY:
        case CPP_WHILE:
            if ((param->flags & PARSER_WARNING) && !startmacro && level == 0)
                warning("Out of function. %8s [+%d %s]", token, lineno, curfile);
            break;
        case CPP_TYPEDEF:
        {
            /*
             * This parser is too complex to maintain.
             * We should rewrite the whole.
             */
            char savetok[MAXTOKEN];
            int savelineno = 0;
            int typedef_savelevel = level;
            int templates = 0;

            savetok[0] = 0;

            /* skip CV qualifiers */
            do {
                c = nexttoken("{}(),;", cpp_reserved_word);
            } while (IS_CV_QUALIFIER(c) || c == '\n');

            if ((param->flags & PARSER_WARNING) && c == EOF) {
                warning("unexpected eof. [+%d %s]", lineno, curfile);
                break;
            } else if (c == CPP_ENUM || c == CPP_STRUCT || c == CPP_UNION) {
                char *interest_enum = "{},;";
                int c_ = c;

                while ((c = nexttoken(interest_enum, cpp_reserved_word)) == CPP___ATTRIBUTE__)
                    process_attribute(param);
                while (c == '\n')
                    c = nexttoken(interest_enum, cpp_reserved_word);
                /* read tag name if exist */
                if (c == SYMBOL) {
                    if (peekc(0) == '{') { /* } */
                        PUT(PARSER_DEF, token, lineno, sp);
                    } else {
                        PUT(PARSER_REF_SYM, token, lineno, sp);
                    }
                    c = nexttoken(interest_enum, cpp_reserved_word);
                }
                while (c == '\n')
                    c = nexttoken(interest_enum, cpp_reserved_word);
                if (c_ == CPP_ENUM) {
                    if (c == '{') /* } */
                        c = enumerator_list(param);
                    else
                        pushbacktoken();
                } else {
                    for (; c != EOF; c = nexttoken(interest_enum, cpp_reserved_word)) {
                        switch (c) {
                        case SHARP_IFDEF:
                        case SHARP_IFNDEF:
                        case SHARP_IF:
                        case SHARP_ELIF:
                        case SHARP_ELSE:
                        case SHARP_ENDIF:
                            condition_macro(param, c);
                            continue;
                        default:
                            break;
                        }
                        if (c == ';' && level == typedef_savelevel) {
                            if (savetok[0])
                                PUT(PARSER_DEF, savetok, savelineno, sp);
                            break;
                        } else if (c == '{')
                            level++;
                        else if (c == '}') {
                            if (--level == typedef_savelevel)
                                break;
                        } else if (c == SYMBOL) {
                            PUT(PARSER_REF_SYM, token, lineno, sp);
                            /* save lastest token */
                            strlimcpy(savetok, token, sizeof(savetok));
                            savelineno = lineno;
                        }
                    }
                    if (c == ';')
                        break;
                }
                if ((param->flags & PARSER_WARNING) && c == EOF) {
                    warning("unexpected eof. [+%d %s]", lineno, curfile);
                    break;
                }
            } else if (c == SYMBOL) {
                PUT(PARSER_REF_SYM, token, lineno, sp);
            }
            savetok[0] = 0;
            while ((c = nexttoken("()<>,;", cpp_reserved_word)) != EOF) {
                switch (c) {
                case SHARP_IFDEF:
                case SHARP_IFNDEF:
                case SHARP_IF:
                case SHARP_ELIF:
                case SHARP_ELSE:
                case SHARP_ENDIF:
                    condition_macro(param, c);
                    continue;
                default:
                    break;
                }
                if (c == '(')
                    level++;
                else if (c == ')')
                    level--;
                else if (c == '<')
                    templates++;
                else if (c == '>')
                    templates--;
                else if (c == SYMBOL) {
                    if (level > typedef_savelevel) {
                        PUT(PARSER_REF_SYM, token, lineno, sp);
                    } else {
                        /* put latest token if any */
                        if (savetok[0]) {
                            PUT(PARSER_REF_SYM, savetok, savelineno, sp);
                        }
                        /* save lastest token */
                        strlimcpy(savetok, token, sizeof(savetok));
                        savelineno = lineno;
                    }
                } else if (c == ',' || c == ';') {
                    if (savetok[0]) {
                        PUT(templates ? PARSER_REF_SYM : PARSER_DEF, savetok, lineno, sp);
                        savetok[0] = 0;
                    }
                }
                if (level == typedef_savelevel && c == ';')
                    break;
            }
            if (param->flags & PARSER_WARNING) {
                if (c == EOF)
                    warning("unexpected eof. [+%d %s]", lineno, curfile);
                else if (level != typedef_savelevel)
                    warning("unmatched () block. (last at level %d.)[+%d %s]", level, lineno, curfile);
            }
        }
        break;
        case CPP___ATTRIBUTE__:
            process_attribute(param);
            break;
        default:
            break;
        }
    }
finish:
    strbuf_close(sb);
    if (param->flags & PARSER_WARNING) {
        if (level != 0)
            warning("unmatched {} block. (last at level %d.)[+%d %s]", level, lineno, curfile);
        if (piflevel != 0)
            warning("unmatched #if block. (last at level %d.)[+%d %s]", piflevel, lineno, curfile);
    }
    closetoken();
}