Index: gtags/gtags.c
===================================================================
RCS file: /cvsroot/global/global/gtags/gtags.c,v
retrieving revision 1.122
diff -u -r1.122 gtags.c
--- gtags/gtags.c	6 Jul 2005 12:01:15 -0000	1.122
+++ gtags/gtags.c	18 Jul 2005 15:39:45 -0000
@@ -75,6 +75,7 @@
 int printconf(const char *);
 void set_base_directory(const char *, const char *);
 void put_converting(const char *, int, int);
+static void ctags2gtags(const char *, const char *, const char *);
 
 int cflag;					/* compact format */
 int iflag;					/* incremental update */
@@ -99,8 +100,10 @@
 int debug;
 int secure_mode;
 int noxargs;
+int do_ctags2gtags;
 const char *extra_options;
 const char *info_string;
+const char *ctags_tagfile = "tags";
 
 int extractmethod;
 int total;
@@ -133,6 +136,8 @@
 	/* long name only */
 	{"config", optional_argument, &show_config, 1},
 	{"convert", no_argument, &do_convert, 1},
+	{"ctags2gtags", no_argument, &do_ctags2gtags, 1},
+	{"ctags-tagfile", required_argument, NULL, 0},
 	{"debug", no_argument, &debug, 1},
 	{"expand", required_argument, &do_expand, 1},
 	{"find", no_argument, &do_find, 1},
@@ -227,6 +232,8 @@
 				}
 				set_env(name, value);
 				gtagsconf = gtagslabel = 0;
+			} else if (!strcmp(p, "ctags-tagfile")) {
+				ctags_tagfile = optarg;
 			}
 			break;
 		case 'c':
@@ -534,6 +541,15 @@
 	if (cflag == 0 && getconfs("format", sb) && !strcmp(strbuf_value(sb), "compact"))
 		cflag++;
 	/*
+	 * convert ctags tagfile
+	 */
+	if (do_ctags2gtags) {
+		ctags2gtags(dbpath, cwd, ctags_tagfile);
+		if (vflag)
+			fprintf(stderr, "[%s] Done.\n", now());
+		exit(0);
+	}
+	/*
 	 * Pass the following information to gtags-parser(1)
 	 * using environment variable.
 	 *
@@ -1115,4 +1131,190 @@
 	 * print the rest of the record.
 	 */
 	(void)fputs(p, stdout);
