#!/usr/bin/perl
$ETCDIR = "/etc";
$BINDIR = "/usr/bin";
# cgi.pl - CGI assistant routines
# Copyright (C) by TOYODA Eizi, 1999.  All rights reserved.
#
$rcsid .= '$Id: cgi.pl,v 1.4 1999/11/06 18:04:25 toyoda Exp $';
#

	# ホスト名 (FQDN) を返す。
	# Debian GNU/Linux システムで DNS 設定が行われた状態しか考えていない
sub Hostname () {
	local($hostname) = '/bin/hostname';
	return 'localhost' unless -x $hostname;
	delete $ENV{'PATH'};
	$hostname = `$hostname -f`;
	chop $hostname;
	return $hostname;
}

#
# HTML を作るためのサブルーチン.
# 名前が print で始まるものは基本的に print 文の群れであり,
# 標準出力 (select で変更可能) に HTML の一部を出力する.
#

	# 文字列を HTML 文書に挿入できるように変形する.
	# 引数
	#	$line	任意の文字列
	# 返却値
	#	HTML 中で特殊な意味をもつ文字 & < > " を変換したもの
	# バグ
	#	\0 は & と混同されてしまう.
sub HTMLEscape {
	local($line) = @_;
	$line =~ s/&/\0/g;
	$line =~ s/</\&lt;/g;
	$line =~ s/>/\&gt;/g;
	$line =~ s/"/\&quot;/g;
	$line =~ s/\0/\&amp;/g;
	return $line;
}

	# HTTP ヘッダおよび HTML の先頭部を作成する。
	# 引数
	#	$title		文書のタイトル
	#	$color		(省略可) 色指定
sub printHtmlOpening {
	local($title, $color) = @_;
	$color = "#CCEECC" unless $color;
	local($hostname) = &Hostname();
	print <<"END";
Content-type: text/html

<HTML>
<HEAD>
<TITLE>$title</TITLE>
</HEAD>
<BODY BGCOLOR="$color">
<A HREF="/doc/dcbib/dcbib.htm">dcbib</a>
(<A HREF='/'>$hostname</a> にて動作中)
<H1 ALIGN="center">$title</H1>
END
}

	# &printTextField が生成するテキストフィールドの大きさ
	# 変えたいやつはあとで変えてくれ.
$printTextFieldLength = 45;
$printTextFieldHeight = 4;	# テキストエリアでだけ使用

	# 登録フォームの <TABLE> のなかでひとつのテキストフィールドの
	# 入力を要求する <TR> を生成する.
	#
	# 引数
	#   $fieldname		欄の名称
	#   $description	欄の説明
	#   $default		省略時初期値 (なくてもよい)
	#			%card{$fieldname} が存在すればそれが優先
	# 暗黙の引数
	#   %card
sub printTextField {
	local($fieldname, $description, $default) = @_;
	local($size) = $printTextFieldLength;
	local($defaultvalue) = $card{$fieldname} || $default;
	if ($fieldname eq "token") {
		#
		# 欄の名称が token の場合はパスワード欄にする
		# また初期値は空にする
		print <<"END";
 <TR>
 <TD NOWRAP ALIGN="right">$description</TD>
 <TD NOWRAP>
 <INPUT TYPE="PASSWORD" NAME="$fieldname" SIZE="$size">
 </TD>
 </TR>
END
	} elsif ($default =~ /\n/) {
		#
		# 省略時初期値に改行が含まれていればテキストフィールド
		# (スクロールできる)
		#
		print <<"END";
 <TR>
 <TD NOWRAP ALIGN="center">$description</TD>
 <TD NOWRAP>
 <TEXTAREA NAME="$fieldname" COLS="$size" ROWS=$printTextFieldHeight>
$defaultvalue
 </TEXTAREA>
 </TD>
 </TR>
END
	} else {
		print <<"END";
 <TR>
 <TD NOWRAP ALIGN="right">$description</TD>
 <TD NOWRAP>
 <INPUT TYPE="text" NAME="$fieldname" SIZE="$size" VALUE="$defaultvalue">
 </TD>
 </TR>
END
	}
}

	# 登録フォームの <TABLE> のなかで選択リストのラジオボタンをもって
	# 入力を要求する <TR> を生成する.
	# 省略時初期値に "\n" が含まれていれば複数行オプションをつける.
	# 引数
	#   $fieldname		欄の名称
	#   $description	欄の説明
	#   $default		デフォルト値
	#   @ValueDescriptionList
	#	可能な値のリスト. 各項が "\t" を含んでいれば
	#	その後の説明が表示される.
