#!/usr/bin/perl
##
## pwgen(1) clone: Passwords generator
## Copyright (c) 2007-2010 SATOH Fumiyasu @ OSS Technology, Inc.
##               <http://www.osstech.co.jp/>
##
## License: GNU General Public License version 2 or later
## Date: 2010-03-27, since 2005-05-23
##

use strict;
use warnings;
use Getopt::Long;

## FIXME: srand(truely random number);

my $seed_digits = '0123456789';
my $seed_uppers = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
my $seed_lowers = 'abcdefghijklmnopqrstuvwxyz';
my $seed_symbols = '#%&\'()*+,-./:;<=>?@[]^_{|}~'; ## Except '"', '$', '\', '`'
#my $seed_symbols = '"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~';
my $seed_ambiguous = '0DOQ1lI2Z5S6G8B9q';

my $length = 32;
my $number = 8;
my $flag_digit = 1;
my $flag_upper = 1;
my $flag_lower = 1;
my $flag_symbol = undef;
my $flag_ambiguous = undef;

my $cmd_usage = "Usage: $0 [OPTIONS] [LENGTH [NUMBER]]

Arguments:
  LENGTH
    Password length
  NUMBER
    Number of passwords

Options:
  -y or --symbols
    Include at least one special symbol in the password
  -B, --ambiguous
    Don't include ambiguous characters in the password
";

{
  ## Trap warning messages from Getopt::Long
  local($SIG{'__WARN__'}) = sub {
    my ($msg) = shift(@_);
    chomp($msg);
    print STDERR "$0: ERROR: $msg\n";
  };
  ## I don't like default behavior.
  Getopt::Long::Configure('bundling');
  Getopt::Long::Configure('no_ignore_case');
  Getopt::Long::Configure('no_auto_abbrev');
  GetOptions(
    'h|help' =>		sub { print $cmd_usage; exit(0); },
    'y|symbols' =>	\$flag_symbol,
    'B|ambiguous' =>	\$flag_ambiguous,
  ) || die "$cmd_usage";
}

$length = shift(@ARGV) if (@ARGV);
$number = shift(@ARGV) if (@ARGV);

my $seed = '';
$seed .= $seed_digits if ($flag_digit);
$seed .= $seed_uppers if ($flag_upper);
$seed .= $seed_lowers if ($flag_lower);
$seed .= $seed_symbols if ($flag_symbol);
unless ($flag_ambiguous) {
  my $ambiguous_re = '(?:' . join('|', split(//, $seed_ambiguous)) . ')';
  $seed =~ s/$ambiguous_re//o;
}

my @seed = split(//, $seed);

for (my $i = 0; $i < $number; $i++) {
  my $password = '';
  for (my $j = 0; $j < $length; $j++) {
    $password .= @seed[rand(@seed)];
  }
  print "$password\n";
}