+}
+/*
+ * ctags2gtags: convert ctags tagfile into GPATH and GTAGS
+ *
+ *	i)	dbpath		dbpath directory
+ *	i)	root		root directory of source tree
+ *	i)	ctags_tagfile	tagfile created by ctags
+ */
+static void
+ctags2gtags(dbpath, root, ctags_tagfile)
+	const char *dbpath;
+	const char *root;
+	const char *ctags_tagfile;
+{
+	GTOP *gtop;
+	int flags;
+	FILE *ip;
+	char command[MAXFILLEN];
+	STRBUF *ib = strbuf_open(MAXBUFLEN);
+	STRBUF *sb = strbuf_open(0);
+	STRBUF *pattern = strbuf_open(0);
+	char *line, *tag, *p, *path, *image = NULL;
+	char buf[MAXPATHLEN + 1];
+	char prev_path[MAXPATHLEN + 1];
+	int c, lno, maxline = 0;
+
+	flags = 0;
+	/*
+	 * Compact format:
+	 *
+	 * -c: COMPACT format.
+	 * -cc: PATHINDEX format.
+	 * Ths -cc is undocumented.
+	 * In the future, it may become the standard format of GLOBAL.
+	 */
+	if (cflag) {
+		flags |= GTAGS_PATHINDEX;
+#if 0
+		if (cflag == 1)
+			flags |= GTAGS_COMPACT;
+#endif
+	}
+	gtop = gtags_open(dbpath, root, GTAGS, GTAGS_CREATE, flags);
+
+	if (ctags_tagfile[0] == '-' && ctags_tagfile[1] == '\0') {
+		snprintf(command, sizeof(command), "gnusort -t '\t' -k 2,2");
+	} else {
+		if (test("d", ctags_tagfile))
+			die("'%s' is a directory.", ctags_tagfile);
+		if (!test("f", ctags_tagfile))
+			die("'%s' not found.", ctags_tagfile);
+		if (!test("r", ctags_tagfile))
+			die("'%s' is not readable.", ctags_tagfile);
+		snprintf(command, sizeof(command), "gnusort -t '\t' -k 2,2 %s", ctags_tagfile);
+	}
+	ip = popen(command, "r");
+	if (ip == NULL)
+		die("cannot execute '%s'.", command);
+
+	signal_setup();
+	prev_path[0] = '\0';
+	while ((line = strbuf_fgets(ib, ip, STRBUF_NOCRLF)) != NULL) {
+		if (exitflag)
+			break;
+
+		/*
+		 * pseudo tag starts with "!_"
+		 */
+		if (line[0] == '!' && line[1] == '_')
+			continue;
+
+		p = strchr(line, '\t');
+		if (p == NULL)
+			continue;
+		*p++ = '\0';
+
+		if (strchr(line, ' ')) {
+			if (!qflag)
+				warning("'%s' ignored, because it includes blank.", line);
+			continue;
+		}
+
+		if ((tag = locatestring(line, ".", MATCH_LAST)) != NULL)
+			tag++;
+		else if ((tag = locatestring(line, "::", MATCH_LAST)) != NULL)
+			tag += 2;
+		else
+			tag = line;
+
+		path = p;
+		p = strchr(path, '\t');
+		if (p == NULL)
+			continue;
+		*p++ = '\0';
+
+		if (realpath(path, buf) == NULL)
+			die("realpath(%s, buf) failed. (errno=%d).", path, errno);
+		if (!isabspath(buf))
+			die("realpath(3) is not compatible with BSD version.");
+		if (strncmp(buf, root, strlen(root))) {
+			if (!qflag)
+				fprintf(stderr, "'%s' is out of source tree.\n", buf);
+			continue;
+		}
+		path = buf + strlen(root) - 1;
+		*path = '.';
+
+		if (strchr(path, ' ')) {
+			if (!qflag)
+				warning("'%s' ignored, because it includes blank.", path + 2);
+			continue;
+		}
+
+		if (strcmp(prev_path, path) != 0) {
+			extern VARRAY *vb;
+
+			gpath_put(path);
+			if (prev_path[0] != '\0')
+				linetable_close();
+			if (linetable_open(path) != 0)
+				die("cannot open '%s'.", path);
+			maxline = vb->length;
+			for (lno = 2; lno <= maxline; lno++)
+				linetable_get(lno, NULL)[-1] = '\0';
+			if (maxline != 0) {
+				char *q = strchr(linetable_get(maxline, NULL), '\n');
+
+				if (q != NULL)
+					*q = '\0';
+			}
+			strlimcpy(prev_path, path, sizeof(prev_path));
+		}
+
+		c = (unsigned char)*p;
+		if (c == '/' || c == '?') {
+			p++;
+			if (*p == '^')
+				p++;
+			strbuf_reset(pattern);
+			while (*p != '\0') {
+				if (*p == c)
+					break;
+				if (*p == '\\')
+					p++;
+				if (*p == '\0')
+					break;
+				if (*p == '$' && *(p + 1) == c)
+					break;
+				strbuf_putc(pattern, *p);
+				p++;
+			}
+			if (*p == '\0')
+				continue;
+			for (lno = 1; lno <= maxline; lno++) {
+				image = linetable_get(lno, NULL);
+				if (locatestring(image, strbuf_value(pattern), MATCH_FIRST))
+					break;
+			}
+			if (lno > maxline)
+				continue;
+		} else if (isdigit(c)) {
+			lno = atoi(p);
+			if (lno < 1 || lno > maxline)
+				continue;
+			image = linetable_get(lno, NULL);
+		} else {
+			continue;
+		}
+
+		strbuf_reset(sb);
+		strbuf_sprintf(sb, "%-16s %4d %-16s %s", line, lno, path, image);
+		strbuf_trim(sb);
+		gtags_put(gtop, tag, strbuf_value(sb));
+	}
+
+	if (prev_path[0] != '\0')
+		linetable_close();
+	gtags_close(gtop);
+	if (pclose(ip) != 0)
+		die("'%s' failed.", command);
+	strbuf_close(sb);
+	strbuf_close(ib);
+	strbuf_close(pattern);
+
+	if (exitflag)
+		exit(1);
 }
Index: gtags/manual.in
===================================================================
RCS file: /cvsroot/global/global/gtags/manual.in,v
retrieving revision 1.46
diff -u -r1.46 manual.in
--- gtags/manual.in	5 Jul 2005 12:51:52 -0000	1.46
+++ gtags/manual.in	18 Jul 2005 15:39:45 -0000
@@ -55,6 +55,11 @@
 	@item{@option{--config} @arg{name}}
 		Show the value of config variable @arg{name}.
 		If @arg{name} is not specified then show whole of config entry.
+	@item{@option{--ctags2gtags}}
+		Convert ctags tagfile into @file{GPATH} and @file{GTAGS}.
+	@item{@option{--ctags-tagfile} @arg{file}}
+		Specifies ctags tagfile for @option{--ctags2gtags}.
+		The default is @file{tags}.
 	@item{@option{--gtagsconf} @arg{file}}
 		Load user's configuration from @arg{file}.
 	@item{@option{--gtagslabel} @arg{label}}
