[geany/geany] 1d5d4e: Implement the run helper as a script
Colomban Wendling
git-noreply at geany.org
Sun Nov 13 13:55:42 UTC 2016
Branch: refs/heads/master
Author: Colomban Wendling <ban at herbesfolles.org>
Committer: Enrico Tröger <enrico.troeger at uvena.de>
Date: Sun, 13 Nov 2016 13:55:42 UTC
Commit: 1d5d4e278ab5a9e4f364f4534e39048f613748b4
https://github.com/geany/geany/commit/1d5d4e278ab5a9e4f364f4534e39048f613748b4
Log Message:
-----------
Implement the run helper as a script
Apparently using arguments instead of putting paths directly in the
script is enough for it to work on Windows, so use a simple script
instead of a program, so it's both shorter and easier to tune.
Modified Paths:
--------------
src/Makefile.am
src/build.c
src/geany-run-helper
src/geany-run-helper.bat
src/geany-run-helper.c
src/win32.c
src/win32.h
Modified: src/Makefile.am
10 lines changed, 6 insertions(+), 4 deletions(-)
===================================================================
@@ -184,10 +184,12 @@ signallist.i: $(glade_file) Makefile
CLEANFILES += signallist.i
-pkglibexec_PROGRAMS = geany-run-helper
-geany_run_helper_SOURCES = geany-run-helper.c
-geany_run_helper_CFLAGS = $(GTK_CFLAGS)
-geany_run_helper_LDADD = $(GTK_LIBS)
+# install the run script
+if MINGW
+pkglibexec_SCRIPTS = geany-run-helper.bat
+else
+pkglibexec_SCRIPTS = geany-run-helper
+endif
# Ubuntu ld has a bug so that libtool sees /usr/local/lib as a system path so
# doesn't add RPATH, but ld requires explicit ldconfig there, unlike when
Modified: src/build.c
37 lines changed, 20 insertions(+), 17 deletions(-)
===================================================================
@@ -79,12 +79,6 @@ typedef struct RunInfo
static RunInfo *run_info;
-#ifdef G_OS_WIN32
-static const gchar RUN_SCRIPT_CMD[] = "geany_run_script_XXXXXX.bat";
-#else
-static const gchar RUN_SCRIPT_CMD[] = "geany_run_script_XXXXXX.sh";
-#endif
-
/* pack group (<8) and command (<32) into a user_data pointer */
#define GRP_CMD_TO_POINTER(grp, cmd) GUINT_TO_POINTER((((grp)&7) << 5) | ((cmd)&0x1f))
#define GBO_TO_POINTER(gbo) (GRP_CMD_TO_POINTER(GBO_TO_GBG(gbo), GBO_TO_CMD(gbo)))
@@ -749,13 +743,15 @@ static void build_spawn_cmd(GeanyDocument *doc, const gchar *cmd, const gchar *d
msgwin_compiler_add(COLOR_BLUE, _("%s (in directory: %s)"), cmd, utf8_working_dir);
g_free(utf8_working_dir);
+#ifdef G_OS_UNIX
cmd_string = utils_get_locale_from_utf8(cmd);
argv[2] = cmd_string;
-
-#ifdef G_OS_UNIX
cmd = NULL; /* under Unix, use argv to start cmd via sh for compatibility */
#else
+ /* Expand environment variables like %blah%. */
+ cmd_string = win32_expand_environment_variables(cmd);
argv[0] = NULL; /* under Windows, run cmd directly */
+ cmd = cmd_string;
#endif
/* set the build info for the message window */
@@ -789,7 +785,6 @@ static gchar *prepare_run_cmd(GeanyDocument *doc, gchar **working_dir, guint cmd
const gchar *cmd_working_dir;
gboolean autoclose = FALSE;
gchar *cmd_string_utf8, *working_dir_utf8, *run_cmd, *cmd_string;
- GError *error = NULL;
cmd = get_build_cmd(doc, GEANY_GBG_EXEC, cmdindex, NULL);
@@ -825,13 +820,22 @@ static gchar *prepare_run_cmd(GeanyDocument *doc, gchar **working_dir, guint cmd
}
#endif
+#ifdef G_OS_WIN32
+ /* Expand environment variables like %blah%. */
+ SETPTR(cmd_string, win32_expand_environment_variables(cmd_string));
+#endif
+
gchar *helper = g_build_filename(utils_resource_dir(RESOURCE_DIR_LIBEXEC), "geany-run-helper", NULL);
- // FIXME: should we expand environment variables? build_create_shell_script() did
- ///* Expand environment variables like %blah%. */
- //expanded_cmd = win32_expand_environment_variables(cmd);
- // FIXME: proper quoting of the helper (or not, because it ought to be a valid path,
- // and valid paths can't contain \es or "es, so it's fine.
- SETPTR(run_cmd, g_strdup_printf("\"%s\" %d %s", helper, !!autoclose, cmd_string));
+
+ /* escape helper appropriately */
+#ifdef G_OS_WIN32
+ /* FIXME: check the Windows rules, but it should not matter too much here as \es and "es are not
+ * allowed in paths anyway */
+ SETPTR(helper, g_strdup_printf("\"%s\"", helper));
+#else
+ SETPTR(helper, g_shell_quote(helper));
+#endif
+ run_cmd = g_strdup_printf("%s %d %s", helper, autoclose ? 1 : 0, cmd_string);
g_free(helper);
utils_free_pointers(3, cmd_string_utf8, working_dir_utf8, cmd_string, NULL);
@@ -898,7 +902,7 @@ static void build_run_cmd(GeanyDocument *doc, guint cmdindex)
GString *escaped_run_cmd = g_string_new(NULL);
for (gchar *p = run_cmd; *p; p++)
{
- if (strchr("()%!^\"<>&|", *p)) // cmd.exe metacharacters
+ if (strchr("()%!^\"<>&| ", *p)) // cmd.exe metacharacters
g_string_append_c(escaped_run_cmd, '^');
g_string_append_c(escaped_run_cmd, *p);
}
@@ -922,7 +926,6 @@ static void build_run_cmd(GeanyDocument *doc, guint cmdindex)
"Check the Terminal setting in Preferences"), utf8_term_cmd, error->message);
g_free(utf8_term_cmd);
g_error_free(error);
- g_unlink(run_cmd);
run_info[cmdindex].pid = (GPid) 0;
}
}
Modified: src/geany-run-helper
25 lines changed, 25 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,25 @@
+#!/bin/sh
+# USAGE: geany-run-helper AUTOCLOSE COMMAND...
+
+# save autoclose option and remove it
+autoclose=$1
+shift
+
+# spawn the child
+"$@"
+
+# show the result
+echo "
+
+------------------
+(program exited with code: $?)
+"
+
+# and if wanted, wait on the user
+if ! [ "$autoclose" = 0 ]
+then
+ echo "Press return to continue"
+ # to be more compatible with shells like dash
+ dummy_var=
+ read dummy_var
+fi
Modified: src/geany-run-helper.bat
27 lines changed, 27 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,27 @@
+REM USAGE: geany-run-helper AUTOCLOSE COMMAND...
+
+REM save autoclose option and remove it
+set autoclose=%1
+shift
+
+REM spawn the child
+REM it's tricky because shift doesn't affect %*, so hack it out
+REM https://en.wikibooks.org/wiki/Windows_Batch_Scripting#Command-line_arguments
+set SPAWN=
+:argloop
+if -%1-==-- goto argloop_end
+ set SPAWN=%SPAWN% %1
+ shift
+goto argloop
+:argloop_end
+%SPAWN%
+
+REM show the result
+echo:
+echo:
+echo:------------------
+echo:(program exited with code: %ERRORLEVEL%)
+echo:
+
+REM and if wanted, wait on the user
+if not %autoclose%==1 pause
Modified: src/geany-run-helper.c
208 lines changed, 0 insertions(+), 208 deletions(-)
===================================================================
@@ -1,208 +0,0 @@
-/*
- * geany-run-helper.c - this file is part of Geany, a fast and lightweight IDE
- *
- * Copyright 2016 Colomban Wendling <ban(at)herbesfolles(dot)org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-/* Helper program to run a command, print its return code and wait on the user */
-
-#include <glib.h>
-#include <stdio.h>
-
-#ifdef G_OS_WIN32
-
-/*
- * Uses GetCommandLineW() and CreateProcessW(). It would be a lot shorter to use
- * _wspawnvp(), but like other argv-based Windows APIs (exec* family) it is broken
- * when it comes to "control" characters in the arguments like spaces and quotes:
- * it seems to basically do `CreateProcessW(" ".join(argv))`, which means it
- * re-interprets it as a command line a second time.
- *
- * Interesting read: https://blogs.msdn.microsoft.com/twistylittlepassagesallalike/2011/04/23/everyone-quotes-command-line-arguments-the-wrong-way/
- *
- * FIXME: maybe just use spawn.c itself? That would make the actual logic more
- * convoluted (trip around from commandline (UTF16) -> argv (UTF8) -> commandline (UTF16))
- * but would have all the spawn logic in one place.
- *
- * FIXME: handle cmd.exe's quoting rules? Does that even apply on cmd.exe's
- * command line itself, or only inside the script? (it probably applies to the
- * argument of /C I guess). That would mean to have a special mode for this,
- * just know we're calling it, or inspect the first argument of what we are
- * supposed to launch and figure out whether it's cmd.exe or not. Darn it.
- */
-
-#include <windows.h>
-
-static void w32_perror(const gchar *prefix)
-{
- gchar *msg = g_win32_error_message(GetLastError());
- fprintf(stderr, "%s: %s\n", prefix, msg);
- g_free(msg);
-}
-
-/* Based on spawn_get_program_name().
- * FIXME: this seems unable to handle an argument containing an escaped quote,
- * but OTOH we expect the cmdline to be valid and Windows doesn't allow quotes
- * in filenames */
-static LPWSTR w32_strip_first_arg(LPWSTR command_line)
-{
- while (*command_line && wcschr(L" \t\r\n", *command_line))
- command_line++;
-
- if (*command_line == L'"')
- {
- command_line++;
- LPWSTR p = wcschr(command_line, L'"');
- if (p)
- command_line = p + 1;
- else
- command_line = wcschr(command_line, L'\0');
- }
- else
- {
- while (*command_line && ! wcschr(L" \t", *command_line))
- command_line++;
- }
-
- while (*command_line && wcschr(L" \t\r\n", *command_line))
- command_line++;
-
- return command_line;
-}
-
-int main(void)
-{
- int exit_status = 1;
- STARTUPINFOW startup;
- PROCESS_INFORMATION process;
- LPWSTR command_line = GetCommandLineW();
- LPWSTR auto_close_arg;
-
- ZeroMemory(&startup, sizeof startup);
- startup.cb = sizeof startup;
-
- auto_close_arg = command_line = w32_strip_first_arg(command_line); // strip argv[0]
- command_line = w32_strip_first_arg(command_line); // strip argv[1]
- if (! command_line || ! *command_line)
- fprintf(stderr, "Invalid or missing command\n");
- else if ((auto_close_arg[0] != L'0' && auto_close_arg[0] != L'1') ||
- ! isspace(auto_close_arg[1]))
- fprintf(stderr, "USAGE: geany-run-script 0|1 command...\n");
- else if (! CreateProcessW(NULL, command_line, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &process))
- w32_perror("CreateProcessW()");
- else
- {
- DWORD code;
-
- CloseHandle(process.hThread);
- if (WaitForSingleObject(process.hProcess, INFINITE) == WAIT_FAILED)
- w32_perror("WaitForSingleObject()");
- else if (! GetExitCodeProcess(process.hProcess, &code))
- w32_perror("GetExitCodeProcess()");
- else
- {
- printf("\n\n------------------\n");
- printf("(program exited with status %d)\n", code);
- exit_status = code;
- }
- CloseHandle(process.hProcess);
- }
-
- if (*auto_close_arg != L'1')
- {
- printf("Press return to continue\n");
- getc(stdin);
- }
-
- return exit_status;
-}
-
-#else
-
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <errno.h>
-
-int main(int argc, char **argv)
-{
- int exit_status = 1;
- const char *auto_close_arg;
-
- if (argc < 3 || ((argv[1][0] != '0' && argv[1][0] != '1') || argv[1][1] != 0))
- {
- fprintf(stderr, "USAGE: %s 1|0 command...\n", argv[0]);
- return 1;
- }
-
- auto_close_arg = argv[1];
- /* strip argv[0] and auto-close argument */
- argv += 2;
- argc -= 2;
-
- pid_t pid = fork();
- if (pid < 0)
- perror("fork()");
- else if (pid == 0)
- {
- /* in the child */
- execvp(*argv, argv);
- perror("execvp()");
- return 127;
- }
- else
- {
- int status;
- int ret;
-
- do
- {
- ret = waitpid(pid, &status, 0);
- }
- while (ret == -1 && errno == EINTR);
-
- printf("\n\n------------------\n");
- if (ret == -1)
- perror("waitpid()");
- else if (WIFEXITED(status))
- {
- printf("(program exited with status %d)\n", WEXITSTATUS(status));
- exit_status = WEXITSTATUS(status);
- }
- else if (WIFSIGNALED(status))
- {
- printf("(program exited with signal %d)\n", WTERMSIG(status));
-#ifdef WCOREDUMP
- if (WCOREDUMP(status))
- printf("(core dumped)\n");
-#endif
- }
- else
- fprintf(stderr, "something funky happened to the child\n");
- }
-
- if (*auto_close_arg != '1')
- {
- printf("Press return to continue\n");
- getc(stdin);
- }
-
- return exit_status;
-}
-
-#endif
Modified: src/win32.c
45 lines changed, 10 insertions(+), 35 deletions(-)
===================================================================
@@ -891,14 +891,19 @@ void win32_init_debug_code(void)
}
+/* expands environment placeholders in @str. input and output is in UTF-8 */
gchar *win32_expand_environment_variables(const gchar *str)
{
- gchar expCmdline[32768]; /* 32768 is the limit for ExpandEnvironmentStrings() */
+ wchar_t *cmdline = g_utf8_to_utf16(str, -1, NULL, NULL, NULL);
+ wchar_t expCmdline[32768]; /* 32768 is the limit for ExpandEnvironmentStrings() */
+ gchar *expanded = NULL;
- if (ExpandEnvironmentStrings((LPCTSTR) str, (LPTSTR) expCmdline, sizeof(expCmdline)) != 0)
- return g_strdup(expCmdline);
- else
- return g_strdup(str);
+ if (cmdline && ExpandEnvironmentStringsW(cmdline, expCmdline, sizeof(expCmdline)) != 0)
+ expanded = g_utf16_to_utf8(expCmdline, -1, NULL, NULL, NULL);
+
+ g_free(cmdline);
+
+ return expanded ? expanded : g_strdup(str);
}
@@ -1032,34 +1037,4 @@ gchar *win32_get_user_config_dir(void)
return g_build_filename(g_get_user_config_dir(), "geany", NULL);
}
-
-/* Retrieve the console codepage
- * In case GetConsoleCP() returns 0 (i.e. the application doesn't have an own console window
- * fallback to GetOEMCP(). */
-guint win32_get_console_codepage(void)
-{
- guint codepage = GetConsoleCP();
- if (codepage == 0)
- codepage = GetOEMCP();
- return codepage;
-}
-
-
-/* Convert a string into the system's default codepage, this is different from the
- * locale (e.g. default codepage is 850 but locale is CP1252).
- * This assumes the input string is encoded as UTF-8, otherwise a copy of
- * the input string is returned. */
-gchar *win32_convert_to_system_codepage(const gchar *str, GError **error)
-{
- if (g_utf8_validate(str, -1, NULL))
- {
- guint codepage_code = win32_get_console_codepage();
- gchar codepage[8] = { 0 };
- g_snprintf(codepage, G_N_ELEMENTS(codepage), "%u", codepage_code);
- return g_convert(str, -1, codepage, "utf-8", NULL, NULL, error);
- }
- else
- return g_strdup(str);
-}
-
#endif
Modified: src/win32.h
4 lines changed, 0 insertions(+), 4 deletions(-)
===================================================================
@@ -68,10 +68,6 @@ gchar *win32_expand_environment_variables(const gchar *str);
gchar *win32_get_user_config_dir(void);
-guint win32_get_console_codepage(void);
-
-gchar *win32_convert_to_system_codepage(const gchar *str, GError **error);
-
G_END_DECLS
#endif /* G_OS_WIN32 */
--------------
This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).
More information about the Commits
mailing list