use warnings; use strict; =head1 NAME BarnOwl::Module::ShellFilter =head1 DESCRIPTION filter text through a shell command =cut package BarnOwl::Module::ShellFilter; use POSIX; use BarnOwl::Editwin qw(move_to_line_start move_to_line_end move_to_buffer_start move_to_buffer_end replace_region delete_prev_char set_mark get_region); use IPC::Open2; our $VERSION = 0.2; sub shell_filter { shift; # warning leftover from Digraphs: # There exist things that, if you do them inside save_excursion, cause a segfault? move_to_buffer_start(); set_mark(); move_to_buffer_end(); my $input_text = get_region(); # psychotic haxx from random corners of Google to try to make sure shell # commands that hang don't bring BarnOwl down with them: # http://www.perlmonks.org/?node_id=309205 my $output_text; my $diestr; eval { local $SIG{ALRM} = sub { die "timed out" }; alarm(8); # time out in 8 seconds my $pid = open2(my $child_out, my $child_in, @_); print $child_in $input_text; close $child_in; # weird idiom to read all output: $output_text = do { local $/ = undef; <$child_out> }; close $child_out; waitpid( $pid, 0 ); my $child_exit_status = $? >> 8; die "exited with status $child_exit_status" if $child_exit_status; $diestr = $@ if $@; # string from dying alarm(0); }; $diestr = $@ if $@; # string from dying alarm(0); if (!defined($diestr) && defined($output_text)) { replace_region($output_text); } else { BarnOwl::message("shell-filter error: $diestr"); } } BarnOwl::new_command('shell-filter' => \&shell_filter, { summary => "Filter text through a shell command", usage => "shell-filter CMD", description => "Filter text through a shell command", }); 1;