[Namazu-devel-ja 240] syscmd 試作
Tadamasa Teranishi
yw3t-trns @ asahi-net.or.jp
2004年 10月 10日 (日) 13:17:18 JST
寺西です。
pltests である程度のテストができましたので、syscmd を util.pl
に追加し、サンプルとして filter/{man.pl, pdf.pl, rpm.pl} を
util::syscmd を使うように書き換えてみました。
util::syscmd は、pltests::syscmd よりもシンプルになっており、
バッチコマンドの実行をサポートしていません。
バッチコマンドは何かとトラブルを起こしかねないので、Namazu 本体での
サポートからは外しました。
(現在のところ、フィルタでバッチを実行するものはありませんので
実害はないでしょう。)
また、改行コード変換ルーチン codeconv::normalize_nl を追加しました。
同時に、util::readfile($;$) に省略可能な第二引数を追加し、テキスト
モード("t")での読み込み機能を追加しました。(省略時はバイナリモード)
とりあえず、全フィルタを書き換え、フィルタから
・env コマンドの撤廃
・2> の撤廃
・util::systemcmd の撤廃
・system の撤廃
を行いたいと思っています。
そうすることで、Windows 対応(Windows 95 系対応を含む)となるものと
思います。
--
=====================================================================
寺西 忠勝(TADAMASA TERANISHI) yw3t-trns @ asahi-net.or.jp
http://www.asahi-net.or.jp/~yw3t-trns/index.htm
Key fingerprint = 474E 4D93 8E97 11F6 662D 8A42 17F5 52F4 10E7 D14E
-------------- next part --------------
Index: pl/codeconv.pl
===================================================================
RCS file: /storage/cvsroot/namazu/pl/codeconv.pl,v
retrieving revision 1.23
diff -u -p -r1.23 codeconv.pl
--- pl/codeconv.pl 1 Oct 2004 03:44:28 -0000 1.23
+++ pl/codeconv.pl 9 Oct 2004 22:08:53 -0000
@@ -198,4 +198,13 @@ sub normalize_eucjp ($) {
$contref;
}
+sub normalize_nl ($) {
+ my ($conts) = @_;
+
+ $$conts =~ s/\x0d\x0a/\x0a/g; # Windows
+ $$conts =~ s/\x0d/\x0a/g; # Mac
+ $$conts =~ s/\x0a/\n/g;
+ $$conts;
+}
+
1;
Index: pl/util.pl
===================================================================
RCS file: /storage/cvsroot/namazu/pl/util.pl,v
retrieving revision 1.29
diff -u -p -r1.29 util.pl
--- pl/util.pl 18 Mar 2004 15:52:11 -0000 1.29
+++ pl/util.pl 9 Oct 2004 22:08:53 -0000
@@ -124,8 +124,12 @@ sub rfc822time ($)
$hour, $min, $sec, time::gettimezone());
}
-sub readfile ($) {
- my ($arg) = @_;
+sub readfile ($;$) {
+ my ($arg, $mode) = @_;
+ my $text_mode = undef;
+ if (defined $mode && $mode =~ /^t/i) {
+ $text_mode = 1;
+ }
my $fh;
if (ref $arg) {
@@ -147,6 +151,8 @@ sub readfile ($) {
# }
read $fh, $cont, $size;
+ codeconv::normalize_nl(\$cont) if (defined $text_mode);
+
unless (ref $arg) {
fclose($fh);
}
@@ -334,6 +340,196 @@ sub systemcmd(@) {
$fh_err->seek(0, SEEK_SET) or cdie "seek: $!";
return ($status, $fh_out, $fh_err);
+}
+
+sub syscmd(%)
+{
+ my $status = undef;
+ my %arg = @_;
+ my @args = @{$arg{command}} if (defined $arg{command});
+ my %option = %{$arg{option}} if (defined $arg{option});
+ my %env = %{$arg{env}} if (defined $arg{env});
+
+ dprint(_("Invoked: ") . join(' ', @args));
+
+ # default option
+ $option{stdout} = '/dev/null' unless(defined $option{stdout});
+ $option{stderr} = '/dev/null' unless(defined $option{stderr});
+ $option{mode_stdout} = 'at' unless(defined $option{mode_stdout});
+ $option{mode_stderr} = 'at' unless(defined $option{mode_stderr});
+ $option{maxsize} = -1 unless(defined $option{maxsize});
+
+ my $handle_out = undef;
+ my $handle_err = undef;
+ if (ref $option{stdout}) {
+ if ($option{stdout} =~ /^(IO::File|FileHandle)/) {
+ $handle_out = $option{stdout};
+ }
+ }
+ if (ref $option{stderr}) {
+ if ($option{stderr} =~ /^(IO::File|FileHandle)/) {
+ $handle_err = $option{stderr};
+ }
+ }
+
+ my $same = 0;
+ if ($option{stdout} eq $option{stderr}) {
+ $same = 1;
+ }
+
+ my $mode_stdout;
+ my $mode_stderr;
+ if ($option{mode_stdout} =~ /^w/i) {
+ $mode_stdout = '>';
+ } elsif ($option{mode_stdout} =~ /^a/i) {
+ $mode_stdout = '>>';
+ } else {
+ warn "unknown mode. : " . quotemeta($option{mode_stdout});
+ $mode_stdout = '>>';
+ }
+ if ($option{mode_stderr} =~ /^w/i) {
+ $mode_stderr = '>';
+ } elsif ($option{mode_stderr} =~ /^a/i) {
+ $mode_stderr = '>>';
+ } else {
+ warn "unknown mode. : " . quotemeta($option{mode_stderr});
+ $mode_stderr = '>>';
+ }
+
+ my $text_stdout = undef;
+ my $text_stderr = undef;
+ if ($option{mode_stdout} =~ /^.t/i) {
+ $text_stdout = 1;
+ }
+ if ($option{mode_stderr} =~ /^.t/i) {
+ $text_stderr = 1;
+ }
+
+ if ($mknmz::SYSTEM eq "MSWin32" || $mknmz::SYSTEM eq "os2") {
+ foreach my $arg (@args) {
+# $arg =~ s!/!\\!g;
+ }
+ }
+
+ my $fh_out = undef;
+ my $fh_err = undef;
+
+ if (defined $handle_out) {
+ $fh_out = $handle_out;
+ } else {
+ $fh_out= IO::File->new_tmpfile();
+ }
+ if ($same) {
+ $fh_err = $fh_out;
+ } else {
+ if (defined $handle_err) {
+ $fh_err = $handle_err;
+ } else {
+ $fh_err = IO::File->new_tmpfile();
+ }
+ }
+
+ {
+ my $saveout = new IO::File (">&" . STDOUT->fileno()) or cdie "Can't dup STDOUT: $!";
+ my $saveerr = new IO::File (">&" . STDERR->fileno()) or cdie "Can't dup STDERR: $!";
+ STDOUT->fdopen($fh_out->fileno(), 'w') or cdie "Can't open fh_out: $!";
+ STDERR->fdopen($fh_err->fileno(), 'w') or cdie "Can't open fh_out: $!";
+
+ # backup $ENV{}
+ my %backup;
+ my ($key, $value);
+ while(($key, $value) = each %env) {
+ $backup{$key} = $ENV{$key};
+ if (defined $value) {
+ $ENV{$key} = $value;
+ } else {
+ delete $ENV{$key};
+ }
+ }
+
+ # Use an indirect object: see Perl Cookbook Recipe 16.2 in detail.
+ $status = system { $args[0] } @args;
+
+ # restore $ENV{}
+ while(($key, $value) = each %env) {
+ if (defined $backup{$key}) {
+ $ENV{$key} = $backup{$key};
+ } else {
+ delete $ENV{$key};
+ }
+ }
+
+ STDOUT->fdopen($saveout->fileno(), 'w') or cdie "Can't restore saveout: $!";
+ STDERR->fdopen($saveerr->fileno(), 'w') or cdie "Can't restore saveerr: $!";
+ }
+
+ # Note that the file position of filehandles must be rewinded.
+ $fh_out->seek(0, SEEK_SET) or cdie "seek: $!";
+ $fh_err->seek(0, SEEK_SET) or cdie "seek: $!";
+
+ if (!defined $handle_out) {
+ if (ref($option{stdout}) ne 'SCALAR') {
+ if ($option{stdout} eq '/dev/null') {
+ $fh_out->close();
+ } else {
+ my $conts_out = "";
+ my $size = -s $fh_out;
+ read $fh_out, $conts_out, $size;
+ $fh_out->close();
+ codeconv::normalize_nl(\$conts_out) if (defined $text_stdout);
+
+ my $file = $option{stdout};
+ if ($mknmz::SYSTEM eq "MSWin32" || $mknmz::SYSTEM eq "os2") {
+# $file =~ s!/!\\!g;
+ }
+ if (!open(OUT, "$mode_stdout$file")) {
+ warn "Can not open file. : $file";
+ return (1);
+ }
+ print OUT $conts_out;
+ close(OUT);
+ }
+ } else {
+ my $conts_out = $option{stdout};
+ my $size = -s $fh_out;
+ read $fh_out, $$conts_out, $size;
+ $fh_out->close();
+ codeconv::normalize_nl($conts_out) if (defined $text_stdout);
+ }
+ }
+
+ if (!(defined $handle_err || $same)) {
+ if (ref($option{stderr}) ne 'SCALAR') {
+ if ($option{stderr} eq '/dev/null') {
+ $fh_err->close();
+ } else {
+ my $conts_err = "";
+ my $size = -s $fh_err;
+ read $fh_err, $conts_err, $size;
+ $fh_err->close();
+ codeconv::normalize_nl(\$conts_err) if (defined $text_stderr);
+
+ my $file = $option{stderr};
+ if ($mknmz::SYSTEM eq "MSWin32" || $mknmz::SYSTEM eq "os2") {
+# $file =~ s!/!\\!g;
+ }
+ if (!open(OUT, "$mode_stderr$file")) {
+ warn "Can not open file. : $file";
+ return (1);
+ }
+ print OUT $conts_err;
+ close(OUT);
+ }
+ } else {
+ my $conts_err = $option{stderr};
+ my $size = -s $fh_err;
+ read $fh_err, $$conts_err, $size;
+ $fh_err->close();
+ codeconv::normalize_nl($conts_err) if (defined $text_stderr);
+ }
+ }
+
+ return ($status);
}
# Returns a string representation of the null device.
Index: filter/pdf.pl
===================================================================
RCS file: /storage/cvsroot/namazu/filter/pdf.pl,v
retrieving revision 1.35
diff -u -p -r1.35 pdf.pl
--- filter/pdf.pl 21 May 2004 11:58:37 -0000 1.35
+++ filter/pdf.pl 9 Oct 2004 22:08:53 -0000
@@ -44,12 +44,20 @@ sub status() {
$pdfconvpath = util::checkcmd('pdftotext');
$pdfinfopath = util::checkcmd('pdfinfo');
if (defined $pdfconvpath) {
- my ($status, $fh_out, $fh_err) = util::systemcmd($pdfconvpath);
- if (<$fh_err> =~ /^pdftotext\s+version\s+([0-9]+\.[0-9]+)/) {
+ my @cmd = ("$pdfconvpath");
+ my $result = "";
+ my $status = util::syscmd(
+ command => \@cmd,
+ option => {
+ "stdout" => "/dev/null",
+ "stderr" => \$result,
+ "mode_stdout" => 'wt',
+ "mode_stderr" => 'wt',
+ },
+ );
+ if ($result =~ /^pdftotext\s+version\s+([0-9]+\.[0-9]+)/) {
$pdfconvver = $1;
}
- util::fclose($fh_out);
- util::fclose($fh_err);
if (util::islang("ja")) {
if ($pdfconvver >= 1.00) {
@pdfconvopts = ('-q', '-raw', '-enc', 'EUC-JP');
@@ -60,12 +68,20 @@ sub status() {
@pdfconvopts = ('-q', '-raw');
}
if (defined $pdfinfopath) {
- my ($status, $fh_out, $fh_err) = util::systemcmd($pdfinfopath);
- if (<$fh_err> =~ /^pdfinfo\s+version\s+([0-9]+\.[0-9]+)/) {
+ my @cmd = ("$pdfinfopath");
+ my $result = "";
+ my $status = util::syscmd(
+ command => \@cmd,
+ option => {
+ "stdout" => "/dev/null",
+ "stderr" => \$result,
+ "mode_stdout" => 'wt',
+ "mode_stderr" => 'wt',
+ },
+ );
+ if ($result =~ /^pdfinfo\s+version\s+([0-9]+\.[0-9]+)/) {
$pdfinfover = $1;
}
- util::fclose($fh_out);
- util::fclose($fh_err);
if (util::islang("ja")) {
if ($pdfinfover >= 2.02) {
@pdfinfoopts = ('-enc', 'EUC-JP');
@@ -112,9 +128,13 @@ sub filter ($$$$$) {
util::fclose($fh);
}
my @cmd = ($pdfconvpath, @pdfconvopts, $tmpfile, $tmpfile2);
- my ($status, $fh_out, $fh_err) = util::systemcmd(@cmd);
- util::fclose($fh_out);
- util::fclose($fh_err);
+ my $status = util::syscmd(
+ command => \@cmd,
+ option => {
+ "stdout" => "/dev/null",
+ "stderr" => "/dev/null",
+ },
+ );
unless (-e $tmpfile2) {
unlink $tmpfile;
return 'Unable to convert pdf file (maybe copying protection)';
@@ -142,10 +162,16 @@ sub filter ($$$$$) {
if (defined $pdfinfopath) {
my @cmd = ($pdfinfopath, @pdfinfoopts, $tmpfile);
- my ($status, $fh_out, $fh_err) = util::systemcmd(@cmd);
- my $result = util::readfile($fh_out);
- util::fclose($fh_out);
- util::fclose($fh_err);
+ my $result = "";
+ my $status = util::syscmd(
+ command => \@cmd,
+ option => {
+ "stdout" => \$result,
+ "stderr" => "/dev/null",
+ "mode_stdout" => 'wt',
+ "mode_stderr" => 'wt',
+ },
+ );
if ($result =~ /Title:\s+(.*)/) { # or /Subject:\s+(.*)/
$fields->{'title'} = $1;
if ($fields->{'title'} =~ /<unicode>/) {
Index: filter/rpm.pl
===================================================================
RCS file: /storage/cvsroot/namazu/filter/rpm.pl,v
retrieving revision 1.12
diff -u -p -r1.12 rpm.pl
--- filter/rpm.pl 22 Mar 2004 12:31:58 -0000 1.12
+++ filter/rpm.pl 9 Oct 2004 22:08:53 -0000
@@ -29,7 +29,6 @@ require 'gfilter.pl';
my $rpmpath = undef;
my @rpmopts = undef;
-my $envpath = undef;
sub mediatype() {
return ('application/x-rpm');
@@ -38,8 +37,7 @@ sub mediatype() {
sub status() {
$rpmpath = util::checkcmd('rpm');
@rpmopts = ("-qpi");
- $envpath = util::checkcmd('env');
- return 'no' unless (defined $rpmpath && defined $envpath);
+ return 'no' unless (defined $rpmpath);
return 'yes';
}
@@ -78,25 +76,34 @@ sub filter ($$$$$) {
}
{
- my @env = ($envpath, "LC_MESSAGE=$util::LANG", "LC_TIME=C");
- my @cmd = (@env, $rpmpath, @rpmopts, $tmpfile);
- my ($status, $fh_out, $fh_err) = util::systemcmd(@cmd);
+ my %env = (
+ "LC_ALL" => undef,
+ "LC_MESSAGE" => $util::LANG,
+ "LC_TIME" => "C",
+ );
+ my @cmd = ($rpmpath, @rpmopts, $tmpfile);
+ my $fh_out = IO::File->new_tmpfile();
+ my $status = util::syscmd(
+ command => \@cmd,
+ option => {
+ "stdout" => $fh_out,
+ "stderr" => "/dev/null",
+ },
+ env => \%env,
+ );
my $size = util::filesize($fh_out);
if ($size == 0) {
util::fclose($fh_out);
- util::fclose($fh_err);
unlink $tmpfile;
return "Unable to convert file ($rpmpath error occurred).";
}
if ($size > $conf::TEXT_SIZE_MAX) {
util::fclose($fh_out);
- util::fclose($fh_err);
unlink $tmpfile;
return 'Too large rpm file.';
}
- $$cont = util::readfile($fh_out);
+ $$cont = util::readfile($fh_out, "t");
util::fclose($fh_out);
- util::fclose($fh_err);
}
unlink $tmpfile;
Index: filter/man.pl
===================================================================
RCS file: /storage/cvsroot/namazu/filter/man.pl,v
retrieving revision 1.31
diff -u -p -r1.31 man.pl
--- filter/man.pl 21 May 2004 11:58:37 -0000 1.31
+++ filter/man.pl 9 Oct 2004 22:08:53 -0000
@@ -31,8 +31,7 @@ require 'gfilter.pl';
my $roffpath = undef;
my @roffopts = undef;
-my $envpath = undef;
-my @env = undef;
+my %env = ();
sub mediatype() {
return ('text/x-roff');
@@ -42,23 +41,30 @@ sub status() {
$roffpath = util::checkcmd('jgroff');
$roffpath = util::checkcmd('groff') unless (defined $roffpath);
$roffpath = util::checkcmd('nroff') unless (defined $roffpath);
- $envpath = util::checkcmd('env');
- unless (defined $roffpath && defined $envpath) {
+ unless (defined $roffpath) {
return 'no';
}
- @env = ($envpath, "LC_ALL=$util::LANG", "LANGUAGE=$util::LANG");
+ %env = (
+ "LC_ALL" => $util::LANG,
+ "LANGUAGE" => $util::LANG,
+ );
if (util::islang("ja") && $roffpath =~ /\bj?groff$/) {
# Check wheter -Tnippon is valid.
- my @cmd = (@env, $roffpath, "-Tnippon", util::devnull());
- my ($status, $fh_out, $fh_err) = util::systemcmd(@cmd);
+ my @cmd = ($roffpath, "-Tnippon", util::devnull());
+ my $status = util::syscmd(
+ command => \@cmd,
+ option => {
+ "stdout" => "/dev/null",
+ "stderr" => "/dev/null",
+ },
+ env => \%env,
+ );
if ($status == 0) {
@roffopts = ('-man', '-Wall', '-Tnippon');
} else {
@roffopts = ('-man', '-Wall', '-Tascii');
}
- util::fclose($fh_out);
- util::fclose($fh_err);
} elsif ($roffpath =~ /\bj?groff$/) {
@roffopts = ('-man', '-Tascii');
} elsif ($roffpath =~ /nroff$/) {
@@ -104,24 +110,29 @@ sub filter ($$$$$) {
util::fclose($fh);
}
{
- my @cmd = (@env, $roffpath, @roffopts, $tmpfile);
- my ($status, $fh_out, $fh_err) = util::systemcmd(@cmd);
+ my @cmd = ($roffpath, @roffopts, $tmpfile);
+ my $fh_out = IO::File->new_tmpfile();
+ my $status = util::syscmd(
+ command => \@cmd,
+ option => {
+ "stdout" => $fh_out,
+ "stderr" => "/dev/null",
+ },
+ env => \%env,
+ );
my $size = util::filesize($fh_out);
if ($size == 0) {
util::fclose($fh_out);
- util::fclose($fh_err);
unlink $tmpfile;
return "Unable to convert file ($roffpath error occurred)";
}
if ($size > $conf::TEXT_SIZE_MAX) {
util::fclose($fh_out);
- util::fclose($fh_err);
unlink $tmpfile;
return 'Too large man file';
}
$$cont = util::readfile($fh_out);
util::fclose($fh_out);
- util::fclose($fh_err);
}
unlink $tmpfile;
Namazu-devel-ja メーリングリストの案内