Index: gtags.conf.in
===================================================================
RCS file: /sources/global/global/gtags.conf.in,v
retrieving revision 1.20
diff -u -p -r1.20 gtags.conf.in
--- gtags.conf.in	30 Oct 2009 16:20:26 -0000	1.20
+++ gtags.conf.in	17 Nov 2009 23:04:45 -0000
@@ -52,6 +52,8 @@ gtags:\
 #
 # 2-pass mode (experimental)
 #
+2pass:\
+	:tc=gtags-2pass:tc=htags:
 gtags-2pass:\
 	:tc=common:\
 	:GTAGS=gtags-parser %s:\
Index: global/global.c
===================================================================
RCS file: /sources/global/global/global/global.c,v
retrieving revision 1.200
diff -u -p -r1.200 global.c
--- global/global.c	12 Nov 2009 12:36:43 -0000	1.200
+++ global/global.c	17 Nov 2009 23:04:45 -0000
@@ -53,7 +53,7 @@ void completion(const char *, const char
 void idutils(const char *, const char *);
 void grep(const char *, const char *);
 void pathlist(const char *, const char *);
-void parsefile(int, char *const *, const char *, const char *, const char *, int);
+void parsefile(char *const *, const char *, const char *, const char *, int);
 int search(const char *, const char *, const char *, const char *, int);
 void tagsearch(const char *, const char *, const char *, const char *, int);
 void encode(char *, int, const char *);
@@ -92,6 +92,7 @@ char root[MAXPATHLEN+1];		/* root of sou
 char dbpath[MAXPATHLEN+1];		/* dbpath directory	*/
 char *context_file;
 char *context_lineno;
+const char *args_file;
 
 static void
 usage(void)
@@ -110,6 +111,7 @@ help(void)
 
 #define RESULT		128
 #define FROM_HERE	129
+#define ARGS_FILE	130
 #define SORT_FILTER     1
 #define PATH_FILTER     2
 #define BOTH_FILTER     (SORT_FILTER|PATH_FILTER)
@@ -140,6 +142,7 @@ static struct option const long_options[
 	{"cxref", no_argument, NULL, 'x'},
 
 	/* long name only */
+	{"args-file", required_argument, NULL, ARGS_FILE},
 	{"from-here", required_argument, NULL, FROM_HERE},
 	{"debug", no_argument, &debug, 1},
 	{"version", no_argument, &show_version, 1},
@@ -306,6 +309,9 @@ main(int argc, char **argv)
 		case 'x':
 			xflag++;
 			break;
+		case ARGS_FILE:
+			args_file = optarg;
+			break;
 		case FROM_HERE:
 			{
 			char *p = optarg;
@@ -374,6 +380,10 @@ main(int argc, char **argv)
 		case 'p':
 		case 'P':
 			break;
+		case 'f':
+			if (args_file == NULL)
+				usage();
+			break;
 		default:
 			usage();
 			break;
@@ -404,6 +414,17 @@ main(int argc, char **argv)
 	if (cflag && av && isregex(av))
 		die_with_code(2, "only name char is allowed with -c option.");
 	/*
+	 * If the args_file other than "-" is given, it must be readable file.
+	 */
+	if (args_file != NULL && strcmp(args_file, "-") != 0) {
+		if (test("d", args_file))
+			die("'%s' is a directory.", args_file);
+		else if (!test("f", args_file))
+			die("'%s' not found.", args_file);
+		else if (!test("r", args_file))
+			die("'%s' is not readable.", args_file);
+	}
+	/*
 	 * get path of following directories.
 	 *	o current directory
 	 *	o root of source tree
@@ -530,7 +551,7 @@ main(int argc, char **argv)
 	 * parse source files.
 	 */
 	else if (fflag) {
-		parsefile(argc, argv, cwd, root, dbpath, db);
+		parsefile(argv, cwd, root, dbpath, db);
 	}
 	/*
 	 * tag search.
@@ -857,7 +878,6 @@ pathlist(const char *pattern, const char
 /*
  * parsefile: parse file to pick up tags.
  *
- *	i)	argc
  *	i)	argv
  *	i)	cwd	current directory
  *	i)	root	root directory of source tree
@@ -865,17 +885,39 @@ pathlist(const char *pattern, const char
  *	i)	db	type of parse
  */
 void
-parsefile(int argc, char *const *argv, const char *cwd, const char *root, const char *dbpath, int db)
+parsefile(char *const *argv, const char *cwd, const char *root, const char *dbpath, int db)
 {
 	CONVERT *cv;
 	int count = 0;
 	int file_count = 0;
 	STRBUF *comline = strbuf_open(0);
-	STRBUF *path_list = strbuf_open(MAXPATHLEN);
+	STRBUF *ib = NULL, *pathlist_sb = NULL;
+	FILE *ip = NULL, *pathlist_fp = NULL;
+	const char *av;
 	XARGS *xp;
 	char *ctags_x;
 	int skip_defined = 0, skip_undefined = 0;
 
+	/*
+	 * Expanding strbuf frequently spends much CPU cycles for mremap(2) system call.
+	 * When args_file is specified, use the temporary file to avoid it.
+	 */
+	if (args_file != NULL) {
+		if (strcmp(args_file, "-") == 0) {
+			ip = stdin;
+		} else {
+			ip = fopen(args_file, "r");
+			if (ip == NULL)
+				 die("cannot open '%s'.", args_file);
+		}
+		ib = strbuf_open(0);
+		pathlist_fp = tmpfile();
+		if (pathlist_fp == NULL)
+			die("cannot make temporary file.");
+	} else {
+		pathlist_sb = strbuf_open(MAXPATHLEN);
+	}
+
 	if (getconfb("use_2pass_parser")) {
 		if (db == GRTAGS) {
 			skip_undefined = 1;
@@ -909,12 +951,14 @@ parsefile(int argc, char *const *argv, c
 	/*
 	 * Make a path list while checking the validity of path name.
 	 */
-	for (; argc > 0; argv++, argc--) {
-		const char *av = argv[0];
+	while ((av = (ip != NULL) ? strbuf_fgets(ib, ip, STRBUF_NOCRLF) : *argv++) != NULL) {
 		char path[MAXPATHLEN+1];
 
+		/* skip empty line. */
+		if (ip != NULL && *av == '\0')
+			continue;
 		/*
-		 * convert the path into relative from the root directory of source tree.
+		 * convert the path into relative to the root directory of source tree.
 		 */
 		if (normalize(av, get_root_with_slash(), cwd, path, sizeof(path)) == NULL)
 			if (!qflag)
@@ -939,16 +983,29 @@ parsefile(int argc, char *const *argv, c
 		/*
 		 * Add a path to the path list.
 		 */
-		strbuf_puts0(path_list, path);
+		if (pathlist_fp != NULL) {
+			fputs(path, pathlist_fp);
+			putc('\n', pathlist_fp);
+		} else {
+			strbuf_puts0(pathlist_sb, path);
+		}
 		file_count++;
 	}
+	if (ip != NULL) {
+		if (ip != stdin)
+			fclose(ip);
+		strbuf_close(ib);
+	}
 	if (file_count > 0) {
 		/*
 		 * Execute parser in the root directory of source tree.
 		 */
 		if (chdir(root) < 0)
 			die("cannot move to '%s' directory.", root);
-		xp = xargs_open_with_strbuf(strbuf_value(comline), 0, path_list);
+		if (pathlist_fp != NULL)
+			xp = xargs_open_with_file(strbuf_value(comline), 0, pathlist_fp);
+		else
+			xp = xargs_open_with_strbuf(strbuf_value(comline), 0, pathlist_sb);
 		if (format == FORMAT_PATH) {
 			SPLIT ptable;
 			char curpath[MAXPATHLEN+1];
@@ -996,9 +1053,13 @@ parsefile(int argc, char *const *argv, c
 	gpath_close();
 	convert_close(cv);
 	strbuf_close(comline);
-	strbuf_close(path_list);
-	if (file_count == 0)
-		die("file not found.");
+	if (pathlist_fp != NULL) {
+		fclose(pathlist_fp);
+	} else {
+		strbuf_close(pathlist_sb);
+		if (file_count == 0)
+			die("file not found.");
+	}
 	if (vflag) {
 		print_count(count);
 		fprintf(stderr, " (no index used).\n");
Index: global/manual.in
===================================================================
RCS file: /sources/global/global/global/manual.in,v
retrieving revision 1.52
diff -u -p -r1.52 manual.in
--- global/manual.in	25 Feb 2009 00:41:14 -0000	1.52
+++ global/manual.in	17 Nov 2009 23:04:45 -0000
@@ -84,6 +84,11 @@
 	@begin_itemize
 	@item{@option{-a}, @option{--absolute}}
 		Print absolute path name. By default, print relative path name.
+	@item{@option{--args-file} @arg{file}}
+		Read from @arg{file} a list of arguments.
+		If @arg{file} is @file{-}, read from standard input.
+		Arguments must be separated by newline.
+		This option can be used only with the @option{-f} command now.
 	@item{@option{--from-here} @arg{context}}
 		Decide tag type by the context. The @arg{context} must be 'lineno:path'.
 		If this option is specified then the @option{-s} and @option{-r}
Index: htags/anchor.c
===================================================================
RCS file: /sources/global/global/htags/anchor.c,v
retrieving revision 1.34
diff -u -p -r1.34 anchor.c
--- htags/anchor.c	12 Nov 2009 12:36:44 -0000	1.34
+++ htags/anchor.c	17 Nov 2009 23:04:45 -0000
@@ -32,10 +32,18 @@
 #ifdef HAVE_CTYPE_H
 #include <ctype.h>
 #endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
 #include "global.h"
 #include "anchor.h"
 #include "htags.h"
 
+#if (defined(_WIN32) && !defined(__CYGWIN__))
+#define mkstemp(p) open(_mktemp(p), _O_CREAT | _O_SHORT_LIVED | _O_EXCL)
+#endif
+
+static char pathlist_name[MAXPATHLEN+1];
 static XARGS *anchor_input[GTAGLIM];
 static struct anchor *table;
 static VARRAY *vb;
@@ -60,24 +68,40 @@ static struct anchor *CURRENTDEF;
 
 /*
  * anchor_prepare: setup input stream.
- *
- *	i)	anchor_stream	file pointer of path list
  */
 void
-anchor_prepare(FILE *anchor_stream)
+anchor_prepare(void)
 {
-	/*
-	 * Option table:
-	 * We use blank string as null option instead of null string("")
-	 * not to change the command length. This length influences
-	 * the number of arguments in the xargs processing.
-	 */
-	static const char *const options[] = {NULL, " ", "r", "s"};
+	static const char *const options[] = {NULL, "", "r", "s"};
 	char comline[MAXFILLEN];
 	int db;
+	static char *const argv[2] = {pathlist_name, NULL};
+	int fd;
+	GFIND *gp;
+	const char *path;
+	FILE *fp;
+
+	/* Create the list of file which should be parsed. */
+	snprintf(pathlist_name, sizeof(pathlist_name), "%s/pathlist.XXXXXX", tmpdir);
+	fd = mkstemp(pathlist_name);
+	if (fd == -1) {
+		pathlist_name[0] = '\0';
+		die("cannot make temporary file.");
+	}
+	fp = fdopen(fd, "w");
+	if (fp == NULL)
+		die("fdopen failed.");
+	gp = gfind_open(dbpath, NULL, GPATH_SOURCE);
+	while ((path = gfind_read(gp)) != NULL) {
+		fputs(path, fp);
+		putc('\n', fp);
+	}
+	gfind_close(gp);
+	fclose(fp);
 
 	for (db = GTAGS; db < GTAGLIM; db++) {
-		anchor_input[db] = NULL;
+		if (!gtags_exist[db])
+			continue;
 		/*
 		 * Htags(1) should not use gtags-parser(1) directly;
 		 * it should use global(1) with the -f option instead.
@@ -91,10 +115,19 @@ anchor_prepare(FILE *anchor_stream)
 		 * by the path, it is guaranteed that the records concerning
 		 * the same file are consecutive.
 		 */
-		if (gtags_exist[db] == 1) {
-			snprintf(comline, sizeof(comline), "%s -f%s --nofilter=path", global_path, options[db]);
-			anchor_input[db] = xargs_open_with_file(comline, 0, anchor_stream);
-		}
+		snprintf(comline, sizeof(comline), "%s -f%s --nofilter=path --args-file", global_path, options[db]);
+		anchor_input[db] = xargs_open_with_argv(comline, 0, 1, argv);
+	}
+}
+/*
+ * anchor_close: remove temporary file
+ */
+void
+anchor_close(void)
+{
+	if (pathlist_name[0] != '\0') {
+		unlink(pathlist_name);
+		pathlist_name[0] = '\0';
 	}
 }
 /*
Index: htags/anchor.h
===================================================================
RCS file: /sources/global/global/htags/anchor.h,v
retrieving revision 1.16
diff -u -p -r1.16 anchor.h
--- htags/anchor.h	5 Jul 2007 06:52:00 -0000	1.16
+++ htags/anchor.h	17 Nov 2009 23:04:45 -0000
@@ -63,7 +63,8 @@ struct anchor {
 #define A_HELP		7
 #define A_LIMIT		8
 
-void anchor_prepare(FILE *);
+void anchor_prepare(void);
+void anchor_close(void);
 void anchor_load(const char *);
 void anchor_unload(void);
 struct anchor *anchor_first(void);
Index: htags/htags.c
===================================================================
RCS file: /sources/global/global/htags/htags.c,v
retrieving revision 1.134
diff -u -p -r1.134 htags.c
--- htags/htags.c	16 Nov 2009 15:15:56 -0000	1.134
+++ htags/htags.c	17 Nov 2009 23:04:45 -0000
@@ -331,6 +331,7 @@ clean(void)
 {
 	unload_gpath();
 	cache_close();
+	anchor_close();
 }
 /*
  * Signal handler.
@@ -815,26 +816,13 @@ static void
 makehtml(int total)
 {
 	GFIND *gp;
-	FILE *anchor_stream;
 	const char *path;
 	int count = 0;
 
 	/*
-	 * Create anchor stream for anchor_load().
-	 */
-	anchor_stream = tmpfile();
-	gp = gfind_open(dbpath, NULL, other_files ? GPATH_BOTH : GPATH_SOURCE);
-	while ((path = gfind_read(gp)) != NULL) {
-		if (gp->type == GPATH_OTHER)
-			fputc(' ', anchor_stream);
-		fputs(path, anchor_stream);
-		fputc('\n', anchor_stream);
-	}
-	gfind_close(gp);
-	/*
 	 * Prepare anchor stream for anchor_load().
 	 */
-	anchor_prepare(anchor_stream);
+	anchor_prepare();
 	/*
 	 * For each path in GPATH, convert the path into HTML file.
 	 */