sub printRadioButton {
	local($fieldname, $description, $default, @ValueDescriptionList) = @_;
	print <<"END";
<TR>
<TD NOWRAP ALIGN="center">$description</TD>
<TD>
以下のリストから選んでください:<BR>
<TABLE BORDER><TR><TD><!-- 枠をつけたかっただけ -->
END
	local($vdpair, $value, $desc, $checked);
	foreach $vdpair (@ValueDescriptionList) {
		print "<BR>" if $value;
		($value, $desc) = split(/\t/, $vdpair, 2);
		$checked = ($value eq $default) ? "CHECKED" : "";
		$desc = $value unless $desc;
		print "<INPUT TYPE=RADIO NAME='$fieldname' ",
		"VALUE='$value' $checked>$desc\n";
	}
	print <<"END";
</TD></TR></TABLE><!-- 枠をつけたかっただけ -->
</TD>
END
}

	# HTML 文書の末尾の作成
	# 引数
	#	$title		文書のタイトル
sub printHtmlClosing {
	local($title) = @_;
	print "<hr>\n";
	print "<a href=\"", &CGISelfName, "\">$title にもどる</a><br>\n"
		if &FormSubmitted();
	print <<"END";
<div align="right">
管理人: <i><a href=mailto:$MAILADDR>$MAILADDR</a></i>
<br>$rcsid
</div>
</body>
</html>
END
}

#
# CGI (Common Gateway Interface) 関係のサブルーチン
#

	# ユーザ情報カードを読み込んだ連想配列 %param から
	# クッキーにセットすべき文字列を作る.
sub HashToCookie {
	local(%param) = @_;
	local(@pairs) = ();
	local($key, $value);
	foreach $key (sort(keys(%param))) {
		$value = $param{$key};
		push(@pairs, &URLEncode($key) . ":" . &URLEncode($value));
	}
	join('&', @pairs);
}

	# CGI スクリプトから呼び出した場合, 自分自身のファイル名を返す.
	# これは応答の送り先や戻り先のリンクとして使われる.
sub CGISelfName {
	$ENV{'SCRIPT_NAME'};
}

	# CGI データの長さを返す.
sub CGIDataLength {
	$ENV{'CONTENT_LENGTH'};
}

	# ユーザが Submit ボタンを押した場合真が、
	# そうでない場合偽が返される。
	# CGI プロトコル参照.
sub FormSubmitted() {
	return ($ENV{"CONTENT_LENGTH"} > 0);
}

	# CGI データを読み込んで連想配列として返す.
	# データが与えられていない場合は空リストが返る.
sub getCGIData {
	local(%card);
	local($data, $key, $value);
	require 'jcode.pl';

	return () unless &FormSubmitted();
	read(STDIN, $alldata, &CGIDataLength);
	foreach $data (split(/&/, $alldata)) {
		($key, $value) = split(/=/, $data);
		$value =~ tr/+/ /;
		$value = &URLDecode($value);
		&jcode'convert(*value, "euc");
		$card{$key} = $value;
	}
	%card;
}

	# 引数 $x を URL エンコードして返す.
	# クッキーにいれる文字列は全てこの処理をしなくてはならない。
	# CGI プロトコル参照.
sub URLEncode {
    local($x) = @_;
    $x =~ s/([&:;=%\x00-\x21])/sprintf("%%%02X",unpack("C",$1))/ge;
    return $x;
}
 
	# URL エンコードされた文字列 (引数 $x) を解読して返す.
	# クッキー起源の文字列は全てこの処理をしなくてはならない。
	# CGI プロトコル参照.
sub URLDecode {
    local($x) = @_;
    $x =~ s/%([0-9A-Fa-f][0-9A-Fa-f])/pack("C",hex($1))/ge;
    return $x;
}


0;
# addcgi.pl - CGI main program for dcbib
# Copyright (C) TOYODA Eizi, 1999.  All rights reserved.

#
$rcsid .= '$Id: addcgi.pl,v 1.20 1999/11/06 18:14:50 toyoda Exp $';
#

require 'open3.pl';

$TITLE = "dcbib 文献登録のページ";
$MAILADDR = "toyoda\@gfd-dennou.org";
$BINDIR = '/usr/bin';

