Thank you all for your input.
Many stated that ctrl-Z + newline would get the job done. I was unaware of this, and it does indeed work, so thanks for this tip.
My original goal was to get a single control character to break input without killing the script. In pursuit of that obscure goal, here's what I've since discovered:
1. Accessing SetConsoleCtrlHandler via Win32::API sounds promising, but causes an unhandled exception when a Ctrl-C is generated. Did I do something wrong?
#!perl
use strict;
use Win32::API;
use Win32::API::Callback;
use constant CTRL_C_EVENT => 0;
use constant CTRL_BREAK_EVENT => 1;
use constant CTRL_CLOSE_EVENT => 2;
use constant CTRL_LOGOFF_EVENT => 5;
use constant CTRL_SHUTDOWN_EVENT => 6;
######################################################################
+#
# BOOL WINAPI HandlerRoutine( __in DWORD dwCtrlType );
my $cbfn = Win32::API::Callback->new( sub { my $type = shift; return 0
+; }, 'L', 'L' );
######################################################################
+#
# BOOL WINAPI SetConsoleCtrlHandler( __in_opt PHANDLER_ROUTINE Handle
+rRoutine, __in BOOL Add);
my $fn1 = new Win32::API('kernel32', 'SetConsoleCtrlHandler', 'KL', 'L
+');
die "Can't get function handle" unless ($fn1);
# The following line of code complains that PHANDLER_ROUTINE is an unk
+nown type. Boo. Hiss.
#my $fn = new Win32::API('kernel32', 'BOOL SetConsoleCtrlHandler(PHAND
+LER_ROUTINE HandlerRoutine, BOOL Add)');
#die "Can't get function handle" unless ($fn);
my $fn2 = new Win32::API('kernel32', 'SetConsoleCtrlHandler', 'LL', 'L
+');
die "Can't get function handle" unless ($fn2);
######################################################################
+#
# BOOL WINAPI GenerateConsoleCtrlEvent(DWORD dwCtrlEvent, DWORD dwProc
+essGroupId);
my $fn3 = new Win32::API('kernel32', 'BOOL GenerateConsoleCtrlEvent(DW
+ORD dwCtrlEvent, DWORD dwProcessGroupId)');
die "Can't get function handle" unless ($fn3);
print "Registering the callback function...\n";
die "Bad function call return value"
unless $fn1->Call($cbfn, 1);
# Generate a CTRL-C event that can be captured
print "Generating a CTRL-C event...\n";
$fn3->Call(CTRL_C_EVENT, 0);
print "Resetting the callback handler...\n";
my $return = $fn2->Call(0, 0);
print "Done!\n";
2. I've decided, whether it was intended to be this way or not, that setting $SIG{INT} is a lot more useful for a spawned thread than it is for the main thread. Check this out:
#!perl -w
use strict;
print "Enter CTRL-C to end input\n";
my $lines = get_lines();
print "Enter CTRL-C to exit\n";
while ( 1 )
{
local($") = ', ';
print "You entered: @$lines\n";
sleep(1);
}
sub get_lines
{
use threads;
local($SIG{INT}) = 'IGNORE';
$lines = threads->create( sub{ my @rv = <STDIN>; chomp @rv; return
+\@rv } )->join();
}
Now, I have a three-line routine that will let me pipe data into it (like 'type file.txt | perl myscript.pl'), or get input from the command line (like 'perl myscript.pl'), and in the latter case the sensible ctrl-C works like the average UNIX person expects. (Yeah, it could be a
two-line script if I move the 'use threads' line to the top of the file...)
I have something that works, so I'm a happy camper.
Now, back to my original question: are signal handlers
supposed to work this way? Why couldn't I get it to work like this in the main thread, and why does it work like I expect only in a spawned thread?