如何以跨平台的方式可选地使用Win32 :: Console及其常量?

时间:2012-02-02 23:11:28

标签: perl cross-platform

首先,我正在使用Perl v5.8.4,我无法升级Perl或安装Term::ReadKeyIO::Prompt(或者除了Core之外的任何东西),所以请在回答/评论时考虑到这一点。

我正在尝试编写一个完全自包含的Perl脚本(其中包括)提示输入密码。它需要在Windows,AIX和Solaris之间进行跨平台兼容。我不希望它在键入时回显密码。这就是我所拥有的:

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;
}

这在所有平台上完全正常(假设我不use strict),但是,Win32块中使用的4个常量会在Unix上针对strict subs抛出错误:

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.

我不能为我的生活弄清楚如何使Windows和Unix对这4个常量感到满意。如果我尝试在仅Unix块中定义它们,Windows编译器会告诉我我正在重新定义它们。

我能解决这个问题吗?或者也许以另一种方式做到这一点?在此先感谢您的帮助。

2 个答案:

答案 0 :(得分:4)

您必须使用parens对未声明的子例程进行子例程调用。所以要么通过改变

来添加parens
STD_INPUT_HANDLE
ENABLE_LINE_INPUT
...

STD_INPUT_HANDLE()
ENABLE_LINE_INPUT()
...

或声明子程序,当它们不会被Win32 :: Console声明时通过更改

    if ($^O eq 'MSWin32') {
        require Win32::Console; 
        Win32::Console->import();
    }

    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__
    }

更简洁的方法是将特定于操作系统的代码移动到单独的模块中。

BEGIN {
    my $mod = $^O eq 'MSWin32' ? 'My::IO::Win32' : 'My::IO::Default';
    eval "require $mod" or die $@;
    $mod->import(qw( get_password ));
}

答案 1 :(得分:0)

您可以将get_password的Unix和Win32版本分别放在两个单独的模块中,例如My::Input::UnixMy::Input::Win32,然后require取决于{{1}}平台。因此,甚至不能在Unix机器上编译Win32版本,避免使用未定义的常量等。

相关问题