2
* Code for handling extensions (i.e.\ scripts).
6
* Bryce Harrington <bryce@osdl.org>
7
* Ted Gould <ted@gould.cx>
9
* Copyright (C) 2002-2005,2007 Authors
11
* Released under GNU GPL, read the file 'COPYING' for more information
14
#define __INKSCAPE_EXTENSION_IMPLEMENTATION_SCRIPT_C__
25
#include "ui/view/view.h"
26
#include "desktop-handles.h"
28
#include "selection.h"
29
#include "sp-namedview.h"
31
#include "preferences.h"
32
#include "../system.h"
33
#include "extension/effect.h"
34
#include "extension/output.h"
35
#include "extension/input.h"
36
#include "extension/db.h"
38
#include "dialogs/dialog-events.h"
39
#include "application/application.h"
41
#include "xml/attribute-record.h"
43
#include "util/glib-list-iterators.h"
50
#include "registrytool.h"
55
/** This is the command buffer that gets allocated from the stack */
63
namespace Implementation {
65
/** \brief Make GTK+ events continue to come through a little bit
67
This just keeps coming the events through so that we'll make the GUI
68
update and look pretty.
71
Script::pump_events (void) {
72
while( Gtk::Main::events_pending() )
73
Gtk::Main::iteration();
78
/** \brief A table of what interpreters to call for a given language
80
This table is used to keep track of all the programs to execute a
81
given script. It also tracks the preference to use to overwrite
82
the given interpreter to a custom one per user.
84
Script::interpreter_t const Script::interpreterTab[] = {
85
{"perl", "perl-interpreter", "perl" },
87
{"python", "python-interpreter", "pythonw" },
89
{"python", "python-interpreter", "python" },
91
{"ruby", "ruby-interpreter", "ruby" },
92
{"shell", "shell-interpreter", "sh" },
98
/** \brief Look up an interpreter name, and translate to something that
100
\param interpNameArg The name of the interpreter that we're looking
101
for, should be an entry in interpreterTab
104
Script::resolveInterpreterExecutable(const Glib::ustring &interpNameArg)
107
Glib::ustring interpName = interpNameArg;
109
interpreter_t const *interp;
110
bool foundInterp = false;
111
for (interp = interpreterTab ; interp->identity ; interp++ ){
112
if (interpName == interp->identity) {
118
// Do we have a supported interpreter type?
121
interpName = interp->defaultval;
123
// 1. Check preferences
124
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
125
Glib::ustring prefInterp = prefs->getString("/extensions/" + Glib::ustring(interp->prefstring));
127
if (!prefInterp.empty()) {
128
interpName = prefInterp;
134
// 2. Windows. Try looking relative to inkscape.exe
136
Glib::ustring fullPath;
138
Glib::ustring exeName;
139
if (rt.getExeInfo(fullPath, path, exeName)) {
140
Glib::ustring interpPath = path;
141
interpPath.append("\\");
142
interpPath.append(interpNameArg);
143
interpPath.append("\\");
144
interpPath.append(interpName);
145
interpPath.append(".exe");
147
if (stat(interpPath .c_str(), &finfo) ==0) {
148
g_message("Found local interpreter, '%s', Size: %d",
155
// 3. Try searching the path
156
char szExePath[MAX_PATH];
157
char szCurrentDir[MAX_PATH];
158
GetCurrentDirectory(sizeof(szCurrentDir), szCurrentDir);
159
unsigned int ret = (unsigned int)FindExecutable(
160
interpName.c_str(), szCurrentDir, szExePath);
162
interpName = szExePath;
172
/** \brief This function creates a script object and sets up the
174
\return A script object
176
This function just sets the command to NULL. It should get built
177
officially in the load function. This allows for less allocation
178
of memory in the unloaded state.
195
\return A string with the complete string with the relative directory expanded
196
\brief This function takes in a Repr that contains a reldir entry
197
and returns that data with the relative directory expanded.
198
Mostly it is here so that relative directories all get used
200
\param reprin The Inkscape::XML::Node with the reldir in it.
202
Basically this function looks at an attribute of the Repr, and makes
203
a decision based on that. Currently, it is only working with the
204
'extensions' relative directory, but there will be more of them.
205
One thing to notice is that this function always returns an allocated
206
string. This means that the caller of this function can always
207
free what they are given (and should do it too!).
210
Script::solve_reldir(Inkscape::XML::Node *reprin) {
212
gchar const *s = reprin->attribute("reldir");
215
Glib::ustring str = sp_repr_children(reprin)->content();
219
Glib::ustring reldir = s;
221
if (reldir == "extensions") {
223
for (unsigned int i=0;
224
i < Inkscape::Extension::Extension::search_path.size();
227
gchar * fname = g_build_filename(
228
Inkscape::Extension::Extension::search_path[i],
229
sp_repr_children(reprin)->content(),
231
Glib::ustring filename = fname;
234
if ( Inkscape::IO::file_test(filename.c_str(), G_FILE_TEST_EXISTS) )
239
Glib::ustring str = sp_repr_children(reprin)->content();
249
\return Whether the command given exists, including in the path
250
\brief This function is used to find out if something exists for
251
the check command. It can look in the path if required.
252
\param command The command or file that should be looked for
254
The first thing that this function does is check to see if the
255
incoming file name has a directory delimiter in it. This would
256
mean that it wants to control the directories, and should be
259
If not, the path is used. Each entry in the path is stepped through,
260
attached to the string, and then tested. If the file is found
261
then a TRUE is returned. If we get all the way through the path
262
then a FALSE is returned, the command could not be found.
265
Script::check_existance(const Glib::ustring &command)
268
// Check the simple case first
269
if (command.size() == 0) {
273
//Don't search when it contains a slash. */
274
if (command.find(G_DIR_SEPARATOR) != command.npos) {
275
if (Inkscape::IO::file_test(command.c_str(), G_FILE_TEST_EXISTS))
283
gchar *s = (gchar *) g_getenv("PATH");
287
/* There is no `PATH' in the environment.
288
The default search path is the current directory */
289
path = G_SEARCHPATH_SEPARATOR_S;
291
std::string::size_type pos = 0;
292
std::string::size_type pos2 = 0;
293
while ( pos < path.size() ) {
295
Glib::ustring localPath;
297
pos2 = path.find(G_SEARCHPATH_SEPARATOR, pos);
298
if (pos2 == path.npos) {
299
localPath = path.substr(pos);
302
localPath = path.substr(pos, pos2-pos);
306
//printf("### %s\n", localPath.c_str());
307
Glib::ustring candidatePath =
308
Glib::build_filename(localPath, command);
310
if (Inkscape::IO::file_test(candidatePath .c_str(),
311
G_FILE_TEST_EXISTS)) {
326
\brief This function 'loads' an extention, basically it determines
327
the full command for the extention and stores that.
328
\param module The extention to be loaded.
330
The most difficult part about this function is finding the actual
331
command through all of the Reprs. Basically it is hidden down a
332
couple of layers, and so the code has to move down too. When
333
the command is actually found, it has its relative directory
336
At that point all of the loops are exited, and there is an
337
if statement to make sure they didn't exit because of not finding
338
the command. If that's the case, the extention doesn't get loaded
339
and should error out at a higher level.
343
Script::load(Inkscape::Extension::Extension *module)
345
if (module->loaded())
348
helper_extension = "";
350
/* This should probably check to find the executable... */
351
Inkscape::XML::Node *child_repr = sp_repr_children(module->get_repr());
352
while (child_repr != NULL) {
353
if (!strcmp(child_repr->name(), INKSCAPE_EXTENSION_NS "script")) {
354
child_repr = sp_repr_children(child_repr);
355
while (child_repr != NULL) {
356
if (!strcmp(child_repr->name(), INKSCAPE_EXTENSION_NS "command")) {
357
const gchar *interpretstr = child_repr->attribute("interpreter");
358
if (interpretstr != NULL) {
359
Glib::ustring interpString =
360
resolveInterpreterExecutable(interpretstr);
361
//g_message("Found: %s and %s",interpString.c_str(),interpretstr);
362
command.insert(command.end(), interpretstr);
364
Glib::ustring tmp = "\"";
365
tmp += solve_reldir(child_repr);
368
command.insert(command.end(), tmp);
370
if (!strcmp(child_repr->name(), INKSCAPE_EXTENSION_NS "helper_extension")) {
371
helper_extension = sp_repr_children(child_repr)->content();
373
child_repr = sp_repr_next(child_repr);
378
child_repr = sp_repr_next(child_repr);
381
//g_return_val_if_fail(command.length() > 0, false);
389
\brief Unload this puppy!
390
\param module Extension to be unloaded.
392
This function just sets the module to unloaded. It free's the
393
command if it has been allocated.
396
Script::unload(Inkscape::Extension::Extension */*module*/)
399
helper_extension = "";
406
\return Whether the check passed or not
407
\brief Check every dependency that was given to make sure we should keep this extension
408
\param module The Extension in question
412
Script::check(Inkscape::Extension::Extension *module)
414
int script_count = 0;
415
Inkscape::XML::Node *child_repr = sp_repr_children(module->get_repr());
416
while (child_repr != NULL) {
417
if (!strcmp(child_repr->name(), INKSCAPE_EXTENSION_NS "script")) {
419
child_repr = sp_repr_children(child_repr);
420
while (child_repr != NULL) {
421
if (!strcmp(child_repr->name(), INKSCAPE_EXTENSION_NS "check")) {
422
Glib::ustring command_text = solve_reldir(child_repr);
423
if (command_text.size() > 0) {
424
/* I've got the command */
425
bool existance = check_existance(command_text);
431
if (!strcmp(child_repr->name(), INKSCAPE_EXTENSION_NS "helper_extension")) {
432
gchar const *helper = sp_repr_children(child_repr)->content();
433
if (Inkscape::Extension::db.get(helper) == NULL) {
438
child_repr = sp_repr_next(child_repr);
443
child_repr = sp_repr_next(child_repr);
446
if (script_count == 0) {
453
class ScriptDocCache : public ImplementationDocumentCache {
456
std::string _filename;
459
ScriptDocCache (Inkscape::UI::View::View * view);
463
ScriptDocCache::ScriptDocCache (Inkscape::UI::View::View * view) :
464
ImplementationDocumentCache(view),
469
_tempfd = Inkscape::IO::file_open_tmp(_filename, "ink_ext_XXXXXX.svg");
471
/// \todo Popup dialog here
475
SPDesktop *desktop = (SPDesktop *) view;
476
sp_namedview_document_from_window(desktop);
478
Inkscape::Extension::save(
479
Inkscape::Extension::db.get(SP_MODULE_KEY_OUTPUT_SVG_INKSCAPE),
480
view->doc(), _filename.c_str(), false, false, false);
485
ScriptDocCache::~ScriptDocCache ( )
488
unlink(_filename.c_str());
491
ImplementationDocumentCache *
492
Script::newDocCache( Inkscape::Extension::Extension * /*ext*/, Inkscape::UI::View::View * view ) {
493
return new ScriptDocCache(view);
498
\return A dialog for preferences
499
\brief A stub funtion right now
500
\param module Module who's preferences need getting
501
\param filename Hey, the file you're getting might be important
503
This function should really do something, right now it doesn't.
506
Script::prefs_input(Inkscape::Extension::Input *module,
507
const gchar */*filename*/)
509
return module->autogui(NULL, NULL);
515
\return A dialog for preferences
516
\brief A stub funtion right now
517
\param module Module whose preferences need getting
519
This function should really do something, right now it doesn't.
522
Script::prefs_output(Inkscape::Extension::Output *module)
524
return module->autogui(NULL, NULL);
528
\return A new document that has been opened
529
\brief This function uses a filename that is put in, and calls
530
the extension's command to create an SVG file which is
532
\param module Extension to use.
533
\param filename File to open.
535
First things first, this function needs a temporary file name. To
536
create on of those the function g_file_open_tmp is used with
537
the header of ink_ext_.
539
The extension is then executed using the 'execute' function
540
with the filname coming in, and the temporary filename. After
541
That executing, the SVG should be in the temporary file.
543
Finally, the temporary file is opened using the SVG input module and
544
a document is returned. That document has its filename set to
545
the incoming filename (so that it's not the temporary filename).
546
That document is then returned from this function.
549
Script::open(Inkscape::Extension::Input *module,
550
const gchar *filenameArg)
552
std::list<std::string> params;
553
module->paramListString(params);
555
std::string tempfilename_out;
558
tempfd_out = Inkscape::IO::file_open_tmp(tempfilename_out, "ink_ext_XXXXXX.svg");
560
/// \todo Popup dialog here
564
std::string lfilename = Glib::filename_from_utf8(filenameArg);
566
file_listener fileout;
567
int data_read = execute(command, params, lfilename, fileout);
568
fileout.toFile(tempfilename_out);
570
SPDocument * mydoc = NULL;
571
if (data_read > 10) {
572
if (helper_extension.size()==0) {
573
mydoc = Inkscape::Extension::open(
574
Inkscape::Extension::db.get(SP_MODULE_KEY_INPUT_SVG),
575
tempfilename_out.c_str());
577
mydoc = Inkscape::Extension::open(
578
Inkscape::Extension::db.get(helper_extension.c_str()),
579
tempfilename_out.c_str());
586
sp_document_change_uri_and_hrefs(mydoc, filenameArg);
589
// make sure we don't leak file descriptors from g_file_open_tmp
592
unlink(tempfilename_out.c_str());
601
\brief This function uses an extention to save a document. It first
602
creates an SVG file of the document, and then runs it through
604
\param module Extention to be used
605
\param doc Document to be saved
606
\param filename The name to save the final file as
608
Well, at some point people need to save - it is really what makes
609
the entire application useful. And, it is possible that someone
610
would want to use an extetion for this, so we need a function to
613
First things first, the document is saved to a temporary file that
614
is an SVG file. To get the temporary filename g_file_open_tmp is used with
615
ink_ext_ as a prefix. Don't worry, this file gets deleted at the
618
After we have the SVG file, then extention_execute is called with
619
the temporary file name and the final output filename. This should
620
put the output of the script into the final output file. We then
621
delete the temporary file.
624
Script::save(Inkscape::Extension::Output *module,
626
const gchar *filenameArg)
628
std::list<std::string> params;
629
module->paramListString(params);
631
std::string tempfilename_in;
634
tempfd_in = Inkscape::IO::file_open_tmp(tempfilename_in, "ink_ext_XXXXXX.svg");
636
/// \todo Popup dialog here
640
if (helper_extension.size() == 0) {
641
Inkscape::Extension::save(
642
Inkscape::Extension::db.get(SP_MODULE_KEY_OUTPUT_SVG_INKSCAPE),
643
doc, tempfilename_in.c_str(), false, false, false);
645
Inkscape::Extension::save(
646
Inkscape::Extension::db.get(helper_extension.c_str()),
647
doc, tempfilename_in.c_str(), false, false, false);
651
file_listener fileout;
652
execute(command, params, tempfilename_in, fileout);
654
std::string lfilename = Glib::filename_from_utf8(filenameArg);
655
fileout.toFile(lfilename);
657
// make sure we don't leak file descriptors from g_file_open_tmp
659
// FIXME: convert to utf8 (from "filename encoding") and unlink_utf8name
660
unlink(tempfilename_in.c_str());
669
\brief This function uses an extention as a effect on a document.
670
\param module Extention to effect with.
671
\param doc Document to run through the effect.
673
This function is a little bit trickier than the previous two. It
674
needs two temporary files to get it's work done. Both of these
675
files have random names created for them using the g_file_open_temp function
676
with the ink_ext_ prefix in the temporary directory. Like the other
677
functions, the temporary files are deleted at the end.
679
To save/load the two temporary documents (both are SVG) the internal
680
modules for SVG load and save are used. They are both used through
681
the module system function by passing their keys into the functions.
683
The command itself is built a little bit differently than in other
684
functions because the effect support selections. So on the command
685
line a list of all the ids that are selected is included. Currently,
686
this only works for a single selected object, but there will be more.
687
The command string is filled with the data, and then after the execution
690
The execute function is used at the core of this function
691
to execute the Script on the two SVG documents (actually only one
692
exists at the time, the other is created by that script). At that
693
point both should be full, and the second one is loaded.
696
Script::effect(Inkscape::Extension::Effect *module,
697
Inkscape::UI::View::View *doc,
698
ImplementationDocumentCache * docCache)
700
if (docCache == NULL) {
701
docCache = newDocCache(module, doc);
703
ScriptDocCache * dc = dynamic_cast<ScriptDocCache *>(docCache);
705
printf("TOO BAD TO LIVE!!!");
709
SPDesktop *desktop = (SPDesktop *)doc;
710
sp_namedview_document_from_window(desktop);
712
gchar * orig_output_extension = g_strdup(sp_document_repr_root(desktop->doc())->attribute("inkscape:output_extension"));
714
std::list<std::string> params;
715
module->paramListString(params);
717
if (module->no_doc) {
718
// this is a no-doc extension, e.g. a Help menu command;
719
// just run the command without any files, ignoring errors
722
file_listener outfile;
723
execute(command, params, empty, outfile);
728
std::string tempfilename_out;
731
tempfd_out = Inkscape::IO::file_open_tmp(tempfilename_out, "ink_ext_XXXXXX.svg");
733
/// \todo Popup dialog here
737
if (desktop != NULL) {
738
Inkscape::Util::GSListConstIterator<SPItem *> selected =
739
sp_desktop_selection(desktop)->itemList();
740
while ( selected != NULL ) {
741
Glib::ustring selected_id;
742
selected_id += "--id=";
743
selected_id += SP_OBJECT_ID(*selected);
744
params.insert(params.begin(), selected_id);
749
file_listener fileout;
750
int data_read = execute(command, params, dc->_filename, fileout);
751
fileout.toFile(tempfilename_out);
755
SPDocument * mydoc = NULL;
756
if (data_read > 10) {
757
mydoc = Inkscape::Extension::open(
758
Inkscape::Extension::db.get(SP_MODULE_KEY_INPUT_SVG),
759
tempfilename_out.c_str());
764
// make sure we don't leak file descriptors from g_file_open_tmp
767
// FIXME: convert to utf8 (from "filename encoding") and unlink_utf8name
768
unlink(tempfilename_out.c_str());
770
/* Do something with mydoc.... */
772
doc->doc()->emitReconstructionStart();
773
copy_doc(doc->doc()->rroot, mydoc->rroot);
774
doc->doc()->emitReconstructionFinish();
776
sp_namedview_update_layers_from_document(desktop);
778
sp_document_repr_root(desktop->doc())->setAttribute("inkscape:output_extension", orig_output_extension);
780
g_free(orig_output_extension);
788
\brief A function to take all the svg elements from one document
789
and put them in another.
790
\param oldroot The root node of the document to be replaced
791
\param newroot The root node of the document to replace it with
793
This function first deletes all of the data in the old document. It
794
does this by creating a list of what needs to be deleted, and then
795
goes through the list. This two pass approach removes issues with
796
the list being change while parsing through it. Lots of nasty bugs.
798
Then, it goes through the new document, duplicating all of the
799
elements and putting them into the old document. The copy
803
Script::copy_doc (Inkscape::XML::Node * oldroot, Inkscape::XML::Node * newroot)
805
std::vector<Inkscape::XML::Node *> delete_list;
806
Inkscape::XML::Node * oldroot_namedview = NULL;
808
for (Inkscape::XML::Node * child = oldroot->firstChild();
810
child = child->next()) {
811
if (!strcmp("sodipodi:namedview", child->name())) {
812
oldroot_namedview = child;
813
for (Inkscape::XML::Node * oldroot_namedview_child = child->firstChild();
814
oldroot_namedview_child != NULL;
815
oldroot_namedview_child = oldroot_namedview_child->next()) {
816
delete_list.push_back(oldroot_namedview_child);
819
delete_list.push_back(child);
822
for (unsigned int i = 0; i < delete_list.size(); i++)
823
sp_repr_unparent(delete_list[i]);
825
for (Inkscape::XML::Node * child = newroot->firstChild();
827
child = child->next()) {
828
if (!strcmp("sodipodi:namedview", child->name())) {
829
if (oldroot_namedview != NULL) {
830
for (Inkscape::XML::Node * newroot_namedview_child = child->firstChild();
831
newroot_namedview_child != NULL;
832
newroot_namedview_child = newroot_namedview_child->next()) {
833
oldroot_namedview->appendChild(newroot_namedview_child->duplicate(oldroot->document()));
837
oldroot->appendChild(child->duplicate(oldroot->document()));
842
using Inkscape::Util::List;
843
using Inkscape::XML::AttributeRecord;
844
std::vector<gchar const *> attribs;
846
// Make a list of all attributes of the old root node.
847
for (List<AttributeRecord const> iter = oldroot->attributeList(); iter; ++iter) {
848
attribs.push_back(g_quark_to_string(iter->key));
851
// Delete the attributes of the old root nodes.
852
for (std::vector<gchar const *>::const_iterator it = attribs.begin(); it != attribs.end(); it++)
853
oldroot->setAttribute(*it, NULL);
855
// Set the new attributes.
856
for (List<AttributeRecord const> iter = newroot->attributeList(); iter; ++iter) {
857
gchar const *name = g_quark_to_string(iter->key);
858
oldroot->setAttribute(name, newroot->attribute(name));
862
/** \todo Restore correct layer */
863
/** \todo Restore correct selection */
866
/** \brief This function checks the stderr file, and if it has data,
867
shows it in a warning dialog to the user
868
\param filename Filename of the stderr file
871
Script::checkStderr (const Glib::ustring &data,
872
Gtk::MessageType type,
873
const Glib::ustring &message)
875
Gtk::MessageDialog warning(message, false, type, Gtk::BUTTONS_OK, true);
876
warning.set_resizable(true);
877
GtkWidget *dlg = GTK_WIDGET(warning.gobj());
878
sp_transientize(dlg);
880
Gtk::VBox * vbox = warning.get_vbox();
882
/* Gtk::TextView * textview = new Gtk::TextView(Gtk::TextBuffer::create()); */
883
Gtk::TextView * textview = new Gtk::TextView();
884
textview->set_editable(false);
885
textview->set_wrap_mode(Gtk::WRAP_WORD);
888
textview->get_buffer()->set_text(data.c_str());
890
Gtk::ScrolledWindow * scrollwindow = new Gtk::ScrolledWindow();
891
scrollwindow->add(*textview);
892
scrollwindow->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
893
scrollwindow->set_shadow_type(Gtk::SHADOW_IN);
894
scrollwindow->show();
896
vbox->pack_start(*scrollwindow, true, true, 5 /* fix these */);
904
Script::cancelProcessing (void) {
907
Glib::spawn_close_pid(_pid);
913
/** \brief This is the core of the extension file as it actually does
914
the execution of the extension.
915
\param in_command The command to be executed
916
\param filein Filename coming in
917
\param fileout Filename of the out file
918
\return Number of bytes that were read into the output file.
920
The first thing that this function does is build the command to be
921
executed. This consists of the first string (in_command) and then
922
the filename for input (filein). This file is put on the command
925
The next thing is that this function does is open a pipe to the
926
command and get the file handle in the ppipe variable. It then
927
opens the output file with the output file handle. Both of these
928
operations are checked extensively for errors.
930
After both are opened, then the data is copied from the output
931
of the pipe into the file out using fread and fwrite. These two
932
functions are used because of their primitive nature they make
933
no assumptions about the data. A buffer is used in the transfer,
934
but the output of fread is stored so the exact number of bytes
935
is handled gracefully.
937
At the very end (after the data has been copied) both of the files
938
are closed, and we return to what we were doing.
941
Script::execute (const std::list<std::string> &in_command,
942
const std::list<std::string> &in_params,
943
const Glib::ustring &filein,
944
file_listener &fileout)
946
g_return_val_if_fail(in_command.size() > 0, 0);
947
// printf("Executing\n");
949
std::vector <std::string> argv;
952
for (std::list<std::string>::const_iterator i = in_command.begin();
953
i != in_command.end(); i++) {
957
// according to http://www.gtk.org/api/2.6/glib/glib-Spawning-Processes.html spawn quotes parameter containing spaces
958
// we tokenize so that spwan does not need to quote over all params
959
for (std::list<std::string>::const_iterator i = in_command.begin();
960
i != in_command.end(); i++) {
961
std::string param_str = *i;
963
//g_message("param: %s", param_str.c_str());
964
size_t first_space = param_str.find_first_of(' ');
965
size_t first_quote = param_str.find_first_of('"');
966
//std::cout << "first space " << first_space << std::endl;
967
//std::cout << "first quote " << first_quote << std::endl;
969
if((first_quote != std::string::npos) && (first_quote == 0)) {
970
size_t next_quote = param_str.find_first_of('"', first_quote + 1);
971
//std::cout << "next quote " << next_quote << std::endl;
973
if(next_quote != std::string::npos) {
974
//std::cout << "now split " << next_quote << std::endl;
975
//std::cout << "now split " << param_str.substr(1, next_quote - 1) << std::endl;
976
//std::cout << "now split " << param_str.substr(next_quote + 1) << std::endl;
977
std::string part_str = param_str.substr(1, next_quote - 1);
978
if(part_str.size() > 0)
979
argv.push_back(part_str);
980
param_str = param_str.substr(next_quote + 1);
984
if(param_str.size() > 0)
985
argv.push_back(param_str);
990
else if(first_space != std::string::npos) {
991
//std::cout << "now split " << first_space << std::endl;
992
//std::cout << "now split " << param_str.substr(0, first_space) << std::endl;
993
//std::cout << "now split " << param_str.substr(first_space + 1) << std::endl;
994
std::string part_str = param_str.substr(0, first_space);
995
if(part_str.size() > 0)
996
argv.push_back(part_str);
997
param_str = param_str.substr(first_space + 1);
1000
if(param_str.size() > 0)
1001
argv.push_back(param_str);
1004
} while(param_str.size() > 0);
1007
for (std::list<std::string>::const_iterator i = in_params.begin();
1008
i != in_params.end(); i++) {
1009
//g_message("Script parameter: %s",(*i)g.c_str());
1013
if (!(filein.empty())) {
1014
argv.push_back(filein);
1017
int stdout_pipe, stderr_pipe;
1020
Inkscape::IO::spawn_async_with_pipes(Glib::get_current_dir(), // working directory
1022
Glib::SPAWN_SEARCH_PATH /*| Glib::SPAWN_DO_NOT_REAP_CHILD*/,
1026
&stdout_pipe, // STDOUT
1027
&stderr_pipe); // STDERR
1028
} catch (Glib::SpawnError e) {
1029
printf("Can't Spawn!!! spawn returns: %d\n", e.code());
1033
_main_loop = Glib::MainLoop::create(false);
1035
file_listener fileerr;
1036
fileout.init(stdout_pipe, _main_loop);
1037
fileerr.init(stderr_pipe, _main_loop);
1042
// Ensure all the data is out of the pipe
1043
while (!fileout.isDead())
1044
fileout.read(Glib::IO_IN);
1045
while (!fileerr.isDead())
1046
fileerr.read(Glib::IO_IN);
1049
// std::cout << "Script Canceled" << std::endl;
1053
Glib::ustring stderr_data = fileerr.string();
1054
if (stderr_data.length() != 0 &&
1055
Inkscape::NSApplication::Application::getUseGui()
1057
checkStderr(stderr_data, Gtk::MESSAGE_INFO,
1058
_("Inkscape has received additional data from the script executed. "
1059
"The script did not return an error, but this may indicate the results will not be as expected."));
1062
Glib::ustring stdout_data = fileout.string();
1063
if (stdout_data.length() == 0) {
1067
// std::cout << "Finishing Execution." << std::endl;
1068
return stdout_data.length();
1074
} // namespace Implementation
1075
} // namespace Extension
1076
} // namespace Inkscape
1081
c-file-style:"stroustrup"
1082
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1083
indent-tabs-mode:nil
1087
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :