Perl 小品集 ─ fview2

#!/usr/bin/perl
# fview2.pl
# 簡易ファイル閲覧ユティリティ
# Perl モジュール Term::ReadKey が必要

# モジュールの宣言
use Term::ReadKey;
# ReadKey モード
# 0        restore
# 1        normal
# 2        noecho
# 3        cbreak
# 4        raw
# 5        ultra-raw

# global value  
#   %progs   ファイルタイプとそれを動かすプログラムの対応表
#   @list    ディレクトリに含まれるファイル名のリスト 
#   @history ディレクトリのヒストリーを保存
#   $root    作業中のディレクトリ
#   $sum     ディレクトリに含まれるファイルの総数
#   $pages   ファイルを表示する場合のページ数

# 表示パネルのデフォルト
$max = 40;          # ページあたりのファイル数
$offset_row = 2;    # オフセット
$offset_col = 1;
$width = 80;        # スクリーンの幅
$col_space = 40;    # 左右の欄の間隔
$park_row = 22;     # 修了時のカーソル位置
$park_col = 1;

# ファイルタイプとそれを表示するプログラムを定義する
%progs = (
    cgi => vedit,
    conf => xz,
    html => xz,
    pl => xz,
    shtml => xz,
    txt => xz,
    bmp => ee,
    gif => ee,
    png => ee,
    jpg => ee,
    tif => ee,
    pdf => acroread,
    mp3 => mpg123,
    mpg => mtvp,
    mid => timidity,
    rmi => timidity
    );

($root) = @ARGV;
# 現在のディレクトリとそのファイル情報を得る
if ($root eq "") {
    ($root) = `pwd`;
    }
chomp $root;
$page = 1;
# ヒストリーの保存
push @history, $root;
push @history, $page;
&get_list;
$page = 1;
&show_list ($page);
$n = 0;
$row = $offset_row;
$col = $offset_col;
print "\033[$row;$col\H\033[7m .. \033[0m";
&select ($page, $n);
exit 0;

# 指定したディレクトリのファイル情報を得る
sub get_list {
    local (@dot_list, @file_list, $entry);
    # リストの初期化
    $list = "";
    # ドットファイルを得る
    @dot_list = glob "$root/.*";
    # 通常のファイルを得る
    @file_list = glob "$root/*";
    $sum = 0;
    # ディレクトリを得る
    foreach $entry (@dot_list) {
        if (-d $entry) {
            $entry =~ /([^\/]+)$/;
            if ($1 ne '.') {
                $list [$sum] = $1;
                $sum++;
                }
            }
        }
    foreach $entry (@file_list) {
        if (-d $entry) {
            $entry =~ /([^\/]+)$/;
            $list [$sum] = $1;
            $sum++;
            }
        }
    # ファイルの場合
    foreach $entry (@dot_list) {
        if (-f $entry) {
            $entry =~ /([^\/]+)$/;
            $list [$sum] = $1;
            $sum++;
            }
        }    
    foreach $entry (@file_list) {
        if (-f $entry) {
            $entry =~ /([^\/]+)$/;
            $list [$sum] = $1;
            $sum++;
            }
        }    
    # ファイルのリストが多い場合、複数ページにわける
    if ($sum > $max){
        $pages = int ($sum / $max);
        if ($sum % $max > 0) {
            $pages = $pages + 1;
            }
        }
    else {
        $pages = 1;
        }
}

# ディレクトリの移動、ファイルの選択
sub select {
    local ($page, $n) = @_;
    ReadMode 3;        # cbreak
    $key = ReadKey;
    # プログラムによって書き込まれたメッセージを消す
    print "\033[2K";
    # 反転表示していたファイルを通常の表示にもどす
    &hilite ($page, $n, 0);
    # ファイルの最後を計算
    if ($page < $pages) {
        $last = $max;
        }
    else {
        $last = $sum - $max * ($page - 1);
        }
    # 次は上記と同じ条件文
    # $last = $max * $page * ($page < $pages) + ($sum - $max * ($page - 1)) * ($page == $pages); # 終了番号
    # 入力されたキーの判定
    # ESC, q : 終了
    if ($key eq 'q' or $key eq 'Q') {
        ReadMode 0;        # restore
        print "\033[$park_row;$park_col\H";
        return;
        }
    # Enter : 表示
    elsif (ord $key == 10 or ord $key == 13) {
        ($page, $n) = &select_2 ($page, $n);
        }
    # 移動
    # BS : ヒストリーをさかのぼる
    elsif (ord $key == 8) {
        if (scalar @history > 0) {
            $page = pop @history;
            $root = pop @history;
            &get_list;
            &show_list ($page);
            $n = 0;
            }
        }
    # ↑ : 前のファイルへ
    elsif ($key eq 'A') {
        # 前のページに
        if ($n == 0 and $page > 1) {
            push @history, $root;
            push @history, $page;
            $page--;
            &show_list ($page);
            $n = $max - 1;
            }
        elsif ($n > 0) {
            $n--;
            }
        }
    # ↓ : 次のファイルへ
    elsif ($key eq 'B') {
        # 次のページに
        if (($n == $max - 1) and ($page < $pages)) {
            push @history, $root;
            push @history, $page;
            $page++;
            &show_list ($page);
            $n = 0;
            }
        elsif ($n < $last - 1) {
            $n++;
            }
        }
    # → : 次のページ
    elsif ($key eq 'C' and $page < $pages) {
        push @history, $root;
        push @history, $page;
        $page++;
        &show_list ($page);
        $n = 0;
        }
    # ← : 前のページ
    elsif ($key eq 'D') {
        # 1ページ目なら上位ディレクトリへ
        if ($page == 1) {
            push @history, $root;
            push @history, $page;
            $root =~ s/\/[^\/]+$//;
            &get_list;
            $page = 1;
            &show_list ($page);
            $n = 0;
            }
        elsif ($page > 1) {
            push @history, $root;
            push @history, $page;
            $page--;
            &show_list ($page);
            $n = 0;
            }
        }
    # 選んだファイルを反転表示する
    &hilite ($page, $n, 1);
    # ファイルを表示した場合、プログラムによって書き込まれるメッセージ
    # がファイル表示を妨げないよう、それを欄外に置く
    print "\033[$park_row;$park_col\H";
    &select ($page, $n);
}