if (not &FormSubmitted()) {
	&SyokiGamen();
	exit 0;
}

%card = &getCGIData();

if ($card{'phase'} eq 'initial') {
	if (not &EmailCheck($card{'from'})) {
		&SyokiGamen("電子メールアドレスを入力してください.");
		exit 0;
	}
	&NyuuryokuGamen();
} else {
	&KekkaGamen();
}

exit 0;

sub SyokiGamen {
	local($message) = @_;
	&printHtmlOpening($TITLE);
	if ($message) {
		print "<HR>", $message;
	}
	print <<EOF;
<HR>
<FORM METHOD="POST" ACTION="$ENV{'SCRIPT_NAME'}">
<INPUT TYPE="hidden" NAME="phase" VALUE="initial">

すべての欄を記入したら
<INPUT TYPE="submit" VALUE="submit">
ボタンを押してください。

<OL>

<LI>
 あなたの電子メールアドレスを入力してください:
 <INPUT TYPE="text" NAME="from" SIZE=60>

<LI>
 登録する文献の種類を選択してください:
 <DL>
 <DT><INPUT TYPE="radio" NAME="cardtype" VALUE="article" CHECKED>article
 <DD>論文誌に掲載された記事ひとつです。
 <DT><INPUT TYPE="radio" NAME="cardtype" VALUE="book">book
 <DD>書籍全体です。
 <DT><INPUT TYPE="radio" NAME="cardtype" VALUE="inbook">inbook
 <DD>書籍の一部です。
 </DL>

</OL>

<INPUT TYPE="submit" VALUE="submit">
</FORM>
EOF
	&printHtmlClosing($TITLE);
}

sub NyuuryokuGamen {
	$lang = $card{'lang'} || 'ja';
	$user = $card{'from'};
	$user =~ s/@.*//;

	&printHtmlOpening($TITLE);
	print <<EOF;
	<HR>
	<FORM METHOD="POST" ACTION="$ENV{'SCRIPT_NAME'}">
	<INPUT TYPE="hidden" NAME="phase" VALUE="nyuuryoku">
	<P>
	登録種別 $card{'cardtype'} の文献を登録します。
	重複する登録がないかどうか
	<A HREF="/arch/bunken/search.htm">
	検索</a>してから登録することをお勧めします。
	入力が済んだら <INPUT TYPE="submit" VALUE="submit">
	ボタンを押してください。
	<P>
	注意: 著者または編者が複数いる場合は改行するか '/' で区切ってください。
	人名が姓名順である場合は姓のあとにカンマ (',') を入れてください。
	<P>
	<TABLE BORDER=0>
EOF

	%setumei = (
		'author' => "著者",
		'author-or-editor' => "著者または編者",
		'title' => '表題',
		'title-ja' => '表題(日本語)',
		'journal' => '掲載雑誌',
		'publisher' => '発行者',
		'year' => '発表年度',
		'volume' => '巻数', 
		'chapter' => '章',
		'pages' => 'ページ範囲',
		'number' => '号数',
		'month' => '月',
		'edition' => '版',
		'series' => 'シリーズ',
		'address' => '出版者所在地',
	);
	if ($card{'cardtype'} eq 'article') {
		@needed = qw(author title journal year);
		@optional = qw(title-ja volume number pages month);
	} elsif ($card{'cardtype'} eq 'book') {
		@needed = qw(author-or-editor title publisher year);
		@optional = qw(title-ja volume series address edition month);
	} elsif ($card{'cardtype'} eq 'inbook') {
		@needed = qw(author-or-editor title publisher 
			year pages chapter);
		@optional = qw(title-ja volume series address edition month);
	} else {
		print "oops: unsupported cardtype";
	}
	foreach $key (qw(author editor author-or-editor title title-ja note)) {
		$card{$key} .= "\n";
	}
	$hr = "―" x 20;
	print <<EOF;
	<TR><TD>必須項目:</TD><TD>$hr</TD></TR>
	<TR>
	 <TD><INPUT TYPE="hidden" NAME="cardtype" VALUE="$card{'cardtype'}">
	  登録種別</TD>
	 <TD> $card{'cardtype'}</TD>
	</TR>
	<TR>
	 <TD><INPUT TYPE="hidden" NAME="from" VALUE="$card{'from'}">送信者
	 </TD>
	 <TD> $card{'from'}</TD>
	</TR>
EOF
	foreach $key (@needed) {
		if ($key eq 'author-or-editor') {
			&printRadioButton('select-author-or-editor',
				"著者または編者",
				"author", ("author\t著者", "editor\t編者"));
		}
		&printTextField($key, $setumei{$key}, $card{$key});
	}

	print "<TR><TD>任意項目:</TD><TD>$hr</TD></TR>\n";
	foreach $key (@optional) {
		&printTextField($key, $setumei{$key}, $card{$key});
	}
	&printTextField("Abstract", "概要", "\n");
	&printTextField("Abstract-$lang", "概要邦訳", "\n");

	print <<EOF;
	<TR>
	 <TD>$user 独自の情報:</TD>
	 <TD>$hr</TD>
	</TR>
EOF
	&printTextField("Keyword-$user-$lang", "検索キーワード", "\n");
	&printTextField("ID-$user-$lang", "所在情報", "\n");
	&printTextField("Note-$user-$lang", "備考", "\n");
	$date = &date;
	&printTextField("History", "履歴", "$date $user initial\n");

	print <<EOF;
	<TR>
	 <TD>その他自由記入欄:</TD>
	 <TD>$hr</TD>
	</TR>
EOF
	&printTextField("mainpart", "備考", "\n");
	print <<EOF;
	<TR><TD></TD><TD>$hr</TD></TR>
	<TR><TD></TD><TD>
		<INPUT TYPE="submit" VALUE="submit">
		<INPUT TYPE="reset" VALUE="reset">
	</TD></TR>
</TABLE>

</FORM>
EOF
	&printHtmlClosing($TITLE);
}

