From: Krzysztof KosiƄski Date: Sun, 28 Mar 2010 20:17:31 +0000 (+0200) Subject: Allow Inkscape to run from Unicode directories on Windows X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=fc619a4a231d691cde619438a5ad8c73126ba98e;p=inkscape.git Allow Inkscape to run from Unicode directories on Windows --- diff --git a/src/extension/implementation/script.cpp b/src/extension/implementation/script.cpp index 60623191f..256996663 100644 --- a/src/extension/implementation/script.cpp +++ b/src/extension/implementation/script.cpp @@ -21,6 +21,8 @@ #include #include +#include +#include #include #include "ui/view/view.h" @@ -101,14 +103,12 @@ Script::interpreter_t const Script::interpreterTab[] = { \param interpNameArg The name of the interpreter that we're looking for, should be an entry in interpreterTab */ -Glib::ustring Script::resolveInterpreterExecutable(const Glib::ustring &interpNameArg) +std::string Script::resolveInterpreterExecutable(const Glib::ustring &interpNameArg) { - Glib::ustring interpName = interpNameArg; - interpreter_t const *interp = 0; bool foundInterp = false; for (interp = interpreterTab ; interp->identity ; interp++ ){ - if (interpName == interp->identity) { + if (interpNameArg == interp->identity) { foundInterp = true; break; } @@ -118,55 +118,26 @@ Glib::ustring Script::resolveInterpreterExecutable(const Glib::ustring &interpNa if (!foundInterp) { return ""; } - interpName = interp->defaultval; + std::string interpreter_path = Glib::filename_from_utf8(interp->defaultval); - // 1. Check preferences + // 1. Check preferences for an override. + // Note: this must be an absolute path. Inkscape::Preferences *prefs = Inkscape::Preferences::get(); Glib::ustring prefInterp = prefs->getString("/extensions/" + Glib::ustring(interp->prefstring)); if (!prefInterp.empty()) { - interpName = prefInterp; - return interpName; - } - -#ifdef WIN32 - - // 2. Windows. Try looking relative to inkscape.exe - RegistryTool rt; - Glib::ustring fullPath; - Glib::ustring path; - Glib::ustring exeName; - if (rt.getExeInfo(fullPath, path, exeName)) { -// TODO replace with proper glib/glibmm path building routines: - Glib::ustring interpPath = path; - interpPath.append("\\"); - interpPath.append(interpNameArg); - interpPath.append("\\"); - interpPath.append(interpName); - interpPath.append(".exe"); - struct stat finfo; - if (stat(interpPath .c_str(), &finfo) == 0) { - g_message("Found local interpreter, '%s', Size: %d", - interpPath .c_str(), - (int)finfo.st_size); - return interpPath; - } + interpreter_path = Glib::filename_from_utf8(prefInterp); } - // 3. Try searching the path - char szExePath[MAX_PATH] = {0}; - char szCurrentDir[MAX_PATH] = {0}; - GetCurrentDirectory(sizeof(szCurrentDir), szCurrentDir); - HINSTANCE ret = FindExecutable(interpName.c_str(), szCurrentDir, szExePath); - if (ret > reinterpret_cast(32)) { - interpName = szExePath; - return interpName; + // 2. Search the path. + // Do this on all systems, for consistency. + // PATH is set up to contain the Python and Perl binary directories + // on Windows, so no extra code is necessary. + if (!Glib::path_is_absolute(interpreter_path)) { + interpreter_path = Glib::find_program_in_path(interpreter_path); } - -#endif // win32 - - - return interpName; + printf("Interpreter name: %s\n", interpreter_path.data()); + return interpreter_path; } /** \brief This function creates a script object and sets up the @@ -206,38 +177,33 @@ Script::~Script() string. This means that the caller of this function can always free what they are given (and should do it too!). */ -Glib::ustring +std::string Script::solve_reldir(Inkscape::XML::Node *reprin) { gchar const *s = reprin->attribute("reldir"); - if (!s) { + // right now the only recognized relative directory is "extensions" + if (!s || Glib::ustring(s) != "extensions") { Glib::ustring str = sp_repr_children(reprin)->content(); return str; } Glib::ustring reldir = s; - if (reldir == "extensions") { - - for (unsigned int i=0; - i < Inkscape::Extension::Extension::search_path.size(); - i++) { + for (unsigned int i=0; + i < Inkscape::Extension::Extension::search_path.size(); + i++) { - gchar * fname = g_build_filename( - Inkscape::Extension::Extension::search_path[i], - sp_repr_children(reprin)->content(), - NULL); - Glib::ustring filename = fname; - g_free(fname); + gchar * fname = g_build_filename( + Inkscape::Extension::Extension::search_path[i], + sp_repr_children(reprin)->content(), + NULL); + Glib::ustring filename = fname; + g_free(fname); - if ( Inkscape::IO::file_test(filename.c_str(), G_FILE_TEST_EXISTS) ) { - return filename; - } + if ( Inkscape::IO::file_test(filename.c_str(), G_FILE_TEST_EXISTS) ) { + return Glib::filename_from_utf8(filename); } - } else { - Glib::ustring str = sp_repr_children(reprin)->content(); - return str; } return ""; @@ -261,29 +227,25 @@ Script::solve_reldir(Inkscape::XML::Node *reprin) { then a TRUE is returned. If we get all the way through the path then a FALSE is returned, the command could not be found. */ -bool Script::check_existance(const Glib::ustring &command) +bool Script::check_existence(const std::string &command) { // Check the simple case first - if (command.size() == 0) { + if (command.empty()) { return false; } - //Don't search when it contains a slash. */ - if (command.find(G_DIR_SEPARATOR) != command.npos) { - if (Inkscape::IO::file_test(command.c_str(), G_FILE_TEST_EXISTS)) { + //Don't search when it is an absolute path. */ + if (!Glib::path_is_absolute(command)) { + if (Glib::file_test(command, Glib::FILE_TEST_EXISTS)) { return true; } else { return false; } } - - Glib::ustring path; - gchar *s = (gchar *) g_getenv("PATH"); - if (s) { - path = s; - } else { + std::string path = Glib::getenv("PATH"); + if (path.empty()) { /* There is no `PATH' in the environment. The default search path is the current directory */ path = G_SEARCHPATH_SEPARATOR_S; @@ -293,7 +255,7 @@ bool Script::check_existance(const Glib::ustring &command) std::string::size_type pos2 = 0; while ( pos < path.size() ) { - Glib::ustring localPath; + std::string localPath; pos2 = path.find(G_SEARCHPATH_SEPARATOR, pos); if (pos2 == path.npos) { @@ -305,11 +267,11 @@ bool Script::check_existance(const Glib::ustring &command) } //printf("### %s\n", localPath.c_str()); - Glib::ustring candidatePath = + std::string candidatePath = Glib::build_filename(localPath, command); - if (Inkscape::IO::file_test(candidatePath .c_str(), - G_FILE_TEST_EXISTS)) { + if (Glib::file_test(candidatePath, + Glib::FILE_TEST_EXISTS)) { return true; } @@ -357,16 +319,10 @@ bool Script::load(Inkscape::Extension::Extension *module) if (!strcmp(child_repr->name(), INKSCAPE_EXTENSION_NS "command")) { const gchar *interpretstr = child_repr->attribute("interpreter"); if (interpretstr != NULL) { - Glib::ustring interpString = - resolveInterpreterExecutable(interpretstr); - //g_message("Found: %s and %s",interpString.c_str(),interpretstr); - command.insert(command.end(), interpretstr); + std::string interpString = resolveInterpreterExecutable(interpretstr); + command.insert(command.end(), interpString); } - Glib::ustring tmp = "\""; - tmp += solve_reldir(child_repr); - tmp += "\""; - - command.insert(command.end(), tmp); + command.insert(command.end(), solve_reldir(child_repr)); } if (!strcmp(child_repr->name(), INKSCAPE_EXTENSION_NS "helper_extension")) { helper_extension = sp_repr_children(child_repr)->content(); @@ -419,10 +375,10 @@ Script::check(Inkscape::Extension::Extension *module) child_repr = sp_repr_children(child_repr); while (child_repr != NULL) { if (!strcmp(child_repr->name(), INKSCAPE_EXTENSION_NS "check")) { - Glib::ustring command_text = solve_reldir(child_repr); - if (command_text.size() > 0) { + std::string command_text = solve_reldir(child_repr); + if (!command_text.empty()) { /* I've got the command */ - bool existance = check_existance(command_text); + bool existance = check_existence(command_text); if (!existance) return false; } @@ -763,8 +719,7 @@ void Script::effect(Inkscape::Extension::Effect *module, // make sure we don't leak file descriptors from g_file_open_tmp close(tempfd_out); - // FIXME: convert to utf8 (from "filename encoding") and unlink_utf8name - unlink(tempfilename_out.c_str()); + g_unlink(tempfilename_out.c_str()); /* Do something with mydoc.... */ if (mydoc) { @@ -937,89 +892,61 @@ int Script::execute (const std::list &in_command, const Glib::ustring &filein, file_listener &fileout) { - g_return_val_if_fail(in_command.size() > 0, 0); + g_return_val_if_fail(!in_command.empty(), 0); // printf("Executing\n"); - std::vector argv; - -/* - for (std::list::const_iterator i = in_command.begin(); - i != in_command.end(); i++) { - argv.push_back(*i); - } -*/ - // according to http://www.gtk.org/api/2.6/glib/glib-Spawning-Processes.html spawn quotes parameter containing spaces - // we tokenize so that spwan does not need to quote over all params - for (std::list::const_iterator i = in_command.begin(); - i != in_command.end(); i++) { - std::string param_str = *i; - do { - //g_message("param: %s", param_str.c_str()); - size_t first_space = param_str.find_first_of(' '); - size_t first_quote = param_str.find_first_of('"'); - //std::cout << "first space " << first_space << std::endl; - //std::cout << "first quote " << first_quote << std::endl; - - if ((first_quote != std::string::npos) && (first_quote == 0)) { - size_t next_quote = param_str.find_first_of('"', first_quote + 1); - //std::cout << "next quote " << next_quote << std::endl; - - if (next_quote != std::string::npos) { - //std::cout << "now split " << next_quote << std::endl; - //std::cout << "now split " << param_str.substr(1, next_quote - 1) << std::endl; - //std::cout << "now split " << param_str.substr(next_quote + 1) << std::endl; - std::string part_str = param_str.substr(1, next_quote - 1); - if (part_str.size() > 0) - argv.push_back(part_str); - param_str = param_str.substr(next_quote + 1); - - } else { - if (param_str.size() > 0) - argv.push_back(param_str); - param_str = ""; - } - - } else if (first_space != std::string::npos) { - //std::cout << "now split " << first_space << std::endl; - //std::cout << "now split " << param_str.substr(0, first_space) << std::endl; - //std::cout << "now split " << param_str.substr(first_space + 1) << std::endl; - std::string part_str = param_str.substr(0, first_space); - if (part_str.size() > 0) { - argv.push_back(part_str); - } - param_str = param_str.substr(first_space + 1); - } else { - if (param_str.size() > 0) { - argv.push_back(param_str); - } - param_str = ""; - } - } while (param_str.size() > 0); - } - - for (std::list::const_iterator i = in_params.begin(); - i != in_params.end(); i++) { - //g_message("Script parameter: %s",(*i)g.c_str()); - argv.push_back(*i); - } - - if (!(filein.empty())) { + std::vector argv; + + bool interpreted = (in_command.size() == 2); + std::string program = in_command.front(); + std::string script = interpreted ? in_command.back() : ""; + std::string working_directory = ""; + + // Use Glib::find_program_in_path instead of the equivalent + // Glib::spawn_* functionality, because _wspawnp is broken on Windows: + // it doesn't work when PATH contains Unicode directories + if (!Glib::path_is_absolute(program)) { + program = Glib::find_program_in_path(program); + } + argv.push_back(program); + + if (interpreted) { + // On Windows, Python garbles Unicode command line parameters + // in an useless way. This means extensions fail when Inkscape + // is run from an Unicode directory. + // As a workaround, we set the working directory to the one + // containing the script. + working_directory = Glib::path_get_dirname(script); + script = Glib::path_get_basename(script); + #ifdef G_OS_WIN32 + // ANNOYING: glibmm does not wrap g_win32_locale_filename_from_utf8 + gchar *workdir_s = g_win32_locale_filename_from_utf8(working_directory.data()); + working_directory = workdir_s; + g_free(workdir_s); + #endif + + argv.push_back(script); + } + + // assemble the rest of argv + std::copy(in_params.begin(), in_params.end(), std::back_inserter(argv)); + if (!filein.empty()) { argv.push_back(filein); } int stdout_pipe, stderr_pipe; try { - Inkscape::IO::spawn_async_with_pipes(Glib::get_current_dir(), // working directory + Glib::spawn_async_with_pipes(working_directory, // working directory argv, // arg v - Glib::SPAWN_SEARCH_PATH /*| Glib::SPAWN_DO_NOT_REAP_CHILD*/, + static_cast(0), // no flags sigc::slot(), &_pid, // Pid NULL, // STDIN &stdout_pipe, // STDOUT &stderr_pipe); // STDERR - } catch (Glib::SpawnError e) { - printf("Can't Spawn!!! spawn returns: %d\n", e.code()); + } catch (Glib::Error e) { + printf("Can't Spawn!!! spawn returns: %s\n", e.what().data()); return 0; } diff --git a/src/extension/implementation/script.h b/src/extension/implementation/script.h index e0b6701bf..f37f27966 100644 --- a/src/extension/implementation/script.h +++ b/src/extension/implementation/script.h @@ -115,31 +115,14 @@ private: */ Glib::ustring helper_extension; - /** - * Just a quick function to find and resolve relative paths for - * the incoming scripts - */ - Glib::ustring solve_reldir (Inkscape::XML::Node *reprin); - - /** - * - */ - bool check_existance (const Glib::ustring &command); - - /** - * - */ + std::string solve_reldir (Inkscape::XML::Node *reprin); + bool check_existence (const std::string &command); void copy_doc (Inkscape::XML::Node * olddoc, Inkscape::XML::Node * newdoc); - - /** - * - */ void checkStderr (const Glib::ustring &filename, Gtk::MessageType type, const Glib::ustring &message); - class file_listener { Glib::ustring _string; sigc::connection _conn; @@ -184,7 +167,6 @@ private: return true; }; - // Note, doing a copy here, on purpose Glib::ustring string (void) { return _string; }; bool toFile (const Glib::ustring &name) { @@ -215,7 +197,7 @@ private: }; static interpreter_t const interpreterTab[]; - Glib::ustring resolveInterpreterExecutable(const Glib::ustring &interpNameArg); + std::string resolveInterpreterExecutable(const Glib::ustring &interpNameArg); }; // class Script diff --git a/src/io/sys.cpp b/src/io/sys.cpp index 34160b648..a68d02707 100644 --- a/src/io/sys.cpp +++ b/src/io/sys.cpp @@ -29,41 +29,9 @@ #include "sys.h" #ifdef WIN32 - -#define BYPASS_GLIB_SPAWN 1 - -#ifdef BYPASS_GLIB_SPAWN - -#include // declares spawn functions -#include // declares _wspawn functions - -#ifndef __MINGW32__ -# ifdef __cplusplus -extern "C" { -# endif -_CRTIMP int __cdecl __MINGW_NOTHROW _wspawnl (int, const wchar_t*, const wchar_t*, ...); -_CRTIMP int __cdecl __MINGW_NOTHROW _wspawnle (int, const wchar_t*, const wchar_t*, ...); -_CRTIMP int __cdecl __MINGW_NOTHROW _wspawnlp (int, const wchar_t*, const wchar_t*, ...); -_CRTIMP int __cdecl __MINGW_NOTHROW _wspawnlpe (int, const wchar_t*, const wchar_t*, ...); -_CRTIMP int __cdecl __MINGW_NOTHROW _wspawnv (int, const wchar_t*, const wchar_t* const*); -_CRTIMP int __cdecl __MINGW_NOTHROW _wspawnve (int, const wchar_t*, const wchar_t* const*, const wchar_t* const*); -_CRTIMP int __cdecl __MINGW_NOTHROW _wspawnvp (int, const wchar_t*, const wchar_t* const*); -_CRTIMP int __cdecl __MINGW_NOTHROW _wspawnvpe (int, const wchar_t*, const wchar_t* const*, const wchar_t* const*); -# ifdef __cplusplus -} -# endif -#endif -#include -#include -#include -#include - -#endif // BYPASS_GLIB_SPAWN - // For now to get at is_os_wide(). #include "extension/internal/win32.h" using Inkscape::Extension::Internal::PrintWin32; - #endif // WIN32 //#define INK_DUMP_FILENAME_CONV 1 @@ -217,32 +185,7 @@ int Inkscape::IO::mkdir_utf8name( char const *utf8name ) * */ int Inkscape::IO::file_open_tmp(std::string& name_used, const std::string& prefix) { -#ifndef WIN32 return Glib::file_open_tmp(name_used, prefix); -#else - /* Special case for WIN32 due to a bug in glibmm - * (only needed for Windows Vista, but since there is only one windows build all builds get the workaround) - * The workaround can be removed if the bug is fixed in glibmm - * - * The code is mostly identical to the implementation in glibmm - * http://svn.gnome.org/svn/glibmm/branches/glibmm-2-12/glib/src/fileutils.ccg - * */ - - std::string basename_template (prefix); - basename_template += "XXXXXX"; // this sillyness shouldn't be in the interface - - GError* error = 0; - gchar *buf_name_used; - - gint fileno = g_file_open_tmp(basename_template.c_str(), &buf_name_used, &error); - - if(error) - Glib::Error::throw_exception(error); - - name_used = g_strdup(buf_name_used); - g_free(buf_name_used); - return fileno; -#endif } bool Inkscape::IO::file_test( char const *utf8name, GFileTest test ) @@ -372,842 +315,6 @@ gchar* Inkscape::IO::locale_to_utf8_fallback( const gchar *opsysstring, return result; } -#ifdef BYPASS_GLIB_SPAWN -/* - this code was taken from the original glib sources -*/ -#define GSPAWN_HELPER - -enum -{ - CHILD_NO_ERROR, - CHILD_CHDIR_FAILED, - CHILD_SPAWN_FAILED, -}; - -enum { - ARG_CHILD_ERR_REPORT = 1, - ARG_HELPER_SYNC, - ARG_STDIN, - ARG_STDOUT, - ARG_STDERR, - ARG_WORKING_DIRECTORY, - ARG_CLOSE_DESCRIPTORS, - ARG_USE_PATH, - ARG_WAIT, - ARG_PROGRAM, - ARG_COUNT = ARG_PROGRAM -}; -static int debug = 0; -#define HELPER_PROCESS "gspawn-win32-helper" - - -static int -dup_noninherited (int fd, - int mode) -{ - HANDLE filehandle; - - DuplicateHandle (GetCurrentProcess (), (LPHANDLE) _get_osfhandle (fd), - GetCurrentProcess (), &filehandle, - 0, FALSE, DUPLICATE_SAME_ACCESS); - close (fd); - return _open_osfhandle(reinterpret_cast(filehandle), mode | _O_NOINHERIT); -} - -/* The helper process writes a status report back to us, through a - * pipe, consisting of two ints. - */ -static gboolean -read_helper_report (int fd, - gint report[2], - GError **error) -{ - gint bytes = 0; - - while (bytes < sizeof(gint)*2) - { - gint chunk; - - if (debug) - g_print ("%s:read_helper_report: read %d...\n", - __FILE__, - sizeof(gint)*2 - bytes); - - chunk = read (fd, ((gchar*)report) + bytes, - sizeof(gint)*2 - bytes); - - if (debug) - g_print ("...got %d bytes\n", chunk); - - if (chunk < 0) - { - /* Some weird shit happened, bail out */ - - g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, - _("Failed to read from child pipe (%s)"), - g_strerror (errno)); - - return FALSE; - } - else if (chunk == 0) - { - g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, - _("Failed to read from child pipe (%s)"), - "EOF"); - break; /* EOF */ - } - else - bytes += chunk; - } - - if (bytes < sizeof(gint)*2) - return FALSE; - - return TRUE; -} - - -static void -set_child_error (gint report[2], - const gchar *working_directory, - GError **error) -{ - switch (report[0]) - { - case CHILD_CHDIR_FAILED: - g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_CHDIR, - _("Failed to change to directory '%s' (%s)"), - working_directory, - g_strerror (report[1])); - break; - case CHILD_SPAWN_FAILED: - g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, - _("Failed to execute child process (%s)"), - g_strerror (report[1])); - break; - default: - g_assert_not_reached (); - } -} - -static gchar * -protect_argv_string (const gchar *string) -{ - const gchar *p = string; - gchar *retval, *q; - gint len = 0; - gboolean need_dblquotes = FALSE; - while (*p) - { - if (*p == ' ' || *p == '\t') - need_dblquotes = TRUE; - else if (*p == '"') - len++; - else if (*p == '\\') - { - const gchar *pp = p; - while (*pp && *pp == '\\') - pp++; - if (*pp == '"') - len++; - } - len++; - p++; - } - - q = retval = (gchar *)g_malloc (len + need_dblquotes*2 + 1); - p = string; - - if (need_dblquotes) - *q++ = '"'; - - while (*p) - { - if (*p == '"') - *q++ = '\\'; - else if (*p == '\\') - { - const gchar *pp = p; - while (*pp && *pp == '\\') - pp++; - if (*pp == '"') - *q++ = '\\'; - } - *q++ = *p; - p++; - } - - if (need_dblquotes) - *q++ = '"'; - *q++ = '\0'; - - return retval; -} - - -static gint -protect_argv (gchar **argv, - gchar ***new_argv) -{ - gint i; - gint argc = 0; - - while (argv[argc]) - ++argc; - *new_argv = g_new (gchar *, argc+1); - - /* Quote each argv element if necessary, so that it will get - * reconstructed correctly in the C runtime startup code. Note that - * the unquoting algorithm in the C runtime is really weird, and - * rather different than what Unix shells do. See stdargv.c in the C - * runtime sources (in the Platform SDK, in src/crt). - * - * Note that an new_argv[0] constructed by this function should - * *not* be passed as the filename argument to a spawn* or exec* - * family function. That argument should be the real file name - * without any quoting. - */ - for (i = 0; i < argc; i++) - (*new_argv)[i] = protect_argv_string (argv[i]); - - (*new_argv)[argc] = NULL; - - return argc; -} - - -static gboolean -utf8_charv_to_wcharv (char **utf8_charv, - wchar_t ***wcharv, - int *error_index, - GError **error) -{ - wchar_t **retval = NULL; - - *wcharv = NULL; - if (utf8_charv != NULL) - { - int n = 0, i; - - while (utf8_charv[n]) - n++; - retval = g_new (wchar_t *, n + 1); - - for (i = 0; i < n; i++) - { - retval[i] = (wchar_t *)g_utf8_to_utf16 (utf8_charv[i], -1, NULL, NULL, error); - if (retval[i] == NULL) - { - if (error_index) - *error_index = i; - while (i) - g_free (retval[--i]); - g_free (retval); - return FALSE; - } - } - - retval[n] = NULL; - } - *wcharv = retval; - return TRUE; -} - - -/* Avoids a danger in threaded situations (calling close() - * on a file descriptor twice, and another thread has - * re-opened it since the first close) - */ -static void -close_and_invalidate (gint *fd) -{ - if (*fd < 0) - return; - - close (*fd); - *fd = -1; -} - - -static gboolean -do_spawn_directly (gint *exit_status, - gboolean do_return_handle, - GSpawnFlags flags, - gchar **argv, - char **envp, - char **protected_argv, - GSpawnChildSetupFunc child_setup, - gpointer user_data, - GPid *child_handle, - GError **error) -{ - const int mode = (exit_status == NULL) ? P_NOWAIT : P_WAIT; - char **new_argv; - int rc = -1; - int saved_errno; - GError *conv_error = NULL; - gint conv_error_index; - wchar_t *wargv0, **wargv, **wenvp; - - new_argv = (flags & G_SPAWN_FILE_AND_ARGV_ZERO) ? protected_argv + 1 : protected_argv; - - wargv0 = (wchar_t *)g_utf8_to_utf16 (argv[0], -1, NULL, NULL, &conv_error); - if (wargv0 == NULL) - { - g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, - _("Invalid program name: %s"), - conv_error->message); - g_error_free (conv_error); - - return FALSE; - } - - if (!utf8_charv_to_wcharv (new_argv, &wargv, &conv_error_index, &conv_error)) - { - g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, - _("Invalid string in argument vector at %d: %s"), - conv_error_index, conv_error->message); - g_error_free (conv_error); - g_free (wargv0); - - return FALSE; - } - - if (!utf8_charv_to_wcharv (envp, &wenvp, NULL, &conv_error)) - { - g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, - _("Invalid string in environment: %s"), - conv_error->message); - g_error_free (conv_error); - g_free (wargv0); - g_strfreev ((gchar **) wargv); - - return FALSE; - } - - if (child_setup) - (* child_setup) (user_data); - - if (flags & G_SPAWN_SEARCH_PATH) - if (wenvp != NULL) - rc = _wspawnvpe (mode, wargv0, (const wchar_t **) wargv, (const wchar_t **) wenvp); - else - rc = _wspawnvp (mode, wargv0, (const wchar_t **) wargv); - else - if (wenvp != NULL) - rc = _wspawnve (mode, wargv0, (const wchar_t **) wargv, (const wchar_t **) wenvp); - else - rc = _wspawnv (mode, wargv0, (const wchar_t **) wargv); - - g_free (wargv0); - g_strfreev ((gchar **) wargv); - g_strfreev ((gchar **) wenvp); - - saved_errno = errno; - - if (rc == -1 && saved_errno != 0) - { - g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, - _("Failed to execute child process (%s)"), - g_strerror (saved_errno)); - return FALSE; - } - - if (exit_status == NULL) - { - if (child_handle && do_return_handle) - *child_handle = (GPid) rc; - else - { - CloseHandle ((HANDLE) rc); - if (child_handle) - *child_handle = 0; - } - } - else - *exit_status = rc; - - return TRUE; -} - -static gboolean -make_pipe (gint p[2], - GError **error) -{ - if (_pipe (p, 4096, _O_BINARY) < 0) - { - g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, - _("Failed to create pipe for communicating with child process (%s)"), - g_strerror (errno)); - return FALSE; - } - else - return TRUE; -} - - -static gboolean -do_spawn_with_pipes (gint *exit_status, - gboolean do_return_handle, - const gchar *working_directory, - gchar **argv, - char **envp, - GSpawnFlags flags, - GSpawnChildSetupFunc child_setup, - gpointer user_data, - GPid *child_handle, - gint *standard_input, - gint *standard_output, - gint *standard_error, - gint *err_report, - GError **error) -{ - char **protected_argv; - char args[ARG_COUNT][10]; - char **new_argv; - int i; - int rc = -1; - int saved_errno; - int argc; - int stdin_pipe[2] = { -1, -1 }; - int stdout_pipe[2] = { -1, -1 }; - int stderr_pipe[2] = { -1, -1 }; - int child_err_report_pipe[2] = { -1, -1 }; - int helper_sync_pipe[2] = { -1, -1 }; - int helper_report[2]; - static gboolean warned_about_child_setup = FALSE; - GError *conv_error = NULL; - gint conv_error_index; - gchar *helper_process; - CONSOLE_CURSOR_INFO cursor_info; - wchar_t *whelper, **wargv, **wenvp; - //extern gchar *_glib_get_installation_directory (void); - gchar *glib_top; - - if (child_setup && !warned_about_child_setup) - { - warned_about_child_setup = TRUE; - g_warning ("passing a child setup function to the g_spawn functions is pointless and dangerous on Win32"); - } - - argc = protect_argv (argv, &protected_argv); - - if (!standard_input && !standard_output && !standard_error && - (flags & G_SPAWN_CHILD_INHERITS_STDIN) && - !(flags & G_SPAWN_STDOUT_TO_DEV_NULL) && - !(flags & G_SPAWN_STDERR_TO_DEV_NULL) && - (working_directory == NULL || !*working_directory) && - (flags & G_SPAWN_LEAVE_DESCRIPTORS_OPEN)) - { - /* We can do without the helper process */ - gboolean retval = - do_spawn_directly (exit_status, do_return_handle, flags, - argv, envp, protected_argv, - child_setup, user_data, child_handle, - error); - g_strfreev (protected_argv); - return retval; - } - - if (standard_input && !make_pipe (stdin_pipe, error)) - goto cleanup_and_fail; - - if (standard_output && !make_pipe (stdout_pipe, error)) - goto cleanup_and_fail; - - if (standard_error && !make_pipe (stderr_pipe, error)) - goto cleanup_and_fail; - - if (!make_pipe (child_err_report_pipe, error)) - goto cleanup_and_fail; - - if (!make_pipe (helper_sync_pipe, error)) - goto cleanup_and_fail; - - new_argv = g_new (char *, argc + 1 + ARG_COUNT); - if (GetConsoleCursorInfo (GetStdHandle (STD_OUTPUT_HANDLE), &cursor_info)) - helper_process = HELPER_PROCESS "-console.exe"; - else - helper_process = HELPER_PROCESS ".exe"; - - glib_top = NULL; - if (glib_top != NULL) - { - helper_process = g_build_filename (glib_top, "bin", helper_process, NULL); - g_free (glib_top); - } - else - helper_process = g_strdup (helper_process); - - new_argv[0] = protect_argv_string (helper_process); - - sprintf (args[ARG_CHILD_ERR_REPORT], "%d", child_err_report_pipe[1]); - new_argv[ARG_CHILD_ERR_REPORT] = args[ARG_CHILD_ERR_REPORT]; - - /* Make the read end of the child error report pipe - * noninherited. Otherwise it will needlessly be inherited by the - * helper process, and the started actual user process. As such that - * shouldn't harm, but it is unnecessary. - */ - child_err_report_pipe[0] = dup_noninherited (child_err_report_pipe[0], _O_RDONLY); - - if (flags & G_SPAWN_FILE_AND_ARGV_ZERO) - { - /* Overload ARG_CHILD_ERR_REPORT to also encode the - * G_SPAWN_FILE_AND_ARGV_ZERO functionality. - */ - strcat (args[ARG_CHILD_ERR_REPORT], "#"); - } - - sprintf (args[ARG_HELPER_SYNC], "%d", helper_sync_pipe[0]); - new_argv[ARG_HELPER_SYNC] = args[ARG_HELPER_SYNC]; - - /* Make the write end of the sync pipe noninherited. Otherwise the - * helper process will inherit it, and thus if this process happens - * to crash before writing the sync byte to the pipe, the helper - * process won't read but won't get any EOF either, as it has the - * write end open itself. - */ - helper_sync_pipe[1] = dup_noninherited (helper_sync_pipe[1], _O_WRONLY); - - if (standard_input) - { - sprintf (args[ARG_STDIN], "%d", stdin_pipe[0]); - new_argv[ARG_STDIN] = args[ARG_STDIN]; - } - else if (flags & G_SPAWN_CHILD_INHERITS_STDIN) - { - /* Let stdin be alone */ - new_argv[ARG_STDIN] = "-"; - } - else - { - /* Keep process from blocking on a read of stdin */ - new_argv[ARG_STDIN] = "z"; - } - - if (standard_output) - { - sprintf (args[ARG_STDOUT], "%d", stdout_pipe[1]); - new_argv[ARG_STDOUT] = args[ARG_STDOUT]; - } - else if (flags & G_SPAWN_STDOUT_TO_DEV_NULL) - { - new_argv[ARG_STDOUT] = "z"; - } - else - { - new_argv[ARG_STDOUT] = "-"; - } - - if (standard_error) - { - sprintf (args[ARG_STDERR], "%d", stderr_pipe[1]); - new_argv[ARG_STDERR] = args[ARG_STDERR]; - } - else if (flags & G_SPAWN_STDERR_TO_DEV_NULL) - { - new_argv[ARG_STDERR] = "z"; - } - else - { - new_argv[ARG_STDERR] = "-"; - } - - if (working_directory && *working_directory) - new_argv[ARG_WORKING_DIRECTORY] = protect_argv_string (working_directory); - else - new_argv[ARG_WORKING_DIRECTORY] = g_strdup ("-"); - - if (!(flags & G_SPAWN_LEAVE_DESCRIPTORS_OPEN)) - new_argv[ARG_CLOSE_DESCRIPTORS] = "y"; - else - new_argv[ARG_CLOSE_DESCRIPTORS] = "-"; - - if (flags & G_SPAWN_SEARCH_PATH) - new_argv[ARG_USE_PATH] = "y"; - else - new_argv[ARG_USE_PATH] = "-"; - - if (exit_status == NULL) - new_argv[ARG_WAIT] = "-"; - else - new_argv[ARG_WAIT] = "w"; - - for (i = 0; i <= argc; i++) - new_argv[ARG_PROGRAM + i] = protected_argv[i]; - - //SETUP_DEBUG(); - - if (debug) - { - g_print ("calling %s with argv:\n", helper_process); - for (i = 0; i < argc + 1 + ARG_COUNT; i++) - g_print ("argv[%d]: %s\n", i, (new_argv[i] ? new_argv[i] : "NULL")); - } - - if (!utf8_charv_to_wcharv (new_argv, &wargv, &conv_error_index, &conv_error)) - { - if (conv_error_index == ARG_WORKING_DIRECTORY) - g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_CHDIR, - _("Invalid working directory: %s"), - conv_error->message); - else - g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, - _("Invalid string in argument vector at %d: %s"), - conv_error_index - ARG_PROGRAM, conv_error->message); - g_error_free (conv_error); - g_strfreev (protected_argv); - g_free (new_argv[0]); - g_free (new_argv[ARG_WORKING_DIRECTORY]); - g_free (new_argv); - g_free (helper_process); - - goto cleanup_and_fail; - } - - if (!utf8_charv_to_wcharv (envp, &wenvp, NULL, &conv_error)) - { - g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, - _("Invalid string in environment: %s"), - conv_error->message); - g_error_free (conv_error); - g_strfreev (protected_argv); - g_free (new_argv[0]); - g_free (new_argv[ARG_WORKING_DIRECTORY]); - g_free (new_argv); - g_free (helper_process); - g_strfreev ((gchar **) wargv); - - goto cleanup_and_fail; - } - - if (child_setup) - (* child_setup) (user_data); - - whelper = (wchar_t *)g_utf8_to_utf16 (helper_process, -1, NULL, NULL, NULL); - g_free (helper_process); - - if (wenvp != NULL) - rc = _wspawnvpe (P_NOWAIT, whelper, (const wchar_t **) wargv, (const wchar_t **) wenvp); - else - rc = _wspawnvp (P_NOWAIT, whelper, (const wchar_t **) wargv); - - saved_errno = errno; - - g_free (whelper); - g_strfreev ((gchar **) wargv); - g_strfreev ((gchar **) wenvp); - - /* Close the other process's ends of the pipes in this process, - * otherwise the reader will never get EOF. - */ - close_and_invalidate (&child_err_report_pipe[1]); - close_and_invalidate (&helper_sync_pipe[0]); - close_and_invalidate (&stdin_pipe[0]); - close_and_invalidate (&stdout_pipe[1]); - close_and_invalidate (&stderr_pipe[1]); - - g_strfreev (protected_argv); - - g_free (new_argv[0]); - g_free (new_argv[ARG_WORKING_DIRECTORY]); - g_free (new_argv); - - /* Check if gspawn-win32-helper couldn't be run */ - if (rc == -1 && saved_errno != 0) - { - g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, - _("Failed to execute helper program (%s)"), - g_strerror (saved_errno)); - goto cleanup_and_fail; - } - - if (exit_status != NULL) - { - /* Synchronous case. Pass helper's report pipe back to caller, - * which takes care of reading it after the grandchild has - * finished. - */ - g_assert (err_report != NULL); - *err_report = child_err_report_pipe[0]; - write (helper_sync_pipe[1], " ", 1); - close_and_invalidate (&helper_sync_pipe[1]); - } - else - { - /* Asynchronous case. We read the helper's report right away. */ - if (!read_helper_report (child_err_report_pipe[0], helper_report, error)) - goto cleanup_and_fail; - - close_and_invalidate (&child_err_report_pipe[0]); - - switch (helper_report[0]) - { - case CHILD_NO_ERROR: - if (child_handle && do_return_handle) - { - /* rc is our HANDLE for gspawn-win32-helper. It has - * told us the HANDLE of its child. Duplicate that into - * a HANDLE valid in this process. - */ - if (!DuplicateHandle ((HANDLE) rc, (HANDLE) helper_report[1], - GetCurrentProcess (), (LPHANDLE) child_handle, - 0, TRUE, DUPLICATE_SAME_ACCESS)) - { - char *emsg = g_win32_error_message (GetLastError ()); - g_print("%s\n", emsg); - *child_handle = 0; - } - } - else if (child_handle) - *child_handle = 0; - write (helper_sync_pipe[1], " ", 1); - close_and_invalidate (&helper_sync_pipe[1]); - break; - - default: - write (helper_sync_pipe[1], " ", 1); - close_and_invalidate (&helper_sync_pipe[1]); - set_child_error (helper_report, working_directory, error); - goto cleanup_and_fail; - } - } - - /* Success against all odds! return the information */ - - if (standard_input) - *standard_input = stdin_pipe[1]; - if (standard_output) - *standard_output = stdout_pipe[0]; - if (standard_error) - *standard_error = stderr_pipe[0]; - if (rc != -1) - CloseHandle ((HANDLE) rc); - - return TRUE; - - cleanup_and_fail: - - if (rc != -1) - CloseHandle ((HANDLE) rc); - if (child_err_report_pipe[0] != -1) - close (child_err_report_pipe[0]); - if (child_err_report_pipe[1] != -1) - close (child_err_report_pipe[1]); - if (helper_sync_pipe[0] != -1) - close (helper_sync_pipe[0]); - if (helper_sync_pipe[1] != -1) - close (helper_sync_pipe[1]); - if (stdin_pipe[0] != -1) - close (stdin_pipe[0]); - if (stdin_pipe[1] != -1) - close (stdin_pipe[1]); - if (stdout_pipe[0] != -1) - close (stdout_pipe[0]); - if (stdout_pipe[1] != -1) - close (stdout_pipe[1]); - if (stderr_pipe[0] != -1) - close (stderr_pipe[0]); - if (stderr_pipe[1] != -1) - close (stderr_pipe[1]); - - return FALSE; -} - -gboolean -my_spawn_async_with_pipes_utf8 (const gchar *working_directory, - gchar **argv, - gchar **envp, - GSpawnFlags flags, - GSpawnChildSetupFunc child_setup, - gpointer user_data, - GPid *child_handle, - gint *standard_input, - gint *standard_output, - gint *standard_error, - GError **error) -{ - g_return_val_if_fail (argv != NULL, FALSE); - g_return_val_if_fail (standard_output == NULL || - !(flags & G_SPAWN_STDOUT_TO_DEV_NULL), FALSE); - g_return_val_if_fail (standard_error == NULL || - !(flags & G_SPAWN_STDERR_TO_DEV_NULL), FALSE); - /* can't inherit stdin if we have an input pipe. */ - g_return_val_if_fail (standard_input == NULL || - !(flags & G_SPAWN_CHILD_INHERITS_STDIN), FALSE); - - return do_spawn_with_pipes (NULL, - (flags & G_SPAWN_DO_NOT_REAP_CHILD), - working_directory, - argv, - envp, - flags, - child_setup, - user_data, - child_handle, - standard_input, - standard_output, - standard_error, - NULL, - error); -} - -typedef GPid Pid; - -// _WRAP_ENUM(SpawnFlags, GSpawnFlags, NO_GTYPE) - -/* Helper callback to invoke the actual sigc++ slot. - * We don't need to worry about (un)referencing, since the - * child process gets its own copy of the parent's memory anyway. - */ -static void child_setup_callback(void* user_data) -{ - #ifdef GLIBMM_EXCEPTIONS_ENABLED - try - { - #endif //GLIBMM_EXCEPTIONS_ENABLED - (*reinterpret_cast*>(user_data))(); - #ifdef GLIBMM_EXCEPTIONS_ENABLED - } - catch(...) - { - Glib::exception_handlers_invoke(); - } - #endif //GLIBMM_EXCEPTIONS_ENABLED -} - - -void my_spawn_async_with_pipes(const std::string& working_directory, - const Glib::ArrayHandle& argv, - GSpawnFlags flags, - const sigc::slot& child_setup, - Pid* child_pid, - int* standard_input, - int* standard_output, - int* standard_error) -{ - const bool setup_slot = !child_setup.empty(); - sigc::slot child_setup_ = child_setup; - GError* error = 0; - - my_spawn_async_with_pipes_utf8( - working_directory.c_str(), - const_cast(argv.data()), 0, - static_cast(unsigned(flags)), - (setup_slot) ? &child_setup_callback : 0, - (setup_slot) ? &child_setup_ : 0, - child_pid, - standard_input, standard_output, standard_error, - &error); - - if(error) - Glib::Error::throw_exception(error); -} - -#endif - void Inkscape::IO::spawn_async_with_pipes( const std::string& working_directory, const Glib::ArrayHandle& argv, @@ -1218,7 +325,6 @@ Inkscape::IO::spawn_async_with_pipes( const std::string& working_directory, int* standard_output, int* standard_error) { -#ifndef BYPASS_GLIB_SPAWN Glib::spawn_async_with_pipes(working_directory, argv, flags, @@ -1227,16 +333,6 @@ Inkscape::IO::spawn_async_with_pipes( const std::string& working_directory, standard_input, standard_output, standard_error); -#else - my_spawn_async_with_pipes(working_directory, - argv, - static_cast(flags), - child_setup, - child_pid, - standard_input, - standard_output, - standard_error); -#endif } diff --git a/src/main.cpp b/src/main.cpp index d11222203..a4ed5d77b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -47,6 +47,8 @@ #endif /* Not def: POPT_TABLEEND */ #include +#include +#include #include #include #include @@ -471,61 +473,71 @@ gchar * blankParam = g_strdup(""); #ifdef WIN32 -/** - * Return the directory of the .exe that is currently running - */ -static Glib::ustring _win32_getExePath() -{ - char exeName[MAX_PATH+1]; - // TODO these should use xxxW() calls explicitly and convert UTF-16 <--> UTF-8 - GetModuleFileName(NULL, exeName, MAX_PATH); - char *slashPos = strrchr(exeName, '\\'); - if (slashPos) { - *slashPos = '\0'; - } - Glib::ustring s = exeName; - return s; -} - /** * Set up the PATH and PYTHONPATH environment variables on * win32 + * @param exe Inkscape executable directory in UTF-8 */ -static int _win32_set_inkscape_env(const Glib::ustring &exePath) +static void _win32_set_inkscape_env(gchar const *exe) { - // TODO use g_getenv() and g_setenv() that use filename encoding, which is UTF-8 on Windows - - char *oldenv = getenv("PATH"); - Glib::ustring tmp = "PATH="; - tmp += exePath; - tmp += ";"; - tmp += exePath; - tmp += "\\python;"; - tmp += exePath; - tmp += "\\python\\Scripts;"; // for uniconv.cmd - tmp += exePath; - tmp += "\\perl"; - if(oldenv != NULL) { - tmp += ";"; - tmp += oldenv; + gchar const *path = g_getenv("PATH"); + gchar const *pythonpath = g_getenv("PYTHONPATH"); + + gchar *python = g_build_filename(exe, "python", NULL); + gchar *scripts = g_build_filename(exe, "python", "Scripts", NULL); + gchar *perl = g_build_filename(exe, "python", NULL); + gchar *pythonlib = g_build_filename(exe, "python", "Lib", NULL); + gchar *pythondll = g_build_filename(exe, "python", "DLLs", NULL); + + // Python 2.x needs short paths in PYTHONPATH. + // Otherwise it doesn't work when Inkscape is installed in Unicode directories. + // g_win32_locale_filename_from_utf8 is the Glib equivalent + // of GetShortPathName. + // Remove this once we move to Python 3.0. + gchar *python_s = g_win32_locale_filename_from_utf8(python); + gchar *pythonlib_s = g_win32_locale_filename_from_utf8(pythonlib); + gchar *pythondll_s = g_win32_locale_filename_from_utf8(pythondll); + + gchar *new_path; + gchar *new_pythonpath; + if (path) { + new_path = g_strdup_printf("%s;%s;%s;%s;%s", exe, python, scripts, perl, path); + } else { + new_path = g_strdup_printf("%s;%s;%s;%s", exe, python, scripts, perl); } - _putenv(tmp.c_str()); - - oldenv = getenv("PYTHONPATH"); - tmp = "PYTHONPATH="; - tmp += exePath; - tmp += "\\python;"; - tmp += exePath; - tmp += "\\python\\Lib;"; - tmp += exePath; - tmp += "\\python\\DLLs"; - if(oldenv != NULL) { - tmp += ";"; - tmp += oldenv; + if (pythonpath) { + new_pythonpath = g_strdup_printf("%s;%s;%s;%s", python_s, pythonlib_s, pythondll_s, pythonpath); + } else { + new_pythonpath = g_strdup_printf("%s;%s;%s", python_s, pythonlib_s, pythondll_s); } - _putenv(tmp.c_str()); - return 0; + g_setenv("PATH", new_path, TRUE); + g_setenv("PYTHONPATH", new_pythonpath, TRUE); + + /* + printf("PATH = %s\n\n", g_getenv("PATH")); + printf("PYTHONPATH = %s\n\n", g_getenv("PYTHONPATH")); + + gchar *p = g_find_program_in_path("python"); + if (p) { + printf("python in %s\n\n", p); + g_free(p); + } else { + printf("python not found\n\n"); + }*/ + + g_free(python); + g_free(scripts); + g_free(perl); + g_free(pythonlib); + g_free(pythondll); + + g_free(python_s); + g_free(pythonlib_s); + g_free(pythondll_s); + + g_free(new_path); + g_free(new_pythonpath); } #endif @@ -568,55 +580,68 @@ main(int argc, char **argv) when inkscape.exe is executed from another directory. We use relative paths on win32. HKCR\svgfile\shell\open\command is a good example + + TODO: this breaks the CLI on Windows, see LP #167455 + However, the CLI is broken anyway, because we are a GUI app */ - Glib::ustring homedir = _win32_getExePath(); - // TODO these should use xxxW() calls explicitly and convert UTF-16 <--> UTF-8 - SetCurrentDirectory(homedir.c_str()); - _win32_set_inkscape_env(homedir); + const int pathbuf = 2048; + gunichar2 *path = g_new(gunichar2, pathbuf); + GetModuleFileNameW(NULL, (WCHAR*) path, pathbuf); + gchar *inkscape = g_utf16_to_utf8(path, -1, NULL, NULL, NULL); + gchar *exedir = g_path_get_dirname(inkscape); + gunichar2 *dirw = g_utf8_to_utf16(exedir, -1, NULL, NULL, NULL); + SetCurrentDirectoryW((WCHAR*) dirw); + _win32_set_inkscape_env(exedir); + +# ifdef ENABLE_NLS + // obtain short path to executable dir and pass it + // to bindtextdomain (it doesn't understand UTF-8) + gchar *shortexedir = g_win32_locale_filename_from_utf8(exedir); + gchar *localepath = g_build_filename(shortexedir, PACKAGE_LOCALE_DIR, NULL); + bindtextdomain(GETTEXT_PACKAGE, localepath); + g_free(shortexedir); + g_free(localepath); +# endif + + g_free(path); + g_free(inkscape); + g_free(exedir); + g_free(dirw); + // Don't touch the registry (works fine without it) for Inkscape Portable gchar const *val = g_getenv("INKSCAPE_PORTABLE_PROFILE_DIR"); if (!val) { RegistryTool rt; rt.setPathInfo(); } -#endif - - // Prevents errors like "Unable to wrap GdkPixbuf..." (in nr-filter-image.cpp for example) - Gtk::Main::init_gtkmm_internals(); - - // Bug #197475 - set_extensions_env(); - - /** - * Call bindtextdomain() for various machines's paths - */ -#ifdef ENABLE_NLS -#ifdef WIN32 - Glib::ustring localePath = homedir; - localePath += "\\"; - localePath += PACKAGE_LOCALE_DIR; - bindtextdomain(GETTEXT_PACKAGE, localePath.c_str()); -#else -#ifdef ENABLE_BINRELOC +#elif defined(ENABLE_NLS) +# ifdef ENABLE_BINRELOC bindtextdomain(GETTEXT_PACKAGE, BR_LOCALEDIR("")); -#else +# else bindtextdomain(GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR); +# endif #endif -#endif + + // the bit below compiles regardless of platform +#ifdef ENABLE_NLS // Allow the user to override the locale directory by setting // the environment variable INKSCAPE_LOCALEDIR. - char *inkscape_localedir = getenv("INKSCAPE_LOCALEDIR"); + char const *inkscape_localedir = g_getenv("INKSCAPE_LOCALEDIR"); if (inkscape_localedir != NULL) { bindtextdomain(GETTEXT_PACKAGE, inkscape_localedir); } -#endif + // common setup bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8"); - -#ifdef ENABLE_NLS textdomain(GETTEXT_PACKAGE); #endif + // Prevents errors like "Unable to wrap GdkPixbuf..." (in nr-filter-image.cpp for example) + Gtk::Main::init_gtkmm_internals(); + + // Bug #197475 + set_extensions_env(); + LIBXML_TEST_VERSION Inkscape::GC::init(); @@ -626,8 +651,7 @@ main(int argc, char **argv) gboolean use_gui; #ifndef WIN32 - // TODO use g_getenv() and g_setenv() that use filename encoding, which is UTF-8 on Windows - use_gui = (getenv("DISPLAY") != NULL); + use_gui = (g_getenv("DISPLAY") != NULL); #else use_gui = TRUE; #endif diff --git a/src/prefix.cpp b/src/prefix.cpp index f1fa3c2cd..8c1dd4f00 100644 --- a/src/prefix.cpp +++ b/src/prefix.cpp @@ -31,14 +31,7 @@ #endif -/* PLEASE NOTE: We use GThreads now for portability */ -/* @see http://developer.gnome.org/doc/API/2.0/glib/glib-Threads.html */ -#ifndef BR_THREADS - /* Change 1 to 0 if you don't want thread support */ - #define BR_THREADS 1 - #include //for GThreads -#endif /* BR_THREADS */ - +#include #include #include #include @@ -55,9 +48,9 @@ extern "C" { #define NULL ((void *) 0) #ifdef __GNUC__ - #define br_return_val_if_fail(expr,val) if (!(expr)) {fprintf (stderr, "** BinReloc (%s): assertion %s failed\n", __PRETTY_FUNCTION__, #expr); return val;} + #define br_return_val_if_fail(expr,val) if (!(expr)) {fprintf (stderr, "** BinReloc (%s): assertion %s failed\n", __PRETTY_FUNCTION__, #expr); return val;} #else - #define br_return_val_if_fail(expr,val) if (!(expr)) return val + #define br_return_val_if_fail(expr,val) if (!(expr)) return val #endif /* __GNUC__ */ @@ -72,8 +65,8 @@ extern "C" { * br_locate: * symbol: A symbol that belongs to the app/library you want to locate. * Returns: A newly allocated string containing the full path of the - * app/library that func belongs to, or NULL on error. This - * string should be freed when not when no longer needed. + * app/library that func belongs to, or NULL on error. This + * string should be freed when not when no longer needed. * * Finds out to which application or library symbol belongs, then locate * the full path of that application or library. @@ -85,70 +78,70 @@ extern "C" { * #include "libfoo.h" * * int main (int argc, char *argv[]) { - * printf ("Full path of this app: %s\n", br_locate (&argc)); - * libfoo_start (); - * return 0; + * printf ("Full path of this app: %s\n", br_locate (&argc)); + * libfoo_start (); + * return 0; * } * * --> libfoo.c starts here * #include "prefix.h" * * void libfoo_start () { - * --> "" is a symbol that belongs to libfoo (because it's called - * --> from libfoo_start()); that's why this works. - * printf ("libfoo is located in: %s\n", br_locate ("")); + * --> "" is a symbol that belongs to libfoo (because it's called + * --> from libfoo_start()); that's why this works. + * printf ("libfoo is located in: %s\n", br_locate ("")); * } */ char * br_locate (void *symbol) { - char line[5000]; - FILE *f; - char *path; - - br_return_val_if_fail (symbol != NULL, NULL); - - f = fopen ("/proc/self/maps", "r"); - if (!f) - return NULL; - - while (!feof (f)) - { - unsigned long start, end; - - if (!fgets (line, sizeof (line), f)) - continue; - if (!strstr (line, " r-xp ") || !strchr (line, '/')) - continue; - - sscanf (line, "%lx-%lx ", &start, &end); - if (symbol >= (void *) start && symbol < (void *) end) - { - char *tmp; - size_t len; - - /* Extract the filename; it is always an absolute path */ - path = strchr (line, '/'); - - /* Get rid of the newline */ - tmp = strrchr (path, '\n'); - if (tmp) *tmp = 0; - - /* Get rid of "(deleted)" */ - len = strlen (path); - if (len > 10 && strcmp (path + len - 10, " (deleted)") == 0) - { - tmp = path + len - 10; - *tmp = 0; - } - - fclose(f); - return strdup (path); - } - } - - fclose (f); - return NULL; + char line[5000]; + FILE *f; + char *path; + + br_return_val_if_fail (symbol != NULL, NULL); + + f = fopen ("/proc/self/maps", "r"); + if (!f) + return NULL; + + while (!feof (f)) + { + unsigned long start, end; + + if (!fgets (line, sizeof (line), f)) + continue; + if (!strstr (line, " r-xp ") || !strchr (line, '/')) + continue; + + sscanf (line, "%lx-%lx ", &start, &end); + if (symbol >= (void *) start && symbol < (void *) end) + { + char *tmp; + size_t len; + + /* Extract the filename; it is always an absolute path */ + path = strchr (line, '/'); + + /* Get rid of the newline */ + tmp = strrchr (path, '\n'); + if (tmp) *tmp = 0; + + /* Get rid of "(deleted)" */ + len = strlen (path); + if (len > 10 && strcmp (path + len - 10, " (deleted)") == 0) + { + tmp = path + len - 10; + *tmp = 0; + } + + fclose(f); + return strdup (path); + } + } + + fclose (f); + return NULL; } @@ -168,16 +161,16 @@ br_locate (void *symbol) char * br_locate_prefix (void *symbol) { - char *path, *prefix; + char *path, *prefix; - br_return_val_if_fail (symbol != NULL, NULL); + br_return_val_if_fail (symbol != NULL, NULL); - path = br_locate (symbol); - if (!path) return NULL; + path = br_locate (symbol); + if (!path) return NULL; - prefix = br_extract_prefix (path); - free (path); - return prefix; + prefix = br_extract_prefix (path); + free (path); + return prefix; } @@ -186,7 +179,7 @@ br_locate_prefix (void *symbol) * symbol: A symbol that belongs to the app/library you want to locate. * path: The path that you want to prepend the prefix to. * Returns: The new path, or NULL on error. This string should be freed when no - * longer needed. + * longer needed. * * Gets the prefix of the app/library that symbol belongs to. Prepend that prefix to path. * Note that symbol cannot be a pointer to a function. That will not work. @@ -198,24 +191,24 @@ br_locate_prefix (void *symbol) char * br_prepend_prefix (void *symbol, char *path) { - char *tmp, *newpath; + char *tmp, *newpath; - br_return_val_if_fail (symbol != NULL, NULL); - br_return_val_if_fail (path != NULL, NULL); + br_return_val_if_fail (symbol != NULL, NULL); + br_return_val_if_fail (path != NULL, NULL); - tmp = br_locate_prefix (symbol); - if (!tmp) return NULL; + tmp = br_locate_prefix (symbol); + if (!tmp) return NULL; - if (strcmp (tmp, "/") == 0) - newpath = strdup (path); - else - newpath = br_strcat (tmp, path); + if (strcmp (tmp, "/") == 0) + newpath = strdup (path); + else + newpath = br_strcat (tmp, path); - /* Get rid of compiler warning ("br_prepend_prefix never used") */ - if (0) br_prepend_prefix (NULL, NULL); + /* Get rid of compiler warning ("br_prepend_prefix never used") */ + if (0) br_prepend_prefix (NULL, NULL); - free (tmp); - return newpath; + free (tmp); + return newpath; } #endif /* ENABLE_BINRELOC */ @@ -264,33 +257,33 @@ br_free_last_value () const char * br_thread_local_store (char *str) { - #if BR_THREADS + #if BR_THREADS if (!g_thread_supported ()) { g_thread_init ((GThreadFunctions *)NULL); br_thread_key = g_private_new (g_free); } - char *specific = (char *) g_private_get (br_thread_key); - if (specific) + char *specific = (char *) g_private_get (br_thread_key); + if (specific) free (specific); g_private_set (br_thread_key, str); - #else /* !BR_THREADS */ - static int initialized = 0; + #else /* !BR_THREADS */ + static int initialized = 0; - if (!initialized) - { - atexit (br_free_last_value); - initialized = 1; - } + if (!initialized) + { + atexit (br_free_last_value); + initialized = 1; + } - if (br_last_value) - free (br_last_value); - br_last_value = str; - #endif /* BR_THREADS */ + if (br_last_value) + free (br_last_value); + br_last_value = str; + #endif /* BR_THREADS */ - return (const char *) str; + return (const char *) str; } @@ -305,21 +298,21 @@ br_thread_local_store (char *str) char * br_strcat (const char *str1, const char *str2) { - char *result; - size_t len1, len2; + char *result; + size_t len1, len2; - if (!str1) str1 = ""; - if (!str2) str2 = ""; + if (!str1) str1 = ""; + if (!str2) str2 = ""; - len1 = strlen (str1); - len2 = strlen (str2); + len1 = strlen (str1); + len2 = strlen (str2); - result = (char *) malloc (len1 + len2 + 1); - memcpy (result, str1, len1); - memcpy (result + len1, str2, len2); - result[len1 + len2] = '\0'; + result = (char *) malloc (len1 + len2 + 1); + memcpy (result, str1, len1); + memcpy (result + len1, str2, len2); + result[len1 + len2] = '\0'; - return result; + return result; } @@ -327,18 +320,18 @@ br_strcat (const char *str1, const char *str2) static char * br_strndup (char *str, size_t size) { - char *result = (char*)NULL; - size_t len; + char *result = (char*)NULL; + size_t len; - br_return_val_if_fail (str != (char*)NULL, (char*)NULL); + br_return_val_if_fail (str != (char*)NULL, (char*)NULL); - len = strlen (str); - if (!len) return strdup (""); - if (size > len) size = len; + len = strlen (str); + if (!len) return strdup (""); + if (size > len) size = len; - result = (char *) calloc (sizeof (char), len + 1); - memcpy (result, str, size); - return result; + result = (char *) calloc (sizeof (char), len + 1); + memcpy (result, str, size); + return result; } @@ -356,23 +349,23 @@ br_strndup (char *str, size_t size) char * br_extract_dir (const char *path) { - const char *end; - char *result; - - br_return_val_if_fail (path != (char*)NULL, (char*)NULL); - - end = strrchr (path, '/'); - if (!end) return strdup ("."); - - while (end > path && *end == '/') - end--; - result = br_strndup ((char *) path, end - path + 1); - if (!*result) - { - free (result); - return strdup ("/"); - } else - return result; + const char *end; + char *result; + + br_return_val_if_fail (path != (char*)NULL, (char*)NULL); + + end = strrchr (path, '/'); + if (!end) return strdup ("."); + + while (end > path && *end == '/') + end--; + result = br_strndup ((char *) path, end - path + 1); + if (!*result) + { + free (result); + return strdup ("/"); + } else + return result; } @@ -392,34 +385,34 @@ br_extract_dir (const char *path) char * br_extract_prefix (const char *path) { - const char *end; - char *tmp, *result; - - br_return_val_if_fail (path != (char*)NULL, (char*)NULL); - - if (!*path) return strdup ("/"); - end = strrchr (path, '/'); - if (!end) return strdup (path); - - tmp = br_strndup ((char *) path, end - path); - if (!*tmp) - { - free (tmp); - return strdup ("/"); - } - end = strrchr (tmp, '/'); - if (!end) return tmp; - - result = br_strndup (tmp, end - tmp); - free (tmp); - - if (!*result) - { - free (result); - result = strdup ("/"); - } - - return result; + const char *end; + char *tmp, *result; + + br_return_val_if_fail (path != (char*)NULL, (char*)NULL); + + if (!*path) return strdup ("/"); + end = strrchr (path, '/'); + if (!end) return strdup (path); + + tmp = br_strndup ((char *) path, end - path); + if (!*tmp) + { + free (tmp); + return strdup ("/"); + } + end = strrchr (tmp, '/'); + if (!end) return tmp; + + result = br_strndup (tmp, end - tmp); + free (tmp); + + if (!*result) + { + free (result); + result = strdup ("/"); + } + + return result; } @@ -444,13 +437,14 @@ br_extract_prefix (const char *path) */ static Glib::ustring win32_getExePath() { - char exeName[MAX_PATH+1]; - GetModuleFileName(NULL, exeName, MAX_PATH); - char *slashPos = strrchr(exeName, '\\'); - if (slashPos) - *slashPos = '\0'; - Glib::ustring s = exeName; - return s; + gunichar2 path[2048]; + GetModuleFileNameW(NULL, (WCHAR*) path, 2048); + gchar *exe = g_utf16_to_utf8(path, -1, NULL, NULL, NULL); + gchar *dir = g_path_get_dirname(exe); + Glib::ustring ret = dir; + g_free(dir); + g_free(exe); + return ret; } @@ -461,8 +455,8 @@ static Glib::ustring win32_getExePath() static Glib::ustring win32_getDataDir() { Glib::ustring dir = win32_getExePath(); - if (INKSCAPE_DATADIR && *INKSCAPE_DATADIR && - strcmp(INKSCAPE_DATADIR, ".") != 0) + if (INKSCAPE_DATADIR && *INKSCAPE_DATADIR && + strcmp(INKSCAPE_DATADIR, ".") != 0) { dir += "\\"; dir += INKSCAPE_DATADIR; diff --git a/src/registrytool.cpp b/src/registrytool.cpp index 2017f50c7..af41c3eaf 100644 --- a/src/registrytool.cpp +++ b/src/registrytool.cpp @@ -60,6 +60,7 @@ bool RegistryTool::setStringValue(const Glib::ustring &keyNameArg, const Glib::ustring &value) { Glib::ustring keyName = keyNameArg; + bool ret = false; HKEY rootKey = HKEY_LOCAL_MACHINE; //default root //Trim out the root key if necessary @@ -74,28 +75,35 @@ bool RegistryTool::setStringValue(const Glib::ustring &keyNameArg, //printf("trimmed string: '%s'\n", keyName.c_str()); //Get or create the key + gunichar2 *keyw = g_utf8_to_utf16(keyName.data(), -1, 0,0,0); + gunichar2 *valuenamew = g_utf8_to_utf16(valueName.data(), -1, 0,0,0); + HKEY key; - if (RegCreateKeyEx(rootKey, keyName.c_str(), + if (RegCreateKeyExW(rootKey, (WCHAR*) keyw, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &key, NULL)) - { + { fprintf(stderr, "RegistryTool: Could not create the registry key '%s'\n", keyName.c_str()); - return false; - } + goto fail; + } - //Set the value - if (RegSetValueEx(key, valueName.c_str(), - 0, REG_SZ, (LPBYTE) value.c_str(), (DWORD) value.size())) - { + // Set the value + if (RegSetValueExW(key, (WCHAR*) valuenamew, + 0, REG_SZ, (LPBYTE) value.data(), (DWORD) (value.size() + 1))) + { fprintf(stderr, "RegistryTool: Could not set the value '%s'\n", value.c_str()); - RegCloseKey(key); - return false; - } - + goto failkey; + } + ret = true; + + failkey: RegCloseKey(key); - - return true; + + fail: + g_free(keyw); + g_free(valuenamew); + return ret; } @@ -107,19 +115,14 @@ bool RegistryTool::getExeInfo(Glib::ustring &fullPath, Glib::ustring &path, Glib::ustring &exeName) { + const int pathbuf = 2048; + gunichar2 pathw[pathbuf]; + GetModuleFileNameW(NULL, (WCHAR*) pathw, pathbuf); - char buf[MAX_PATH+1]; - if (!GetModuleFileName(NULL, buf, MAX_PATH)) - { - fprintf(stderr, "Could not fetch executable file name\n"); - return false; - } - else - { - //printf("Executable file name: '%s'\n", buf); - } + gchar *utf8path = g_utf16_to_utf8(pathw, -1, 0,0,0); + fullPath = utf8path; + g_free(utf8path); - fullPath = buf; path = ""; exeName = ""; Glib::ustring::size_type pos = fullPath.rfind('\\');