Hello,

I've redone the patch because I had moved the whole arg building into the child 
process (on non-Windows) which is both inefficient and obfuscates the diff.

Regards.

-- 
Olivier Certner
--- gtags.conf.in.~1.55.~	2017-12-12 15:05:24.000000000 +0100
+++ gtags.conf.in	2023-04-07 14:39:50.709124000 +0200
@@ -181,6 +181,7 @@
 universal-ctags|setting to use Universal Ctags plug-in parser:\
 	:tc=common:\
 	:ctagscom=@UNIVERSAL_CTAGS@:\
+	:ctagsoptfile=:\
 	:ctagslib=$libdir/gtags/universal-ctags.la:\
 	:langmap=Ada\:.adb.ads.Ada:\
 	:langmap=Ant\:(build.xml)(*.build.xml).ant.xml:\
--- plugin-factory/Makefile.am.~1.13.~	2023-04-06 21:28:23.170662000 +0200
+++ plugin-factory/Makefile.am	2023-04-07 12:02:21.191300000 +0200
@@ -22,7 +22,7 @@
 exuberant_ctags_la_LDFLAGS = -module -avoid-version -no-undefined
 # Univercal Ctags parser
 universal_ctags_la_SOURCES = exuberant-ctags.c
-universal_ctags_la_CFLAGS  = -DUSE_EXTRA_FIELDS
+universal_ctags_la_CFLAGS  = -DUNIVERSAL_CTAGS_FLAVOR
 universal_ctags_la_LDFLAGS = -module -avoid-version -no-undefined
 
 # Pygments parser
--- plugin-factory/exuberant-ctags.c.~1.15.~	2021-10-26 01:00:31.000000000 +0200
+++ plugin-factory/exuberant-ctags.c	2023-04-07 14:37:28.053247000 +0200
@@ -49,6 +49,9 @@
 
 #define TERMINATOR		"###terminator###"
 #define LANGMAP_OPTION		"--langmap="
+#if defined(UNIVERSAL_CTAGS_FLAVOR)
+#define OPTIONS_OPTION		"--options="
+#endif
 #define INITIAL_BUFSIZE		1024
 
 static FILE *ip, *op;
@@ -60,13 +63,14 @@
  * In execution phase, plug-in parser get the value from the configuration file
  * (gtags.conf, $HOME/.globalrc) if it is defined.
  */
-#if defined(USE_EXTRA_FIELDS)
+#if defined(UNIVERSAL_CTAGS_FLAVOR)
 static char *ctagscom = UNIVERSAL_CTAGS;
-static const char *ctagsnotfound = "Universal Ctags not found. Please see ./configure --help.";
+static const char *ctagsnotfound = "No Universal Ctags executable specified."
 #else
 static char *ctagscom = EXUBERANT_CTAGS;
-static const char *ctagsnotfound = "Exuberant Ctags not found. Please see ./configure --help.";
+static const char *ctagsnotfound = "No Exuberant Ctags executable specified."
 #endif
+" Specify through ./configure or the 'ctagscom' configuration variable.";
 
 #ifdef __GNUC__
 static void terminate_ctags(void) __attribute__((destructor));
@@ -98,7 +102,8 @@
 #include <fcntl.h>
 static HANDLE pid;
 static char argv[] = "\" "
-#if defined(USE_EXTRA_FIELDS)
+#if defined(UNIVERSAL_CTAGS_FLAVOR)
+	"--quiet --options=NONE "
 	"\"--_xformat=%R %-16N %4n %-16F %C\" "
 	"--extras=+r "
 	"--fields=+r "
@@ -116,21 +121,58 @@
 	SECURITY_ATTRIBUTES sa;
 	STARTUPINFO si;
 	PROCESS_INFORMATION pi;
-	char* arg;
+	char* org_arg, arg;
 	char *path = param->getconf("ctagscom");
+	size_t ctagscom_len;
+	size_t const langmap_len = strlen(param->langmap);
+#ifdef UNIVERSAL_CTAGS_FLAVOR
+        char const * options_file = param->getconf("ctagsoptfile");
+	size_t full_options_file_len;
 
