X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fextension%2Fimplementation%2Fscript.cpp;h=428ee626fd361f79342dc7624d67f192e62da165;hb=9374eea4b2a4b72eeb5e7cc0ebc6db99931a48df;hp=4e8d0b3607aba700a417cd8ad14fac3df67ec525;hpb=0e2ae4c8c8b08dd632bb7cc019dcef111ac810d6;p=inkscape.git diff --git a/src/extension/implementation/script.cpp b/src/extension/implementation/script.cpp index 4e8d0b360..428ee626f 100644 --- a/src/extension/implementation/script.cpp +++ b/src/extension/implementation/script.cpp @@ -6,6 +6,7 @@ * Bryce Harrington * Ted Gould * Jon A. Cruz + * Abhishek Sharma * * Copyright (C) 2002-2005,2007 Authors * @@ -21,6 +22,8 @@ #include #include +#include +#include #include #include "ui/view/view.h" @@ -37,7 +40,7 @@ #include "extension/db.h" #include "script.h" #include "dialogs/dialog-events.h" -#include "application/application.h" +#include "inkscape.h" #include "xml/node.h" #include "xml/attribute-record.h" @@ -65,8 +68,8 @@ namespace Implementation { /** \brief Make GTK+ events continue to come through a little bit - This just keeps coming the events through so that we'll make the GUI - update and look pretty. + This just keeps coming the events through so that we'll make the GUI + update and look pretty. */ void Script::pump_events (void) { while ( Gtk::Main::events_pending() ) { @@ -97,18 +100,16 @@ Script::interpreter_t const Script::interpreterTab[] = { /** \brief Look up an interpreter name, and translate to something that - is executable + is executable \param interpNameArg The name of the interpreter that we're looking - for, should be an entry in interpreterTab + 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 +119,25 @@ 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; + interpreter_path = Glib::filename_from_utf8(prefInterp); } -#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; - } + // 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); } - - // 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; - } - -#endif // win32 - - - return interpName; + 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; } @@ -577,9 +533,8 @@ SPDocument *Script::open(Inkscape::Extension::Input *module, } // data_read if (mydoc != NULL) { - g_free(mydoc->base); - mydoc->base = NULL; - sp_document_change_uri_and_hrefs(mydoc, filenameArg); + mydoc->setBase(0); + mydoc->changeUriAndHrefs(filenameArg); } // make sure we don't leak file descriptors from g_file_open_tmp @@ -647,10 +602,14 @@ void Script::save(Inkscape::Extension::Output *module, file_listener fileout; - execute(command, params, tempfilename_in, fileout); + int data_read = execute(command, params, tempfilename_in, fileout); + + bool success = false; - std::string lfilename = Glib::filename_from_utf8(filenameArg); - bool success = fileout.toFile(lfilename); + if (data_read > 0) { + std::string lfilename = Glib::filename_from_utf8(filenameArg); + success = fileout.toFile(lfilename); + } // make sure we don't leak file descriptors from g_file_open_tmp close(tempfd_in); @@ -739,7 +698,7 @@ void Script::effect(Inkscape::Extension::Effect *module, while ( selected != NULL ) { Glib::ustring selected_id; selected_id += "--id="; - selected_id += (*selected)->id; + selected_id += (*selected)->getId(); params.insert(params.begin(), selected_id); ++selected; } @@ -763,8 +722,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) { @@ -881,7 +839,13 @@ void Script::checkStderr (const Glib::ustring &data, textview->set_wrap_mode(Gtk::WRAP_WORD); textview->show(); - textview->get_buffer()->set_text(data.c_str()); + // Remove the last character + char *errormsg = (char*) data.c_str(); + while (*errormsg != '\0') errormsg++; + errormsg -= 1; + *errormsg = '\0'; + + textview->get_buffer()->set_text(_(data.c_str())); Gtk::ScrolledWindow * scrollwindow = new Gtk::ScrolledWindow(); scrollwindow->add(*textview); @@ -937,89 +901,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; } @@ -1047,7 +983,7 @@ int Script::execute (const std::list &in_command, Glib::ustring stderr_data = fileerr.string(); if (stderr_data.length() != 0 && - Inkscape::NSApplication::Application::getUseGui() + inkscape_use_gui() ) { checkStderr(stderr_data, Gtk::MESSAGE_INFO, _("Inkscape has received additional data from the script executed. " @@ -1079,4 +1015,4 @@ int Script::execute (const std::list &in_command, fill-column:99 End: */ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :