[PATCH Variant A] hgexe: adding new hgexe.c

Adrian Buehlmann adrian at cadifra.com
Thu Jun 28 15:10:37 CDT 2012


# HG changeset patch
# User Adrian Buehlmann <adrian at cadifra.com>
# Date 1340914025 -7200
# Node ID 76023d6a977b51a4088377fc9afc6a777d1ec658
# Parent  0a413b28fdd193483e544c1c1412985356ce0b6e
hgexe: adding new hgexe.c

diff --git a/mercurial/hgexe.c b/mercurial/hgexe.c
new file mode 100644
--- /dev/null
+++ b/mercurial/hgexe.c
@@ -0,0 +1,117 @@
+/*
+hgexe.c - wrapper for calling Mercurial on Windows
+
+Copyright (c) 2012 Adrian Buehlmann and other contributors
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include <Python.h>
+#include <windows.h>
+
+
+#ifdef __GNUC__
+int strcat_s(char *d, size_t n, const char *s)
+{
+	return !strncat(d, s, n);
+}
+#endif
+
+
+static char pyscript[MAX_PATH + 10];
+
+int main(int argc, char *argv[])
+{
+	char* dot;
+	int ret;
+	int i;
+	int n;
+	char **pyargv;
+	WIN32_FIND_DATA fdata;
+	HANDLE hfind;
+	const char *err;
+
+	if (GetModuleFileName(NULL, pyscript, sizeof(pyscript)) == 0)
+	{
+		err = "GetModuleFileName failed";
+		goto bail;
+	}
+
+	dot = strrchr(pyscript, '.');
+	if (dot == NULL) {
+		err = "malformed module filename";
+		goto bail;
+	}
+	*dot = 0; /* cut trailing ".exe" */
+
+	hfind = FindFirstFile(pyscript, &fdata);
+	if (hfind != INVALID_HANDLE_VALUE) {
+		/* pyscript exists, close handle */
+		FindClose(hfind);
+	} else {
+		/* file pyscript isn't there, take <pyscript>exe.py */
+		strcat_s(pyscript, sizeof(pyscript), "exe.py");
+	}
+
+	/*
+	Only add the pyscript to the args, if it's not already there. It may
+	already be there, if Mercurial spawned a child process of itself, in
+	the same way as it got called, that is, with the pyscript already in
+	place. So we optionally accept the pyscript as the first argument
+	(argv[1]), letting our exe taking the role of the python interpreter.
+	*/
+	if (argc >= 2 && strcmp(argv[1], pyscript) == 0) {
+		/*
+		pyscript is already in the args, so there is no need to copy
+		the args and we can directly call the python interpreter with
+		the original args.
+		*/
+		return Py_Main(argc, argv);
+	}
+
+	/*
+	Start assembling the args for the Python interpreter call. We put the
+	name of our exe (argv[0]) in the position where the python.exe
+	canonically is,	and insert the pyscript next.
+	*/
+	pyargv = malloc((argc + 5) * sizeof(char*));
+	if (pyargv == NULL) {
+		err = "not enough memory";
+		goto bail;
+	}
+	n = 0;
+	pyargv[n++] = argv[0];
+	pyargv[n++] = pyscript;
+
+	/* copy remaining args from the command line */
+	for (i = 1; i < argc; i++)
+		pyargv[n++] = argv[i];
+	/* argv[argc] is guaranteed to be NULL, so we forward that guarantee */
+	pyargv[n] = NULL;
+
+	ret = Py_Main(n, pyargv); /* The Python interpreter call */
+
+	free(pyargv);
+	return ret;
+
+bail:
+	fprintf(stderr, "abort: %s\n", err);
+	return 255;
+}


More information about the Mercurial-devel mailing list