[Mew-dist 1180] Re: imsort + patch (Re: IM official patch 1)
ukai at example.com
ukai at example.com
1997年 7月 3日 (木) 17:57:51 JST
From: SAKAI Kiyotaka <ksakai at example.com>
Subject: [Mew-dist 1176] Re: imsort + patch (Re: IM official patch 1)
Date: Thu, 03 Jul 1997 13:27:59 +0900
> > これ Alpha testing だし、C が必要みたいですが、それでも
> > いいんでしょうか?
>
> 個人的には、perl で標準に添付されているものであれば使う価値はあります
> が、そうでなければプラットホーム間の互換性も心配になりますし、ユーザー
> にとってはわざわざインストールするのは手間ですので、自前で用意した方が
> いいと思います。option で使うかどうかを選択できるようにするのであれば
> 問題ないと思いますが、そこまでやるのも…、という気もします。
そうですねぇ。とりあえず RFC822 と INN の parsedate(3)あたりが
解釈できればいいのでしょうか?
> あと、imsort ですが、欲を言えば contrib/mew-sort.el で行っている機能を
> 実現するために、sortm の -datefiled, -textfield に相当する機能があると
> 便利だと思います。
これはそんなに難しくなかったので作ってみました(^^;
--textfield は -textfield -limit 0 と同じように sort (text major, date minor)
--textfield と --datefield を同時に指定したら datefield も
変更できて かつ text major, date minor で sort
--textfield=subject の時は Re: をけずって比較
するはずです。これでどうでしょうか?
date major, text minor は date が秒単位で比較なので
意味なさそう(なのでなし)。 sortmの -limit もいまいちよくわかんないし…
あと Date: は $Header{'date'}じゃなくて $Header{'date:'}なので
([Mew-dist 1148]) 指定するなら --datefield=date: じゃないと駄目
なので注意
> # mew-dist の配送が遅い…。
# 自分のが3時間かかってかえってきた…
--
鵜飼文敏
-------------- next part --------------
#! @im_cv_path_perl@
# Copyright (c) 1997 UKAI Fumitoshi
#
my $VERSION = "imsort @im_cv_version@";
$Prog = 'imsort';
use IM::Config;
use IM::Scan;
use IM::Date;
$EXPLANATION = "
$Prog :: Internet Message Sort
$VERSION
Usage :: $Prog [options] [+folder] [range]
";
@OptConfig = (
'src;F@;;' => 'Message source',
'datefield;s;;' => 'Sort by specified field, as RFC822 date'
. "\n\t\t(default: \"date:\")",
'textfield;s;;' => 'Sort by specified field'
. "\n\t\t(default: \"subject\")",
'noharm;b;;' => 'No sorting. Show what will happen.',
'verbose;b;;' => 'set verbose mode',
'help;b;;' => 'Show this message',
);
init_opt(\@OptConfig);
read_env(\@EnvConfig);
read_cfg();
read_opt(\@ARGV);
help($EXPLANATION) && exit $EXIT_SUCCESS if ($opt_help);
@ARGV = ('all') if $#ARGV == -1;
@opt_src = &uniq(@opt_src);
my $keyhook;
my $textfield;
my $datefield = 'date:';
my $sort_method = \&sortbydate;
if (defined($opt_datefield)) {
$datefield = $opt_datefield || 'date:';
$sort_method = \&sortbydate;
}
if (defined($opt_textfield)) {
$textfield = $opt_textfield || 'subject';
if ($textfield eq 'subject') {
$keyhook = 's/re:\s+//i';
}
$sort_method = \&sortbytext;
}
if (scalar(@opt_src) < 1) {
im_die("must specify one or more folders.\n");
} else {
if (scalar(@opt_src) != 1) {
im_die("must specify just one folder.\n");
}
$_ = $opt_src[0];
if (/^[+=]/) {
require IM::Folder && import IM::Folder;
&local_files($datefield, $textfield, $keyhook,
$sort_method, $_, @ARGV);
} else {
im_die("doesn't support $opt_src\n");
}
exit $EXIT_SUCCESS;
}
sub sortbynum {
$sortkey{$a} <=> $sortkey{$b} or $msgdate{$a} <=> $msgdate{$b};
}
sub sortbytext {
$sortkey{$a} cmp $sortkey{$b} or $msgdate{$a} <=> $msgdate{$b};
}
sub sortbydate {
$msgdate{$a} <=> $msgdate{$b};
}
sub local_files {
my ($datefield, $textfield, $keyhook, $method, $folder, @arg) = @_;
my (%Head) = ();
my ($num);
my (@list, @sorted) = ();
local (%sortkey, %msgdate) = (); # XXX
$datefield = 'date:' unless defined($datefield);
foreach $num (get_message_paths($folder, @arg)) {
if (-f $num) {
%Head = &get_header($num);
if (defined($textfield)) {
$_ = $Head{$textfield};
if (defined($keyhook)) {
eval($keyhook);
}
$sortkey{$num} = $_;
}
;# always
$msgdate{$num} = datetm($Head{$datefield});
push(@list, $num);
}
}
$method = \&sortbytext unless defined($method);
@sorted = sort {&{$method}} @list;
&renumber_messages(\@sorted, \@list);
}
;# renumber @{$cur} to @{$new}
sub renumber_messages {
my ($cur, $new) = @_;
my (%tmp);
my ($n);
if ($#{$cur} != $#{$new}) {
im_die("array size not match $#{$cur} != $#{$new}\n");
}
foreach (@{$cur}) {
$tmp{$_} = $_;
}
;# cur[$n]: current nth filename
;# new[$n]: desired nth filename
;# tmp{$num}: actual current $num's filename
for ($n = 0; $n <= $#{$cur}; $n++) {
if ($cur->[$n] ne $new->[$n]) {
;# $cur->[$n] should be renamed to $new->[$n]
print "$cur->[$n] => $new->[$n]\n" if $opt_verbose;
if (defined($tmp{$new->[$n]})) {
# but $new->[$n] still exits, so save as .tmp
# record this file is now .tmp
$tmp{$new->[$n]} .= '.tmp';
&renamefile($new->[$n], $tmp{$new->[$n]});
}
# at this point, $new->[$n] is no longer exists (already moved)
# or move to .tmp now, so we can rename $cur->[$n] to $new->[$n]
&renamefile($tmp{$cur->[$n]}, $new->[$n]);
# mark $cur->[$n] is done, moved to $new->[$n]
delete $tmp{$cur->[$n]};
}
}
}
sub renamefile {
my ($a, $b) = @_;
if ($opt_noharm) {
print "mv $a $b\n";
} else {
rename($a, $b) || die;
}
}
sub uniq {
my @array = @_;
my %hash;
foreach (@array) {
$hash{$_} = $_;
}
return keys %hash;
}
-------------- next part --------------
## Date.pm
## Copyright (c) 1997 UKAI Fumitoshi
##
my $VERSION = "IM:Date.pm @im_cv_version@";
package IM::Date;
require Exporter;
use IM::Config;
use IM::Debug;
use IM::ErrorReport;
use Time::Local;
@ISA = qw(Exporter);
@EXPORT = qw(datetm);
=head1 NAME
Date - RFC822 style date parser
=head1 SYNOPSIS
use IM::Date;
$t = datetm($datefield);
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
localtime($t);
=head1 DESCRIPTION
datetm returns a time as returned by the time function,
the number of non-leap seconds since whatever time the
system considers to be the epoch (that's 00:00:00 UTC, January 1,
1970.)
=cut
@dstrs = ('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun');
$dstrpat = join('|', @dstrs);
@mstrs = ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec');
$mstrpat = join('|', @mstrs);
%zone = (
'UT' => 0,
'GMT' => 0,
'EST' => (-5 * 60),
'EDT' => (-4 * 60),
'CST' => (-6 * 60),
'CDT' => (-5 * 60),
'MST' => (-7 * 60),
'MDT' => (-6 * 60),
'PST' => (-8 * 60),
'PDT' => (-7 * 60),
'JST' => (9 * 60), # non-standard, but used by old(?) mailer
);
$zonepat = join('|', keys %zone, 'A-IK-Z', '[-+]\d{4}');
sub datetm {
my ($d) = @_;
my $date = {};
$d =~ s/\(.*?\)/ /g; # remove comments
$d =~ s/\n/ /g;
if ($d =~ s/^\s*($dstrpat)\s*,\s*//i) {
$date->{'wday'} = $1;
}
if ($d =~ /^\s*(\d{1,2})\s+($mstrpat)\s+(\d{2,4})\s+(\d{2}):(\d{2}):(\d{2})\s+(\S*)\s*$/i) {
$date->{'mday'} = $1;
$date->{'mon'} = &mstr2num($2);
$date->{'year'} = $3;
$date->{'hours'} = $4;
$date->{'min'} = $5;
$date->{'sec'} = $6;
my $tz = $7;
if ($tz =~ /$zonepat/) {
$date->{'tzoffset'} = &tz2num($tz);
} else {
$date->{'tzoffset'} = 0; # XXX
}
} else {
&error_log(0, "illegal format for date: $d\n");
return 0;
}
return timegm($date->{'sec'}, $date->{'min'}, $date->{'hours'},
$date->{'mday'}, $date->{'mon'}-1, $date->{'year'})
- ($date->{'tzoffset'} * 60);
}
sub mstr2num {
my ($mstr) = @_;
my ($m) = 1;
foreach (@mstrs) {
if ($mstr =~ /$_/i) {
return $m;
}
++$m;
}
return 0; # /* illegal? */
}
sub tz2num {
my ($tzstr) = @_;
$tzstr = uc($tzstr);
if (defined($zone{$tzstr})) {
return $zone{$tzstr};
} elsif ($tzstr =~ /A-IK-Z/) {
;# draft-ietf-drums-msg-fmt-02.txt says
;# mil timezones SHOULD all be considered equivalent to "-0000".
return 0;
my ($m) = ord($tzstr);
if ($m == ord('Z')) {
return 0;
} elsif ($m < ord('J')) {
return -1 * ($m - ord('A') + 1) * 60;
} elsif ($m < ord('M')) {
return -1 * ($m - ord('A')) * 60;
} else {
return ($m - ord('M')) * 60;
}
} elsif ($tzstr =~ /([+-])(\d{2})(\d{2})/) {
my $sign = 1;
$sign = ($1 eq '+') ? 1 : -1;
return $sign * $2 * 60 + $3;
}
;# draft-ietf-drums-msg-fmt-02.txt
;# Any unknown time zone specification SHOULD be considered equivalent
;# too "-0000".
return 0;
}
1;
Mew-dist メーリングリストの案内