-	if (path && strlen(path) > 0 && strcmp(path, "no") != 0)
+	if (options_file != NULL &&
+	    (!options_file[0] || !strcmp(options_file, "no"))) {
+		free(options_file);
+		options_file = NULL;
+	}
+
+	full_options_file_len = options_file == NULL ? 0 :
+		strlen(options_file) + sizeof(OPTIONS_OPTION) - 1 + 1 /*SPACE*/;
+#endif
+
+	if (path && path[0] && strcmp(path, "no") != 0)
 		ctagscom = path;
-	if (!ctagscom || !strlen(ctagscom) || !strcmp(ctagscom, "no"))
+	if (!ctagscom || !(ctagscom_len = strlen(ctagscom)) ||
+	    !strcmp(ctagscom, "no"))
 		param->die(ctagsnotfound);
 
-	arg = malloc(1 + strlen(ctagscom) + sizeof(argv) + strlen(param->langmap));
-	if (arg == NULL)
+	org_arg = arg =
+		malloc(1 /*NUL*/ + 1 /*First double-quote*/ +
+		       ctagscom_len + sizeof(argv) - 1 + langmap_len
+#ifdef UNIVERSAL_CTAGS_FLAVOR
+		       + full_options_file_len
+#endif
+		      );
+	if (org_arg == NULL)
 		param->die("short of memory.");
-	*arg = '"';
-	strcpy(arg+1, ctagscom);
-	strcat(arg, argv);
-	copy_langmap_converting_cpp(arg + strlen(arg), param->langmap);
+	*arg++ = '"';
+	memcpy(arg, ctagscom, ctagscom_len);
+	arg += ctagscom_len;
+	free(path);
+	ctagscom = NULL; // Prevent inadvertent use-after-free
+	memcpy(arg, argv, sizeof(argv) - 1);
+	arg += sizeof(argv) - 1;
+	copy_langmap_converting_cpp(arg, param->langmap);
+	// Previous call preserves length (and inserts NUL)
+	arg += langmap_len;
+#ifdef UNIVERSAL_CTAGS_FLAVOR
+	if (options_file != NULL) {
+		*arg++ = ' ';
+		memcpy(arg, OPTIONS_OPTION, sizeof(OPTIONS_OPTION) - 1);
+		arg += sizeof(OPTIONS_OPTION) - 1;
+		strcpy(arg, options_file);
+		free(options_file);
+	}
+#endif
 
 	sa.nLength = sizeof(sa);
 	sa.bInheritHandle = TRUE;
@@ -146,8 +188,11 @@
 	si.hStdOutput = ipipe[1];
 	si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
 	si.dwFlags = STARTF_USESTDHANDLES;
