The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#!/usr/bin/perl --
# 

use strict;
use warnings "all";
use Getopt::Std;
use Pod::Usage;
use List::Util qw(first);
use Data::SimplePassword;

# getopts
Getopt::Std::getopts 'ht:n:eu' => my $opt = {};

# help
&usage if defined $opt->{h};

# exclusive check
if( defined $opt->{n} and defined $opt->{e} ){
    printf STDERR "notice: -n and -e options are exclusive.\n";
    exit 1;
}

# length
my $n = 8;
if( defined $opt->{n} ){
    $opt->{n} =~ /^\d+$/o
	? $n = $opt->{n}
	: &usage;
}
elsif( scalar @ARGV == 1 ){
    $ARGV[0] =~ /^\d+$/o
	? $n = shift @ARGV
	: &usage;
}

# type
my $chars = {
    default => [ 0..9, 'a'..'z', 'A'..'Z' ],
    ascii => [ map { sprintf "%c", $_ } 33 .. 126 ],
    base64 => [ 0..9, 'a'..'z', 'A'..'Z', qw(+ /) ],
    b64 => [ 0..9, 'a'..'z', 'A'..'Z', qw(+ /) ],
    simple => [ 0..9, 'a'..'z' ],
    digit => [ 0..9 ],
    binary => [ 0, 1 ],
    morse => [ qw(. -) ],
};

my $type = $opt->{t} || 'default';
&usage if not first { $type eq $_ } keys %{ $chars };

my $sp = Data::SimplePassword->new;
$sp->chars( @{ $chars->{ $type } } );

if( defined $opt->{u} ){
    $sp->provider('devurandom');    # try to use non-blocking RNG
}

if( defined $opt->{e} ){
    require IO::Handle;
    STDOUT->autoflush(1);
    print $sp->make_password( 256 ) while 1;
}
else{
    print $sp->make_password( $n ), "\n";
}

sub usage {
    pod2usage 0;
}

*HELP_MESSAGE = \&usage;

__END__

=head1 NAME

rndpassword - a command-line frontend to Data::SimplePassword

=head1 SYNOPSIS

rndpassword [-hu] [-t <type>] [-n <length>]

 Options:
    -h  show usage
    -t  set character type
    -n  set length (default: 8 byte)
    -e  endless mode on
    -u  try to use non-blocking RNG (/dev/urandom)

 Types:       (output sample)
    default   0xaVbi3O2Lz8E69s    # 0..9 a..z A..Z
    ascii     n:.T<Gr!,e*[k=eu    # visible ascii (a.k.a. spaghetti)
    base64    PC2gb5/8+fBDuw+d    # 0..9 a..z A..Z /+
    simple    xek4imbjcmctsxd3    # 0..9 a..z
    digit     7563919623282657    # 0..9
    binary    1001011110000101
    morse     -.--...-.--.-..-

 Examples:
    shell> rndpassword
    shell> rndpassword 16
    shell> rndpassword -n 16
    shell> rndpassword -t digit  -n 32
    shell> rndpassword -t binary -n 1024 -u
    shell> rndpassword -t ascii  -e      # type Ctrl-C to terminate

=head1 DEPENDENCY

Data::SimplePassword