sub KekkaGamen {
        ($exitcode, $pid, @result) = &processCard;
	&printHtmlOpening($TITLE);
	print "<HR>\n";
	if ($exitcode == 0) {
		$result = "成功";
	} elsif ($exitcode == 1) {
		$result = "(警告はあるものの) いちおう成功";
	} else {
		$result = "失敗";
	}
	print "<H2>処理は${result}しました</H2>\n";
	print join("<BR>\n", @result);
	print <<EOF;
<HR>
送信内容は以下のとおりです。
<DL>
EOF
	foreach $key (keys %card) {
		print "<DT>$key:<DD>$card{$key}\n";
	}
	print "</DL>\n";
	&printHtmlClosing($TITLE);
}


sub processCard {
	if ($select = $card{'select-author-or-editor'}) {
		$card{$select} = $card{'author-or-editor'};
		delete $card{'author-or-editor'};
		delete $card{'select-author-or-editor'};
	}
	delete $card{'phase'};

	local($READ, $WRITE, $pid, @result, $exitcode);
        $READ = "READ";
        $WRITE = "WRITE";
        $pid = &open3($WRITE, $READ, '', "$BINDIR/dcbib-add");
        &writeCardStream($WRITE, %card);
        close($WRITE);
        @result = <$READ>;
        (waitpid($pid, 0) >= 0)
                || (@result = ("$?: invocation failed."));
        $exitcode = (($? >> 8) & 255);
        ($exitcode, $pid, @result)
}

sub EmailCheck {
	local($email) = @_;
	return 0 unless $email;
	return ($email =~ /.@./);
}

sub writeCardStream {
	local($WRITE, %card) = @_;
	local(%xcard);
	foreach $key (keys %card) {
		$xcard{"$key:"} = $card{$key};
	}
	&emlWrite($WRITE, %xcard);
}

sub date {
	local($sec, $min, $hour, $day, $mon, $year) = gmtime(time);
	return sprintf("%04d-%02d-%02d", $year+1900, $mon+1, $day);
}
# error.pl: error handler
# $Id: error.pl,v 1.3 1999/05/18 12:47:51 toyoda Exp $
# Copyright (c) TOYODA Eizi, 1998.  All rights reserved.
# see COPYING.TXT for terms of license.

sub die {
	local($msg) = @_;
	print STDERR "ERROR: $msg\n";
	exit 2;
}

sub warn {
	local($msg) = @_;
	print STDERR "WARNING: $msg\n";
	$exit = 1;
}

sub okay {
	local($msg) = join(' ', @_);
	print STDERR "OK: $msg\n";
}

sub exit {
	exit $exit;
}
# RFC-822-like file reading/writing module
# $Id: rfc822.pl,v 1.4 1999/11/06 18:04:25 toyoda Exp $
# Copyright (c) TOYODA Eizi, 1998.  All rights reserved.
# see COPYING.TXT for terms of license.

