index 5f1bef8d1afe1013e6189b00df72a2114818aea2..bc143fd14ece526f129b0c68576dc9d107e8081e 100644 (file)
* Authors:
* Bryce Harrington <bryce@osdl.org>
* Ted Gould <ted@gould.cx>
+ * Jon A. Cruz <jon@joncruz.org>
+ * Abhishek Sharma
*
* Copyright (C) 2002-2005,2007 Authors
*
#include <unistd.h>
#include <errno.h>
+#include <glib.h>
+#include <glib/gstdio.h>
#include <gtkmm.h>
#include "ui/view/view.h"
#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"
/** \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() )
+void Script::pump_events (void) {
+ while ( Gtk::Main::events_pending() ) {
Gtk::Main::iteration();
+ }
return;
}
/** \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;
+ 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;
}
}
// Do we have a supported interpreter type?
- if (!foundInterp)
+ 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)) {
- 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];
- char szCurrentDir[MAX_PATH];
- GetCurrentDirectory(sizeof(szCurrentDir), szCurrentDir);
- unsigned int ret = (unsigned int)FindExecutable(
- interpName.c_str(), szCurrentDir, szExePath);
- if (ret > 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;
+ return interpreter_path;
}
/** \brief This function creates a script object and sets up the
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);
-
- if ( Inkscape::IO::file_test(filename.c_str(), G_FILE_TEST_EXISTS) )
- return filename;
+ 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 Glib::filename_from_utf8(filename);
}
- } else {
- Glib::ustring str = sp_repr_children(reprin)->content();
- return str;
}
return "";
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
+ } 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;
+ }
std::string::size_type pos = 0;
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) {
}
//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;
}
and should error out at a higher level.
*/
-bool
-Script::load(Inkscape::Extension::Extension *module)
+bool Script::load(Inkscape::Extension::Extension *module)
{
- if (module->loaded())
+ if (module->loaded()) {
return true;
+ }
helper_extension = "";
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();
This function just sets the module to unloaded. It free's the
command if it has been allocated.
*/
-void
-Script::unload(Inkscape::Extension::Extension */*module*/)
+void Script::unload(Inkscape::Extension::Extension */*module*/)
{
command.clear();
helper_extension = "";
bool
Script::check(Inkscape::Extension::Extension *module)
{
- int script_count = 0;
+ int script_count = 0;
Inkscape::XML::Node *child_repr = sp_repr_children(module->get_repr());
while (child_repr != NULL) {
if (!strcmp(child_repr->name(), INKSCAPE_EXTENSION_NS "script")) {
- script_count++;
+ script_count++;
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;
}
child_repr = sp_repr_next(child_repr);
}
- if (script_count == 0) {
- return false;
- }
+ if (script_count == 0) {
+ return false;
+ }
return true;
}
unlink(_filename.c_str());
}
-ImplementationDocumentCache *
-Script::newDocCache( Inkscape::Extension::Extension * /*ext*/, Inkscape::UI::View::View * view ) {
+ImplementationDocumentCache *Script::newDocCache( Inkscape::Extension::Extension * /*ext*/, Inkscape::UI::View::View * view ) {
return new ScriptDocCache(view);
}
@@ -502,8 +457,7 @@ Script::newDocCache( Inkscape::Extension::Extension * /*ext*/, Inkscape::UI::Vie
This function should really do something, right now it doesn't.
*/
-Gtk::Widget *
-Script::prefs_input(Inkscape::Extension::Input *module,
+Gtk::Widget *Script::prefs_input(Inkscape::Extension::Input *module,
const gchar */*filename*/)
{
return module->autogui(NULL, NULL);
This function should really do something, right now it doesn't.
*/
-Gtk::Widget *
-Script::prefs_output(Inkscape::Extension::Output *module)
+Gtk::Widget *Script::prefs_output(Inkscape::Extension::Output *module)
{
return module->autogui(NULL, NULL);
}
the incoming filename (so that it's not the temporary filename).
That document is then returned from this function.
*/
-SPDocument *
-Script::open(Inkscape::Extension::Input *module,
+SPDocument *Script::open(Inkscape::Extension::Input *module,
const gchar *filenameArg)
{
std::list<std::string> params;
} // 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
put the output of the script into the final output file. We then
delete the temporary file.
*/
-void
-Script::save(Inkscape::Extension::Output *module,
+void Script::save(Inkscape::Extension::Output *module,
SPDocument *doc,
const gchar *filenameArg)
{
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);
// FIXME: convert to utf8 (from "filename encoding") and unlink_utf8name
unlink(tempfilename_in.c_str());
- if(success == false) {
+ if (success == false) {
throw Inkscape::Extension::Output::save_failed();
}
exists at the time, the other is created by that script). At that
point both should be full, and the second one is loaded.
*/
-void
-Script::effect(Inkscape::Extension::Effect *module,
+void Script::effect(Inkscape::Extension::Effect *module,
Inkscape::UI::View::View *doc,
ImplementationDocumentCache * docCache)
{
while ( selected != NULL ) {
Glib::ustring selected_id;
selected_id += "--id=";
- selected_id += SP_OBJECT_ID(*selected);
+ selected_id += (*selected)->getId();
params.insert(params.begin(), selected_id);
++selected;
}
// 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) {
elements and putting them into the old document. The copy
is then complete.
*/
-void
-Script::copy_doc (Inkscape::XML::Node * oldroot, Inkscape::XML::Node * newroot)
+void Script::copy_doc (Inkscape::XML::Node * oldroot, Inkscape::XML::Node * newroot)
{
std::vector<Inkscape::XML::Node *> delete_list;
Inkscape::XML::Node * oldroot_namedview = NULL;
delete_list.push_back(child);
}
}
- for (unsigned int i = 0; i < delete_list.size(); i++)
+ for (unsigned int i = 0; i < delete_list.size(); i++) {
sp_repr_unparent(delete_list[i]);
+ }
for (Inkscape::XML::Node * child = newroot->firstChild();
child != NULL;
}
// Delete the attributes of the old root nodes.
- for (std::vector<gchar const *>::const_iterator it = attribs.begin(); it != attribs.end(); it++)
+ for (std::vector<gchar const *>::const_iterator it = attribs.begin(); it != attribs.end(); it++) {
oldroot->setAttribute(*it, NULL);
+ }
// Set the new attributes.
for (List<AttributeRecord const> iter = newroot->attributeList(); iter; ++iter) {
shows it in a warning dialog to the user
\param filename Filename of the stderr file
*/
-void
-Script::checkStderr (const Glib::ustring &data,
+void Script::checkStderr (const Glib::ustring &data,
Gtk::MessageType type,
const Glib::ustring &message)
{
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);
return;
}
-bool
-Script::cancelProcessing (void) {
+bool Script::cancelProcessing (void) {
_canceled = true;
_main_loop->quit();
Glib::spawn_close_pid(_pid);
At the very end (after the data has been copied) both of the files
are closed, and we return to what we were doing.
*/
-int
-Script::execute (const std::list<std::string> &in_command,
+int Script::execute (const std::list<std::string> &in_command,
const std::list<std::string> &in_params,
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 <std::string> argv;
+ std::vector<std::string> argv;
-/*
- for (std::list<std::string>::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<std::string>::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 = "";
- }
+ bool interpreted = (in_command.size() == 2);
+ std::string program = in_command.front();
+ std::string script = interpreted ? in_command.back() : "";
+ std::string working_directory = "";
- }
- 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);
+ // 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
- for (std::list<std::string>::const_iterator i = in_params.begin();
- i != in_params.end(); i++) {
- //g_message("Script parameter: %s",(*i)g.c_str());
- argv.push_back(*i);
+ argv.push_back(script);
}
- if (!(filein.empty())) {
- argv.push_back(filein);
+ // 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<Glib::SpawnFlags>(0), // no flags
sigc::slot<void>(),
&_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;
}
_main_loop->run();
// Ensure all the data is out of the pipe
- while (!fileout.isDead())
+ while (!fileout.isDead()) {
fileout.read(Glib::IO_IN);
- while (!fileerr.isDead())
+ }
+ while (!fileerr.isDead()) {
fileerr.read(Glib::IO_IN);
+ }
if (_canceled) {
// std::cout << "Script Canceled" << std::endl;
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. "
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 :