package string;

my %convSymbol = (
	'，' => ',', '．' => '.', '：' => ':', '；' => ';',
	'？' => '?', '！' => '!', '｀' => '`', '＾' => '^',
	'＿' => '_', '／' => '/', '｜' => '|', '’' => "'",
	'”' => '"', '（' => '(', '）' => ')', '［' => '[',
	'］' => ']', '｛' => '{', '｝' => '}', '＋' => '+',
	'－' => '-', '＜' => '<', '＞' => '>', '￥' => '\\',
	'＝' => '=', '＄' => '$', '％' => '%', '＃' => '#',
	'＆' => '&', '＊' => '*', '＠' => '@', #'ー' => '-',
	'＼' => '\\', '‘' => '`', '～' => '~', '　' => ' ',
);

sub toAscii {
	${$_[0]} =~ s/\xa3([\xb0-\xb9])/ord($1) - 0xb0/eg;
	${$_[0]} =~ s/\xa3([\xc1-\xda\xe1-\xfa])/chr(ord($1) - 0x80)/eg;
	${$_[0]} =~ s/(\xa1\W)/defined($convSymbol{$1}) ? $convSymbol{$1} : $1/eg;
}

sub toHiragana {
	${$_[0]} =~ s/(?:\xa4|\xa5)([\xa1-\xf3])/\xa4$1/g;
	isHiragana($_[0]);
}

sub toKatakana {
	${$_[0]} =~ s/(?:\xa4|\xa5)([\xa1-\xf3])/\xa5$1/g;
	isKatakana($_[0]);
}

package locker;

sub new {
	my $class = shift;
	my $self = {};
	my $file = shift;
	my $argRef = shift;
	eval { flock STDIN, 5; };
	if ($@ eq '' and not $argRef->{'noFlock'}) {
		$self->{'mode'} = 'flock';
	} else {
		eval { symlink '', ''; };
		if ($@ eq '') {
			$self->{'mode'} = 'symlink';
		} else {
			$self->{'mode'} = 'file';
		}
		$self->{'lock'} = "${file}.lck";
	}
	$self->{'file'} = $file;
	$self->{'tout'} = (exists $argRef->{'timeout'})? $argRef->{'timeout'} : 30;
	$self->{'retry'} = (exists $argRef->{'retry'})? $argRef->{'retry'} : 10;
	bless $self, $class;
	$self;
}

sub lock {
	my $self = shift;
	if ($self->{'mode'} eq 'flock') {
		local *LFH = $_[0];
		my $type = (defined $_[1])? $_[1] : 2;
		my $result = flock *LFH, $type;
		$self->{'flag'} = *LFH;
		return $result;
	}
	$self->{'flag'} = 'true';
	if ($self->{'mode'} eq 'symlink') {
		unlink $self->{'lock'}
			if(time - (stat $self->{'lock'})[9] > $self->{'tout'});
		my $retry = $self->{'retry'};
		while (not symlink $self->{'file'}, $self->{'lock'}) {
			return undef if ($retry-- <= 0);
			sleep 2;
		}
		return not 0;
	} else {
		my $count = 0;
		my $lock = $self->{'lock'};
		my $now = time;
		if (-e $lock) {
			utime $now, $now, $lock and return not 0
				if ($now - (stat(_))[9] > $self->{'tout'});
		}
		my $retry = $self->{'retry'};
		while ($retry-- >= 0) {
			if (mkdir $lock, 0755) {
				utime $now, $now, $lock;
				return not 0;
			}
			sleep 2;
		}
		return undef;
	}
}

sub unlock {
	my $self = shift;
	$self->{'flag'} = undef;
	if ($self->{'mode'} eq 'flock') {
# flock は明示的に解除する必要がない
#		local *LFH = $_[0];
#		return flock *LFH, 8;
	} elsif ($self->{'mode'} eq 'symlink') {
		return unlink $self->{'lock'};
	} else {
		my $lock = $self->{'lock'};
		return rmdir $lock;
	}
}

sub DESTROY {
	my $self = shift;
	if (defined $self and $self->{'flag'} eq 'true') {
		$self->unlock($self->{'flag'});
	}
}


1;