sub select_2 {
    local ($page, $n) = @_;
    local $file = $list [$max * ($page - 1) + $n];
    # アクセス許可が無い場合
    if (!(-r "$root/$file")) {
        print "\033[$park_row;$park_col\H No Permissions!";
        return ($page, $n);
        }
    # 上位ディレクトリへの移動
    elsif ($file eq "..") {
        push @history, $root;
        push @history, $page;
        $root =~ s/\/[^\/]+$//;
        &get_list;
        $page = 1;
        ($last) = &show_list ($page);
        $n = 0;
        }
    # 下位ディレクトリへの移動
    elsif (-d "$root/$file") {
        push @history, $root;
        push @history, $page;
        $root = "$root/$file";
        &get_list;
        $page = 1;
        ($last) = &show_list ($page);
        $n = 0;
        }
    # ファイルの閲覧
    else {
        # ファイルを表示した場合、プログラムによって書き込まれるメッセージ
        # がファイル表示を妨げないよう、それを欄外に置く
        print "\033[$park_row;$park_col\H";
        # テキストファイルの場合
        if (-T "$root/$file") {
            system "xz '$root/$file'";
            }
        # その他のファイル
        else {
            $file =~ /\.([^\.]+)$/;
            $filetype = $1;
            foreach $type (%progs) {
                if ($type eq $filetype) {
                    $program = $progs{$type};
                    system "$program '$root/$file'";
                    last;
                    }
                }
            }
        }
    return ($page, $n);
}

# ファイル名のハイライト
sub hilite {
    local ($file, $p_row, $p_col);
    local ($page, $n, $key) = @_;
    $file = $list [$max * ($page - 1) + $n];
    $p_row = $offset_row + $n - (($max / 2) * ($n >= $max / 2));
    $p_col = $offset_col + $col_space * ($n >= $max / 2);
    # ハイライトにする場合
    if ($key == 1) {
        print "\033[$p_row;$p_col\H\033[7m $file \033[0m";
        }
    # もとにもどす場合
    # アクセス禁止ファイル
    elsif (!(-r "$root/$file")) {
        print "\033[$p_row;$p_col\H\033[31m $file \033[0m";
        }
    # ディレクトリ
    elsif (-d "$root/$file") {
        print "\033[$p_row;$p_col\H\033[34m $file \033[0m";
        }
    # その他のファイル
    else {
        print "\033[$p_row;$p_col\H $file ";
        }
}

# ディレクトリ、ファイルのページごとのリスト
sub show_list {
    local ($line, $i, $row, $col, $start, $last, $p_root, $title_name, $name);
    local ($page) = @_;
    # スクリーンの初期化とタイトルの表示
    if ($root eq "") {
        $p_root = "/";
        }
    else {
        $p_root = $root;
        }
    if ($pages > 1) {
        $title_name = " FileView ($p_root) $page/$pages ";
        }
    else {
        $title_name = " FileView ($p_root) ";
        }
    print "\033[2J\033[1;0H";
    $line = int(($width - length ($title_name)) / 2);
    $i = 0;
    while ($i < $line){
        print '=';
        $i++;
        }
    print $title_name;
    $i = $i + length ($title_name);
    while ($i < $width){
        print '=';
        $i++;
        }
    # リストの表示
    $start = $max * ($page - 1);    # 開始番号
    $last = $max * $page * ($page < $pages) + $sum * ($page == $pages); # 終了番号
    $row = $offset_row;             # 開始位置
    $col = $offset_col;
    while ($start < $last){
        ($name) = &print_name ($list [$start++]);
                                    # 欄の折り返し
        if ($row == $offset_row + $max / 2) {
            $row = $offset_row;
            $col = $offset_col + $col_space;
            }
        print "\033[$row;$col\H $name";
        $row++;
        }
    return;
}

# 表示名の調整
sub print_name {
    local (@letters, $i, $p_name);
    local ($name) = @_;
    # ファイル名が長い場合、それを短くして表示する
    if ((length ($name)) > $col_space - 5) {
        @letters = split //, $name;
        $p_name = "";
        $i = 0;
        while ($i < $col_space - 5){
            $p_name = "$p_name$letters[$i++]";
            }
        $p_name = "$p_name...";
        }
    else {
        $p_name = $name;
        }
    # アクセス禁止ファイル
    if (!(-r "$root/$name")) {
        $p_name = "\033[31m$p_name\033[0m";
        }
    # ディレクトリーのカラー表示
    elsif (-d "$root/$name") {
        $p_name = "\033[34m$p_name\033[0m";
        }
    return $p_name;
}


[INDEX]