问题
To start with, I'm working Perl v5.8.4 and I DO NOT have the ability to upgrade Perl or install Term::ReadKey
or IO::Prompt
(or really anything outside of what is in Core), so please take that into consideration when answering/commenting.
I'm trying to write a completely self contained Perl script that (among other things) prompts for a password. It needs to be cross platform compatible between Windows, AIX, and Solaris. I don't want it to echo the password as it is typed. Here's what I have:
BEGIN {
if ($^O eq 'MSWin32') {
require Win32::Console;
Win32::Console->import();
}
}
sub get_password {
print "Enter password: ";
my $pass = '';
# Change terminal settings to not display password
if ($os eq 'MSWin32') {
my $stdin = new Win32::Console STD_INPUT_HANDLE;
my $orig_mode = $stdin->Mode();
$stdin->Mode(ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT | +ENABLE_MOUSE_INPUT);
chomp($pass = <STDIN>);
$stdin->Mode($orig_mode);
}
else {
system('stty', '-echo');
chomp($password = <STDIN>);
system('stty', 'echo');
}
print "\n";
return $pass;
}
This works perfectly fine on all platforms (assuming I don't use strict
), however, the 4 constants used in the Win32 block throw errors against strict subs
on Unix:
Bareword "STD_INPUT_HANDLE" not allowed while "strict subs" in use at script.pl line 488.
Bareword "ENABLE_LINE_INPUT" not allowed while "strict subs" in use at script.pl line 490.
Bareword "ENABLE_PROCESSED_INPUT" not allowed while "strict subs" in use at script.pl line 490.
Bareword "ENABLE_MOUSE_INPUT" not allowed while "strict subs" in use at script.pl line 490.
I can't for the life of me figure out how to make both Windows and Unix be happy with those 4 constants. If I try to define them in a Unix only block, the Windows compiler tells me that I'm redefining them.
Can I fix this? Or perhaps do it in another way? Thanks in advance for the help.
回答1:
You must use parens for subroutine calls to subroutines you haven't declared. So either add parens by changing
STD_INPUT_HANDLE
ENABLE_LINE_INPUT
...
to
STD_INPUT_HANDLE()
ENABLE_LINE_INPUT()
...
or declare the subroutines when they wouldn't be declared by Win32::Console by changing
if ($^O eq 'MSWin32') {
require Win32::Console;
Win32::Console->import();
}
to
if ($^O eq 'MSWin32') {
require Win32::Console;
Win32::Console->import();
} else {
eval <<'__EOI__'.';1' or die $@;
sub STD_INPUT_HANDLE { die }
sub ENABLE_LINE_INPUT { die }
...
__EOI__
}
A cleaner approach would be to move the OS-specific code into separate modules.
BEGIN {
my $mod = $^O eq 'MSWin32' ? 'My::IO::Win32' : 'My::IO::Default';
eval "require $mod" or die $@;
$mod->import(qw( get_password ));
}
回答2:
You can put the Unix and Win32 versions of get_password
in two separate modules, say, My::Input::Unix
and My::Input::Win32
, respectively, and then require
the appropriate one depending on platform. Therefore, the Win32 version would not even be compiled on a Unix machine, avoiding the undefined constants etc.
来源:https://stackoverflow.com/questions/9121421/how-can-i-optionally-use-win32console-and-its-constants-in-a-cross-platform-wa