sub emlOpenFile {
	local($file) = @_;
	&open_r($file) || &die("cannot open <$file>");
	&emlSetFile($file);
}

sub emlSetFile {
	($emlFile) = @_;
}

sub emlReadLine {
	&readline($emlFile);
}

# -- emlRead() ---
#
# Reads RFC 822 headers from $inputfile and returns hash with which
# $returned_hash{$field_name} == $filed_value,
# where $field_name is lowercased and colon-containing filed name.
# If $field_value contains '\n', it means that the header
# $field_name appeared more than once.
# Undefined return value means there is a format error.

sub emlRead {
	local(%headers) = ();
	local($name, $val) = ("", "");

	while ($_ = &emlReadLine) {
		s/\r?\n$//;
		last if /^$/;
		if (!/^\s/) {
			next if /^From /;
			if (!/^([-A-Za-z0-9]*:)\s*(.*)/) {
				&warn("broken header <$_> in $emlFile");
				return undef;
			}
			($name = $1) =~ tr/A-Z/a-z/;
			($val = $2) =~ s/[\t\r]/ /g;
			if (defined $headers{$name}) {
				# 同名複数ヘッダは改行区切
				$headers{$name} .= "\n$val";
			} else {
				$headers{$name} = $val;
			}
		} else {
			s/[\t\r]/ /g;
			# 継続行はタブ区切
			s/^ */\t/;
			$headers{$name} .= $_;
		}
	}
	%headers;
}

sub emlWrite {
	local($outfnam, %headers) = @_;
	local($fieldname, @values, $value, $folded);

	foreach $fieldname (keys %headers) {
		local(@values) = split(/\n/, $headers{$fieldname});
		foreach $value (@values) {
			next if $value =~ /^[ \n\t]*$/;
			$folded = $value;
			$folded =~ s/\t/\n\t/g;
			print $outfnam "$fieldname $value\n";
		}
	}
}

# misc. file io concerned subroutines
# $Id: fio.pl,v 1.4 1999/05/18 12:47:51 toyoda Exp $
# Copyright (c) TOYODA Eizi, 1998.  All rights reserved.
# see COPYING.TXT for terms of license.

	# create file to write. make directory if necessary.