-	if (!CreateProcess(NULL, arg, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
-		param->die(ctagsnotfound);
+	if (!CreateProcess(NULL, org_arg, NULL, NULL,
+			   TRUE, 0, NULL, NULL, &si, &pi))
+		param->die("cannot execute '%s'. (CreateProcess() failed)",
+			   org_arg);
+	free(org_arg);
 	CloseHandle(opipe[0]);
 	CloseHandle(ipipe[1]);
 	CloseHandle(pi.hThread);
@@ -176,9 +221,10 @@
 #include <sys/wait.h>
 static pid_t pid;
 static char *argv[] = {
-	"ctags",
-	NULL,
-#if defined(USE_EXTRA_FIELDS)
+	NULL, // Slot for program name
+#ifdef UNIVERSAL_CTAGS_FLAVOR
+	"--quiet",
+	"--options=NONE",
 	"--_xformat=%R %-16N %4n %-16F %C",
 	"--extras=+r",
 	"--fields=+r",
@@ -188,45 +234,98 @@
 	"-xu",
 	"--filter",
 	"--filter-terminator=" TERMINATOR "\n",
-	NULL
+	NULL, // Slot for LANGMAP_OPTION
+#ifdef UNIVERSAL_CTAGS_FLAVOR
+	NULL, // Slot for OPTIONS_FILE
+#endif
+	NULL // Sentinel
 };
 static void
 start_ctags(const struct parser_param *param)
 {
 	int opipe[2], ipipe[2];
 	char *path = param->getconf("ctagscom");
+	char ** const argv_last = argv +
+		(sizeof(argv) / sizeof(*argv) - 2);
+#ifdef UNIVERSAL_CTAGS_FLAVOR
+	char const * options_file = param->getconf("ctagsoptfile");
+	char ** const langmap_slot = argv_last - 1;
+	char ** const options_file_slot = argv_last;
+#else
+	char ** const langmap_slot = argv_last;
+#endif
 
-	if (path && strlen(path) > 0 && strcmp(path, "no") != 0)
+	if (path && path[0] && strcmp(path, "no") != 0)
 		ctagscom = path;
-	if (!ctagscom || !strlen(ctagscom) || !strcmp(ctagscom, "no"))
+	if (!ctagscom || !ctagscom[0] || !strcmp(ctagscom, "no"))
 		param->die(ctagsnotfound);
 	argv[0] = ctagscom;
-	argv[1] = malloc(sizeof(LANGMAP_OPTION) + strlen(param->langmap));
-	if (argv[1] == NULL)
+	*langmap_slot = malloc(1 + sizeof(LANGMAP_OPTION) - 1 +
+			       strlen(param->langmap));
+	if (*langmap_slot == NULL)
 		param->die("short of memory.");
-	memcpy(argv[1], LANGMAP_OPTION, sizeof(LANGMAP_OPTION) - 1);
-	copy_langmap_converting_cpp(argv[1] + sizeof(LANGMAP_OPTION) - 1, param->langmap);
+	memcpy(*langmap_slot, LANGMAP_OPTION,
+	       sizeof(LANGMAP_OPTION) - 1);
+	copy_langmap_converting_cpp
+		(*langmap_slot + sizeof(LANGMAP_OPTION) - 1,
+		 param->langmap);
 
+#ifdef UNIVERSAL_CTAGS_FLAVOR
+	if (options_file != NULL &&
+	    (!options_file[0] || !strcmp(options_file, "no"))) {
+		free(options_file);
+		options_file = NULL;
+		*options_file_slot = NULL;
+	}
+
+	if (options_file != NULL) {
+		size_t options_file_len = strlen(options_file);
+
+		*options_file_slot = malloc
+			(1 + sizeof(OPTIONS_OPTION) - 1 + options_file_len);
+		if (*options_file_slot == NULL)
+			param->die("short of memory.");
+		memcpy(*options_file_slot,
+		       OPTIONS_OPTION, sizeof(OPTIONS_OPTION) - 1);
+		memcpy(*options_file_slot + sizeof(OPTIONS_OPTION) - 1,
+		       options_file, options_file_len);
+		(*options_file_slot)
+			[sizeof(OPTIONS_OPTION) - 1 + options_file_len] = 0;
+
+		free(options_file);
+	}
+#endif
+
 	if (pipe(opipe) < 0 || pipe(ipipe) < 0)
 		param->die("cannot create pipe.");
+
 	pid = fork();
+
 	if (pid == 0) {
 		/* child process */
 		close(opipe[1]);
 		close(ipipe[0]);
 		if (dup2(opipe[0], STDIN_FILENO) < 0
-		 || dup2(ipipe[1], STDOUT_FILENO) < 0)
+		    || dup2(ipipe[1], STDOUT_FILENO) < 0)
 			param->die("dup2 failed.");
 		close(opipe[0]);
 		close(ipipe[1]);
+
 		execvp(ctagscom, argv);
-		param->die("cannot execute '%s'. (execvp failed)", ctagscom);
+
+		param->die("cannot execute '%s'. (execvp() failed)", ctagscom);
 	}
+
 	/* parent process */
 	if (pid < 0)
 		param->die("fork failed.");
+
 	free(path);
-	free(argv[1]);
+	free(*langmap_slot);
+#ifdef UNIVERSAL_CTAGS_FLAVOR
+	free(*options_file_slot);
+#endif
+
 	close(opipe[0]);
 	close(ipipe[1]);
 	ip = fdopen(ipipe[0], "r");
@@ -286,7 +385,7 @@
 	int type = PARSER_DEF;
 	char *p, *tagname, *filename;
 
-#if defined(USE_EXTRA_FIELDS)
+#if defined(UNIVERSAL_CTAGS_FLAVOR)
 	/*
 	 * Output of ctags:
 	 * ctags -x ...

Reply via email to