#!/usr/bin/perl
##
## mktemp(1) clone: make a temporary filename
## Copyright (c) 2007-2008 SATOH Fumiyasu @ OSS Technology Corp.
##               <http://www.osstech.co.jp/>
##
## License: GNU General Public License version 2 or later
## Date: 2008-09-19, since 2007-07-11
##

use strict;
use warnings;
use Getopt::Long;
use POSIX;
use IO::File;

umask(0077);

my @seed = ('0'..'9', 'a'..'z', 'A'..'Z');

my $flag_dir = undef;
my $flag_quiet = undef;
my $flag_unsafe = undef;
my $flag_generate_path = undef;
my $temp_dir = '/tmp';
my $temp_name = 'tmp.XXXXXXXXXX';

my $cmd_name = $0;
$cmd_name =~ s#^.*/##;
my $cmd_usage = "Usage: $cmd_name [-dptu] [-p DIRECTORY] [TEMPLATE]\n";

Getopt::Long::Configure('bundling');
Getopt::Long::Configure('no_ignore_case');
Getopt::Long::Configure('no_auto_abbrev');
GetOptions(
  'd' =>	\$flag_dir,
  'q' =>	\$flag_quiet,
  't' =>	\$flag_generate_path,
  'u' =>	\$flag_unsafe,
  'p=s' =>	sub {
    $temp_dir = $_[1];
    $flag_generate_path = 1;
  }
) || die "$cmd_usage";

if ($flag_unsafe) {
  die "$cmd_name: -u option is not supported yet\n";
}

if (@ARGV > 1) {
  die "$cmd_name: too many argument\n";
}

## ----------------------------------------------------------------------

if (defined($ENV{'TMPDIR'})) {
  $temp_dir = $ENV{'TMPDIR'};
}

if ($flag_quiet) {
  $SIG{'__DIE__'} = sub {
    exit(1);
  }
}

## ======================================================================

my $temp_template;
if ($flag_generate_path) {
  if (defined($ARGV[0])) {
    $temp_name = $ARGV[0];
  }
  if ($temp_name =~ m#/#) {
    die "$cmd_name: template must not contain directory separators in -t mode\n";
  }

  $temp_template = "$temp_dir/$temp_name";
}
else {
  $temp_template = defined($ARGV[0]) ? $ARGV[0] : "$temp_dir/$temp_name";
}

$temp_template =~ s#//+#/#g;

$temp_template =~ s/(X+)$//;
my $seed_n = defined($1) ? length($1) : 0;
my $try_max = $seed_n * 10;

for (my $try = 0; $try <= $try_max; $try++) {
  my $temp = $temp_template;
  for (my $n = 0; $n < $seed_n; $n++) {
    $temp .= $seed[int(rand(@seed))];
  }

  if ($flag_dir) {
    if (mkdir($temp, 0700)) {
      print "$temp\n";
      exit(0);
    }
    elsif ($! != POSIX::EEXIST || $try == $try_max) {
      die "$cmd_name: cannot create temporary directory $temp: $!\n";
    }
  }
  else {
    my $fh = IO::File->new($temp, O_RDWR|O_CREAT|O_EXCL, 0600);
    if (defined($fh)) {
      print "$temp\n";
      exit(0);
    }
    elsif ($! != POSIX::EEXIST || $try == $try_max) {
      die "$cmd_name: cannot create temporary file $temp: $!\n";
    }
  }
}

## Not reached
exit(1);