sub creat {
	local($fnam) = @_;
	local($parent) = $fnam;
	&CheckUmask;
	&mkdir($parent) if ($parent =~ s/\/[^\/]+$//);
	open($fnam, ">$fnam") || &die("creat $fnam");
	$fnam;
}

sub CheckUmask {
	return unless ((umask) & 0660);
	local($umask) = (umask) & ~0660;
	&warn(sprintf("warning: umask set to %04lo\n", $umask));
	umask $umask;
}

sub mkdir {
	local($dnam) = @_;
	return if (-d $dnam);
	local($parent) = $dnam;
	if ($parent =~ s/\/[^\/]+$//) {
		&mkdir($parent);
	} else {
		return;
	}
	mkdir($dnam, 0777) || &die("mkdir $dnam");
}

# test.pl - 文献カードの内容のチェック
# $Id: test.pl,v 1.6 1999/11/01 10:42:09 toyoda Exp $
# Copyright (c) TOYODA Eizi, 1998.  All rights reserved.
# see COPYING.TXT for terms of license.

# 仮定:
#	各ヘッダの内容は %HEADER に格納されている。

sub testCard {
	local(*HEADER) = @_;

	if (!$HEADER{'cardtype:'}) {
		&die("cardtype: not given.");
	} elsif ($HEADER{'cardtype:'} eq 'article') {
		&testCardAuthor;
		&testCardTitle;
		&testCardJournal;
		&testCardYear;
		&testCardPages(0);
	} elsif ($HEADER{'cardtype:'} eq 'inbook') {
		&testCardAuthorOrEditor;
		&testCardTitle;
		&testCardPublisher;
		&testCardYear;
		&testCardChapter;
		&testCardPages(1);
	} elsif ($HEADER{'cardtype:'} eq 'book') {
		&testCardAuthorOrEditor;
		&testCardTitle;
		&testCardPublisher;
		&testCardYear;
	} else {
		&die("unknown CardType: $HEADER{'cardtype:'}.");
	}
}

sub testCardChapter {
	&die("chapter: required.") if ($required && !$HEADER{'chapter:'});
}

sub testCardPublisher {
	&die("publisher: required.") if ($required && !$HEADER{'publisher:'});
}

sub testCardPages {
	local($required) = @_;
	&die("pages: required.") if (!$required && !$HEADER{'pages:'});
	&warn("pages: has no number. Are you sure?")
		if ($HEADER{'pages:'} !~ /[0-9]/);
}

sub testCardAuthorOrEditor {
	local($fail) = 1;
	if ($HEADER{'author:'}) {
		&testCardAuthor;
		$fail = 0;
	}
	if ($HEADER{'editor:'}) {
		&testCardEditor;
		$fail = 0;
	}
}

sub testCardEditor {
	&die("editor: required.") unless $HEADER{'editor:'};
}

sub testCardAuthor {
	&die("author: required.") unless $HEADER{'author:'};
	&warn("author: should begin in uppercase letter.")
		if ($HEADER{'author:'} =~ /^[a-z]/);
	&warn("author: should begin in A-Za-z. ($HEADER{'author:'})")
		unless ($HEADER{'author:'} =~ /^[A-Za-z]/);
}

sub testCardJournal {
	&die("journal: required.") if (!$HEADER{'journal:'});
}

sub testCardTitle {
	&die("title: required.") if (!$HEADER{'title:'});
	# 本当は ASCII を強制してもよいが、もうちょっと弱気に
	# アルファベットが1文字もみあたらないと警告する
	&warn("title: has no letter. Are you sure?")
		if ($HEADER{'title:'} !~ /[A-Za-z]/);
}

sub testCardYear {
	$HEADER{'year:'} =~ s/\s+//g;
	if ($HEADER{'year:'} =~ /([^0-9x]+)/) {
		local($bad) = $1;
		$HEADER{'year:'} =~ tr/0-9/x/c;
		&warn("year: has bad character '$bad' --- converted to 'x'.");
	}
	&die("year: required.") if ($HEADER{'year:'} !~ /[0-9x]/);
}
# card.pl - 文献カードのフィールドたちに関する情報
# $Id: card.pl,v 1.2 1999/05/30 13:33:54 toyoda Exp $
# Copyright (c) TOYODA Eizi, 1998.  All rights reserved.
# see COPYING.TXT for terms of license.

sub cardTypeHash {
 %CARDTYPE = (
	'article'	=> '定期刊行物または学術雑誌の記事',
	'book'		=> '書籍 (出版者が明確なもの)',
	'booklet'	=> '書籍 (出版者の明確でないもの)',
	'inbook'	=> '書籍の一部 (固有の表題をもたないもの)',
	'incollection'	=> '書籍の一部 (表題のついたまとまり)',
	'inproceedings'	=> '会議の予稿集に収録された論文',
	'manual'	=> '技術文書',
	'masterthesis'	=> '修士論文',
	'misc'		=> 'その他',
	'phdthesis'	=> '博士論文',
	'proceedings'	=> '会議の予稿集',
	'techreport'	=> '学校や団体の刊行した報告集のひとつ',
	'unpublished'	=> '未公刊文献',
 );
 %REQUIREDFIELD = (
	'article'	=> 'author title journal year',
	'book'		=> 'author/editor title publisher year',
	'booklet'	=> 'title',
	'inbook'	=> 'author/editor title chapter/pages publisher year',
	'incollection'	=> 'author title booktitle publisher year',
	'inproceedings'	=> 'author title booktitle year',
	'manual'	=> 'title',
	'masterthesis'	=> 'author title school year',
	'misc'		=> '',
	'phdthesis'	=> 'author title school year',
	'proceedings'	=> 'title year',
	'techreport'	=> 'author title institution year',
	'unpublished'	=> 'author title note',
 );
 %OPTIONFIELD = (
	'article'	=> 'volume number pages month',
	'book'		=> 'volume series address edition month',
	'booklet'	=> 'author howpublished address month year',
	'inbook'	=> 'volume series address edition month',
	'incollection'	=> 'editor chapter pages address month',
	'inproceedings'	=> 'editor pages organization publisher address',
	'manual'	=> 'author organization address edition month year',
	'masterthesis'	=> 'address month',
	'misc'		=> 'author title howpublished month year',
	'phdthesis'	=> 'address month',
	'proceedings'	=> 'editor publisher organization address month',
	'techreport'	=> 'type number address month',
	'unpublished'	=> 'month year',
 );
 %FIELDDESCRIPTION = (
	'address'	=> '出版者の住所 (著名な出版社ならば都市名だけで可)',
	'author'	=> '著者 (複数いる場合はそれぞれ別の行に記述)',
	'booktitle'	=> '書籍の表題',
	'chapter'	=> '章番号',
	'edition'	=> '書籍の版数',
	'editor'	=> '編集者',
	'howpublished'	=> 'どのように刊行されたか',
	'institution'	=> '発行元組織',
	'journal'	=> '定期刊行物名称',
	'month'		=> '刊行された月 (未刊行の場合は書かれた月)',
	'note'		=> '付加情報',
	'number'	=> '号数',
	'organization'	=> '発行元組織 (会議のスポンサー)',
	'pages'		=> 'ページ範囲',
	'publisher'	=> '出版者',
	'school'	=> '大学',
	'series'	=> '書籍シリーズの表題',
	'title'		=> '表題',
	'type'		=> '報告書の種別',
	'volume'	=> '巻番号',
	'year'		=> '刊行された年 (未刊行の場合は書かれた年)',
 );
}

sub cardTypeList {
	defined %CARDTYPE || cardTypeHash;
	keys %CARDTYPE;
}

sub cardTypeDescription {
	local($type) = @_;
	defined %CARDTYPE || cardTypeHash;
	$CARDTYPE{$type};
}

sub requiredFields {
	local($type) = @_;
	defined %REQUIREDFIELD || cardTypeHash;
	split(' ', $REQUIREDFIELD{$type});
}

sub optionFields {
	local($type) = @_;
	defined %OPTIONFIELD || cardTypeHash;
	split(' ', $OPTIONFIELD{$type});
}

sub availableFields {
	local($type) = @_;
	defined %OPTIONFIELD || cardTypeHash;
	split(' ', "$REQUIREDFIELD{$type} $OPTIONFIELD{$type}");
}
# japanese.pl - 日本語文字コード変換ルーチン
# $Id: japanese.pl,v 1.5 1999/05/18 12:47:51 toyoda Exp $
# Copyright (C) TOYODA Eizi, 1999.  All rights reserved.
#
# プログラムの内部表現として日本語 EUC を使うためのサブルーチン。
#
# &initKC
#	漢字コード変換手段を選択する. 自動的に起動されるが
#	自動判定履歴を初期化する場合には明示的に呼んでもよい.
#
# &open_r($filename)
#	ファイルを読み込みのために開き, そのハンドルを返す.
#
# &readline($handle)
#	$handle から 1 行読み取り内部コードに変換したものを返す.
#
# $KCMethod
# 	'jcodepl':	Perl で自ら jcode.pl を読みに行く. 最善の手段.
#	'nkf':		/usr/bin にあるものを起動する. 次善の策.
#	undef:		最悪.
#
# $KCICode, $KCOCode
#	'jis'		ISO-2022-JP
#	'euc'		日本語 EUC (デフォルト)
#	'sjis'		JIS X 0208-1997 付属書 シフト符号化表現

sub initKC {
	$KC_NKF = '/usr/bin/nkf';

	if (require 'jcode.pl') {
		$KCMethod = 'jcodepl';
	} elsif (-x $KC_NKF) {
		$KCMethod = 'nkf';
	} else {
		die "no kanji conversion method found.";
	}
	$KCIcode = undef;
}

sub open_r {
	local($filename) = @_;
	defined($KCMethod) || &initKC;
	local($path);
	if ($KCMethod eq 'nkf') {
		$path = "$KC_NKF -e \"$filename\"|"
	} else {
		$path = "<$filename";
	}
	open($filename, "$path") && $filename;
}

sub readline {
	local($handle) = @_;
	local($line, $code);
	defined($KCMethod) || &initKC;
	($line = <$handle>) || return undef;
	return $line if ($line !~ /[\033\200-\377]/);
	if ($KCMethod eq 'jcodepl') {
		($code = &jcode'getcode(*line)) && ($KCIcode = $code);
		&jcode'convert(*line, 'euc', $KCIcode);
		&jcode'h2z_euc(*line);
	}
	$line;
}

# debug code: not executed if this file follows 'exit;' line.
while ($fnam = shift) {
	$handle = &open_r($fnam);
	while ($_ = &readline($handle)) {
		print;
	}
}

