50
52
gint end; /* -1 for end of the file */
51
53
const gchar *formatstring; /* the command from the configuration, so including placeholders such as %i, %f, |, etc. */
52
54
gchar *commandstring; /* the command that will be started by g_spawn, the placeholders should have been replaced/removed */
55
CustomCommandCallback customcommand_cb;
54
gchar *securedir; /* if we need any local temporary files for input or output we'll use fifo's */
55
gchar *fifo_in; /* the path for the iput and output fifo */
57
gchar *securedir; /* if we need any local temporary files for input or output */
57
58
gchar *tmp_in; /* the path for the input/output temporary filename */
59
60
gchar *inplace; /* if we use in-place editing, so the input file will become the output file */
60
61
gboolean pipe_in; /* if we use pipes for input and output */
64
gpointer fifo_in_handle; /* the path for 'named pipes' on win32 */
65
gpointer fifo_out_handle;
68
64
gboolean include_stderr; /* if stderr should be included in the output */
70
66
gint standard_input; /* the pipes that will be filled by g_spawn_async_with_pipes */
232
208
ep->channel_in = g_io_channel_unix_new(ep->standard_input);
234
} else if (ep->fifo_in) {
235
DEBUG_MSG("start_command_idle, connecting channel_in to fifo %s\n",ep->fifo_in);
236
/* problem: this can hang if there is no process actually reading from this fifo... so if the
237
command died in some way (a nonexisting command), this call will hang bluefish */
238
ep->channel_in = g_io_channel_new_file(ep->fifo_in,"w",&gerror);
240
DEBUG_MSG("start_command_idle, error connecting to fifo %s: %s\n",ep->fifo_in,gerror->message);
241
g_warning("failed to create fifo %s %d: %s\n",ep->fifo_in, gerror->code, gerror->message);
242
g_error_free(gerror);
243
/* BUG TODO: free Texternalp */
247
if (ep->pipe_in || ep->fifo_in) {
249
213
ep->buffer_out = ep->buffer_out_position = doc_get_chars(ep->bfwin->current_document,ep->begin,ep->end);
250
214
g_io_channel_set_flags(ep->channel_in,G_IO_FLAG_NONBLOCK,NULL);
259
223
ep->channel_out = g_io_channel_unix_new(ep->standard_output);
261
225
DEBUG_MSG("start_command_idle, created channel_out from pipe\n");
262
} else if (ep->fifo_out) {
263
ep->channel_out = g_io_channel_new_file(ep->fifo_out,"r",&gerror);
264
DEBUG_MSG("start_command_idle, created channel_out from fifo %s\n",ep->fifo_out);
266
g_warning("failed to start reading from file %s %d: %s\n",ep->fifo_out, gerror->code, gerror->message);
267
g_error_free(gerror);
268
/* BUG TODO: free Texternalp */
272
if (ep->channel_out_lcb && (ep->pipe_out || ep->fifo_out)) {
227
if (ep->channel_out_lcb && ep->pipe_out) {
274
229
g_io_channel_set_flags(ep->channel_out,G_IO_FLAG_NONBLOCK,NULL);
275
230
DEBUG_MSG("start_command_idle, add watch for channel_out\n");
301
255
g_shell_parse_argv(ep->commandstring, NULL, &argv, NULL);
303
257
DEBUG_MSG("start_command_backend,commandstring=%s\n",ep->commandstring);
305
258
ep->include_stderr = FALSE;
307
ep->fifo_in = g_strdup("\\\\.\\pipe\\bluefish_in");
308
if ((ep->fifo_in_handle = CreateNamedPipe(ep->fifo_in, PIPE_ACCESS_INBOUND, PIPE_TYPE_BYTE | PIPE_NOWAIT,
309
PIPE_UNLIMITED_INSTANCES, 2048, 2048, 100, NULL)) == INVALID_HANDLE_VALUE) {
310
g_print("some error happened creating fifo %s??\n", ep->fifo_in);
315
ep->fifo_out = g_strdup("\\\\.\\pipe\\bluefish_out");
316
if ((ep->fifo_out_handle = CreateNamedPipe(ep->fifo_out, PIPE_ACCESS_OUTBOUND, PIPE_TYPE_BYTE | PIPE_NOWAIT,
317
PIPE_UNLIMITED_INSTANCES, 2048, 2048, 100, NULL)) == INVALID_HANDLE_VALUE) {
318
g_print("some error happened creating fifo %s??\n", ep->fifo_out);
324
if (mkfifo(ep->fifo_in, 0600) != 0) {
325
DEBUG_MSG("some error happened creating fifo %s??\n",ep->fifo_in);
328
DEBUG_MSG("start_command_backend, created fifo %s\n",ep->fifo_in);
331
if (mkfifo(ep->fifo_out, 0600) != 0) {
332
DEBUG_MSG("some error happened creating fifo %s??\n",ep->fifo_out);
337
DEBUG_MSG("start_command_backend, pipe_in=%d, pipe_out=%d, fifo_in=%s, fifo_out=%s,include_stderr=%d\n",ep->pipe_in,ep->pipe_out,ep->fifo_in,ep->fifo_out,ep->include_stderr);
259
DEBUG_MSG("start_command_backend, pipe_in=%d, pipe_out=%d, include_stderr=%d\n",ep->pipe_in,ep->pipe_out,ep->include_stderr);
338
260
DEBUG_MSG("start_command_backend, about to spawn process /bin/sh -c %s\n",argv[2]);
339
261
g_spawn_async_with_pipes(NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH, (ep->include_stderr)?spawn_setup_lcb:NULL, ep, &ep->child_pid,
340
262
(ep->pipe_in) ? &ep->standard_input : NULL,
385
307
/* The format string should have new options:
386
* %flocal full path (function should abort for remote files)
308
* %f local full path (function should abort for remote files)
387
309
* %c local directory of file (function should abort for remote files)
388
310
* %n filename without path
390
312
* %p preview URL if basedir and preview dir are set in project settings, else identical to %u
391
* %i temporary fifo for input, if the document is not modified and local equal to %f
392
* %o temporary fifo for output of filters or outputbox
393
* %I temporary filename for input (fifo is faster), if the document is not modified and local equal to %f
394
* %O temporary filename for output of filters or outputbox (fifo is faster) (previously %f)
313
* %i temporary filename for input (fifo is faster), if the document is not modified and local equal to %f
314
* %o temporary filename for output of filters or outputbox (fifo is faster) (previously %f)
395
315
* %t temporary filename for both input and output (for in-place-editing filters)
316
* %a user supplied arguments
397
318
static gchar *create_commandstring(Texternalp *ep, const gchar *formatstr, gboolean discard_output) {
398
319
Tconvert_table *table;
399
320
gchar *localname=NULL, *localfilename=NULL, *retstring, *curi=NULL;
321
gchar *formatstring, *user_argument=NULL;
401
322
gint formatstringlen;
402
323
gboolean is_local_non_modified;
403
324
gboolean need_local = FALSE,
446
366
if (need_local && !localname) {
447
367
g_free(formatstring);
448
368
g_free(localname);
453
372
need_tmpin = (strstr(formatstring, "%I") != NULL);
454
373
/* %f is for backwards compatibility with bluefish 1.0 */
455
374
need_tmpout = (strstr(formatstring, "%O") != NULL);
456
need_fifoin = (strstr(formatstring, "%i") != NULL);
457
need_fifoout = (strstr(formatstring, "%o") != NULL);
458
375
need_inplace = (strstr(formatstring, "%t") != NULL);
460
if ((need_tmpout || need_fifoout || need_inplace || need_pipeout) && discard_output) {
377
if ((need_tmpout || need_inplace || need_pipeout) && discard_output) {
461
378
DEBUG_MSG("create_commandstring, external_commands should not have %%o\n");
462
/* BUG: give a warning that external commands should not use %o */
463
379
g_free(formatstring);
464
380
g_free(localname);
468
if ((need_tmpin && (need_fifoin || need_inplace || need_pipein))
469
|| (need_fifoin && (need_inplace || need_pipein))
383
if ((need_tmpin && (need_inplace || need_pipein))
470
384
|| (need_inplace && need_pipein)) {
471
385
DEBUG_MSG("create_commandstring, cannot have multiple inputs\n");
472
386
/* BUG: give a warning that you cannot have multiple inputs */
473
387
g_free(formatstring);
474
388
g_free(localname);
478
if ((need_tmpout && (need_fifoout || need_inplace || need_pipeout))
479
|| (need_fifoout && (need_inplace || need_pipeout))
391
if ((need_tmpout && (need_inplace || need_pipeout))
480
392
|| (need_inplace && need_pipeout)) {
481
DEBUG_MSG("create_commandstring, cannot have multiple outputs\n");
393
DEBUG_MSG("create_commandstring, cannot have multiple outputs, tmpout=%d, pipeout=%d, inplace=%d\n",need_tmpout,need_pipeout,need_inplace);
482
394
/* BUG: give a warning that you cannot have multiple outputs */
483
395
g_free(formatstring);
484
396
g_free(localname);
401
if (need_arguments) {
402
GtkWidget *dialog, *entry;
405
dialog = gtk_dialog_new_with_buttons(_("Supply extra arguments"),
406
GTK_WINDOW(ep->bfwin->main_window),
407
GTK_DIALOG_DESTROY_WITH_PARENT,
408
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
409
GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL);
410
tmp = g_strdup_printf(_("Supply arguments to define %%a in '%s'"), formatstring);
411
entry = dialog_entry_labeled(NULL, tmp, gtk_dialog_get_content_area(GTK_DIALOG(dialog)), 6);
413
gtk_widget_show_all(dialog);
414
result = gtk_dialog_run(GTK_DIALOG (dialog));
416
case GTK_RESPONSE_ACCEPT:
417
user_argument = gtk_editable_get_chars(GTK_EDITABLE(entry), 0, -1);
418
if (!user_argument || user_argument[0]=='\0') {
419
need_arguments = FALSE;
423
gtk_widget_destroy(dialog);
427
gtk_widget_destroy(dialog);
488
431
if (need_pipein) ep->pipe_in = TRUE;
489
432
if (need_pipeout) ep->pipe_out = TRUE;
490
/* if (!need_tmpin && !need_fifoin && !need_inplace && !need_filename && !need_preview_uri) {
493
if (!discard_output && !need_tmpout && !need_fifoout && !need_inplace) {
496
433
DEBUG_MSG("create_commandstring, formatstring '%s' seems OK\n",formatstring);
498
435
is_local_non_modified = (ep->bfwin->current_document->uri
552
488
table[cur].my_char = g_strdup(ep->tmp_in);
555
} else if (need_fifoin) {
556
table[cur].my_int = 'i';
557
if (is_local_non_modified) {
558
table[cur].my_char = g_strdup(localname);;
560
ep->fifo_in = create_secure_dir_return_filename();
561
table[cur].my_char = g_strdup(ep->fifo_in);
564
DEBUG_MSG("create_commandstring, %%i will be at %s\n",table[cur].my_char);
566
491
} else if (need_inplace) {
567
492
table[cur].my_int = 't';
568
493
ep->inplace = create_secure_dir_return_filename();
664
static gboolean filter_io_watch_lcb(GIOChannel *channel,GIOCondition condition,gpointer data) {
589
static gboolean filter_custom_io_watch_lcb(GIOChannel *channel,GIOCondition condition,gpointer data) {
665
590
Texternalp *ep = data;
666
DEBUG_MSG("filter_io_watch_lcb, started with condition=%d\n",condition);
591
DEBUG_MSG("filter_custom_io_watch_lcb, started with condition=%d\n",condition);
667
592
if (condition & G_IO_IN) {
668
593
gchar *str_return;
673
598
status = g_io_channel_read_to_end(channel,&str_return,&length,&gerror);
675
g_warning("error while trying to read data for outputbox, %d: %s\n",gerror->code,gerror->message);
600
g_warning("error while trying to read data for filter or custom command, %d: %s\n",gerror->code,gerror->message);
676
601
g_error_free(gerror);
679
604
if (status == G_IO_STATUS_NORMAL && str_return) {
680
605
gint end=ep->end;
681
606
GError *error=NULL;
682
DEBUG_MSG("filter_io_watch_lcb, received '%s'\n",str_return);
683
if (ep->bfwin->current_document) {
607
if (ep->customcommand_cb) {
608
ep->customcommand_cb(str_return, ep->bfwin);
611
GtkTextBuffer *buffer = ep->bfwin->current_document->buffer;
612
DEBUG_MSG("filter_custom_io_watch_lcb, received '%s'\n",str_return);
613
gint line=-1,offset=-1;
684
614
if (ep->end == -1) {
685
end = gtk_text_buffer_get_char_count(ep->bfwin->current_document->buffer);
615
end = gtk_text_buffer_get_char_count(buffer);
617
if (!gtk_text_buffer_get_has_selection(buffer)) {
618
gtk_text_buffer_get_iter_at_mark(buffer, &iter,gtk_text_buffer_get_insert(buffer));
619
line = gtk_text_iter_get_line(&iter);
620
offset = gtk_text_iter_get_line_offset(&iter);
687
622
doc_replace_text(ep->bfwin->current_document, str_return, ep->begin, end);
624
gtk_text_buffer_get_iter_at_line_offset(buffer, &iter, line, offset);
625
gtk_text_buffer_place_cursor(buffer, &iter);
689
628
g_io_channel_shutdown(channel,TRUE,&error);
690
629
externalp_unref(ep);
691
630
g_free(str_return);
694
DEBUG_MSG("filter_io_watch_lcb, status=%d\n",status);
633
DEBUG_MSG("filter_custom_io_watch_lcb, status=%d\n",status);
696
635
if (str_return) g_free(str_return);
753
693
ep->include_stderr = FALSE;
754
694
ep->channel_out_lcb = NULL;
755
695
ep->channel_out_data = NULL;
696
} else if (commandmode == mode_custom) {
697
ep->include_stderr = FALSE;
698
ep->customcommand_cb = customcommand_cb;
699
ep->channel_out_lcb = filter_custom_io_watch_lcb;
700
ep->channel_out_data = ep;
758
703
start_command(ep);
761
706
void outputbox_command(Tbfwin *bfwin, const gchar *formatstring) {
762
command_backend(bfwin, 0, -1,formatstring, mode_outputbox);
707
command_backend(bfwin, 0, -1,formatstring, mode_outputbox, NULL);
766
711
void filter_command(Tbfwin *bfwin, const gchar *formatstring, gint begin, gint end) {
767
command_backend(bfwin, begin, end,formatstring, mode_filter);
712
command_backend(bfwin, begin, end,formatstring, mode_filter, NULL);
770
715
void external_command(Tbfwin *bfwin, const gchar *formatstring) {
771
command_backend(bfwin, 0, -1,formatstring, mode_command);
716
command_backend(bfwin, 0, -1,formatstring, mode_command, NULL);
720
custom_command(Tbfwin *bfwin, const gchar *formatstring, CustomCommandCallback func)
722
command_backend(bfwin, 0, -1,formatstring, mode_custom, func);