Skip to content

Instantly share code, notes, and snippets.

@harasakih
Last active January 13, 2022 13:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save harasakih/0f2a95e7945856d1c68e531c31684156 to your computer and use it in GitHub Desktop.
Save harasakih/0f2a95e7945856d1c68e531c31684156 to your computer and use it in GitHub Desktop.
#!/usr/bin/perl
#
# ファイルあるいはディクレトリ下全ファイルを対象に、検索・置換する
# =ディレクトリ指定時は、1階層下まで。再起検索はしない。
# = ".." '..' `..` は検索・置換の対象外
# = HS|HR は検索・置換対象を16進で指定する
#
###########################################################
# Next TODO
# 1. 16進モード時は、置換前後の表示を16進数に変更する
###########################################################
# package Replace
# Public-VAL
# $LogLevel : ログ出力レベル、dbglog()でSTDERRへ出力
# @Srch : 検索対象語句
# @Repl : 置換語句
# @SrchF : 検索したファイル一覧
# @MatchF : 検索にマッチしたファイル一覧
# $FdOUT : 出力ファイルのFD。呼出側でオープンする。
# $FdLOG : ログファイルのFD。呼出側でオープンする。
#
use strict;
use warnings;
use File::Basename 'basename', 'dirname';
use Getopt::Long 'GetOptions';
# CONSTANT
my $version = "00.00";
my $revision = "20220111" ;
my $OK = 1;
my $NG = 0;
my $ModeSRCH = "S" ;
my $ModeREPL = "R" ;
my $ModeHS = "HS" ;
my $ModeHR = "HR" ;
# OPTIONS
my $Opthelp = 0 ; # FALSE
my $Optmode = ""; # S|R|HR|HS
my $Optsrch = "";
my $Optdir = "";
my $Optout = "";
my $Optlog = "";
my $Optsummary = 0; # FALSE
my $Optsrchdump = 0; # FALSE
my $Optloglevel = 1;
GetOptions(
'help' => \$Opthelp,
'mode=s' => \$Optmode,
'srch=s' => \$Optsrch,
'dir=s' => \$Optdir,
'out=s' => \$Optout,
'log=s' => \$Optlog,
'summary' => \$Optsummary,
'srchdump' => \$Optsrchdump,
'LL=i' => \$Optloglevel
);
# ---------------------------------------------------------
package Replace;
# ---------------------------------------------------------
# Public-VAL
our $Loglevel = 0; # DBGログの出力レベル
our @Srch; # 検索対象HEX-VALの配列
our @Repl; # 置換後HEX-VALの配列
our @SrchF; # 検索したファイル名の配列
our @MatchF; # マッチしたファイル名の配列
our $FdOUT; # 出力ファイルのFD
our $FdLOG; # ログファイルのFD
our $Mode; # 動作モード S(earch)|R(eplace)
our $DnOUT; # 出力ディレクトリ
#############################
# SHARED only package
#############################
# LOG-LEVEL
my $Ldie = 0;
my $Lerr = 1;
my $Linf = 3;
my $Ldbg = 5;
my $Lfnc = 6;
my @Msgtag = ("DIE", "ERR", "2", "INF", "4", "DBG", "FNC", "7");
my $Fn = ""; # 処理中ファイル名
my $Lno = 0; # 処理中行番号
my $TokenNo = 0; # 処理中のトークン番号
#
#################################################
# dbglog : STDERRに出力する
# -- PARM --
# $msglevel i : @msgの出力レベル、$Loglevelより小さ時に出力する
# @msg i : 出力MSGの配列
# -- RETURN --
# $OK
#################################################
sub dbglog {
my ($msglevel, @msg) = @_;
# my $myfunc = (caller(0))[3]; print "$myfunc\n";
#
($msglevel > 7 || $msglevel < 0) && die "!!DIE msglevel invalid:$msglevel:$!";
if($msglevel <= $Loglevel) {
foreach my $msg(@msg) {
printf STDERR ("!!%s:%s\n", $Msgtag[$msglevel], $msg);
}
}
return $OK;
}
#################################################
# make_Srch : 検索ファイルをOPEN/CLOSEし、@Srch,@Replに設定する
# -- PARM --
# $fnSRCH i : 検索ファイルのファイル名
# $mode i : 検索(S)か、置換(R)か
# -- RETURN --
# $OK
# -- GLOVAL --
# @Srch G : 検索対象語句
# @Repl G : 置換先語句
#################################################
sub make_Srch {
my ($fnSRCH, $mode) = @_;
my $myfunc = (caller(0))[3]; &dbglog($Lfnc, "$myfunc");
##
open(SRCH, $fnSRCH) || die "!!DIE $fnSRCH:$!";
my $i = 0;
while( <SRCH> ) {
chomp;
my $l = $_;
next if ($l =~ /^#/); # コメント
next if ($l =~ /^\s*$/); # 空行
my @srch = split(/\s+/, $l);
if( $mode eq $ModeREPL ) {
# $# は配列の要素数ではなく、添字の最大数
$Srch[ $i ] = ($#srch >= 0) ? $srch[0] : "";
$Repl[ $i ] = ($#srch >= 1) ? $srch[1] : "";
$i++;
} elsif( $mode eq $ModeSRCH ) {
$Srch[ $i ] = ($#srch >= 0) ? $srch[0] : "";
$i++;
} elsif( ($mode eq $ModeHR) &&
($srch[0] =~ /^[0-9a-f]+$/) && ($srch[1] =~ /^[0-9a-f]+$/) )
{
$Srch[ $i ] = ($#srch >= 0) ? $srch[0] : "";
$Repl[ $i ] = ($#srch >= 1) ? $srch[1] : "";
$i++;
} elsif( ($mode eq $ModeHS) &&
($srch[0] =~ /^[0-9a-f]+$/) )
{
$Srch[ $i ] = ($#srch >= 0) ? $srch[0] : "";
$i++;
} else {
die "!!DIE mode invalid $mode:$!";
}
}
close(SRCH);
return $OK;
}
#################################################
# srchdump : @Srch,@Replを、DBGログと、ログに出力する
# -- PARM --
# -- RETURN --
# $OK
# -- GLOVAL --
# $FdLOG G : ログフィルのFD
# @Srch G : 検索対象語句
# @Repl G : 置換先語句
#################################################
sub srchdump {
my $myfunc = (caller(0))[3]; &dbglog($Lfnc, "$myfunc");
# STDERRへ出力
&dbglog($Linf, ("--- SRCH ---", @Srch));
&dbglog($Linf, ("--- REPL ---", @Repl));
# LOGへ出力
print $FdLOG "--- SRCH ---\n";
foreach my $s(@Srch) {
print $FdLOG "$s\n";
}
print $FdLOG "--- REPL ---\n";
foreach my $r(@Repl) {
print $FdLOG "$r\n";
}
#
return $OK;
}
#################################################
# isclosed : ” ' ` の数を数え、ペアになっていつかチェックする
# -- PARM --
# $line i : チェック対象
# -- RETURN --
# $OK o : ペアになっている時
# $NG o : ペアでない時
# -- GLOVAL --
#################################################
sub isclosed {
my ($line) = @_;
# my $myfunc = (caller(0))[3]; &dbglog($Lfnc, "$myfunc");
# QUOTE,APOSTの数を数えて、非閉を検知する
my $nquote = 0; # "の数
my $napost = 0; # ’の数
my $backquote = 0; # `の数
# 引用符の数をカウントする
$nquote++ while $line =~ /"/g;
$napost++ while $line =~ /'/g;
$backquote++ while $line =~ /`/g;
if( ($nquote % 2 != 0) || ($napost % 2 != 0) || ($backquote %2 != 0) ) {
return $NG;
} else {
return $OK;
}
}
#################################################
# delpairsub : $aのペア部分を削除する
# -- PARM --
# $line i : 処理対象の文字列
# $a i : ペアとする文字
# -- RETURN --
# $cnt o : 削除したペアの数
# $retstr o : $lineから、ペアを削除した文字列
# @pair o : $lineから抽出したペアを配列で持つ
# -- GLOVAL --
#################################################
sub delpairsub {
my ($line, $a) = @_;
my $myfunc = (caller(0))[3]; &dbglog($Lfnc, "$myfunc");
#
my @pair = ();
my $retstr = "";
my $cnt = 0;
# $aのペアを検索する、最短一致なので ? を付加
$_ = $line;
while( /$a.*?$a/ ) { # 最短一致を繰り返す
$cnt++;
my $str =$&; # 一致した文字列
$retstr .= $`; # 一致より前(一致しない部分) を 連結
push(@pair, $str); # 一致した文字列 を PUSH
$_ = $'; # 一致した残りを次に検索する
}
$retstr .= $_; # 最後に一致しなかった残り を 連結
return ($cnt, $retstr, @pair);
}
#################################################
# delpair : ” ' ` のペアを削除する
# -- PARM --
# $line i : 処理対象の文字列
# -- RETURN --
# $n o : 削除したペアの数
# $retline o : $lineから、ペアを削除した文字列
# @pair o : $lineから抽出したペアを配列で持つ
# -- GLOVAL --
#################################################
sub delpair {
my ($line) = @_;
my $myfunc = (caller(0))[3]; &dbglog($Lfnc, "$myfunc");
#
my $cnt = 0;
my @pair = ();
my @a = ();
# delete-pair
my $retline = $line; # 削除後ライン
my $n = 0; # 削除した数
# 削除して $n を加算して ペア部分をpush
($cnt, $retline, @a) = &delpairsub($retline, "\"") ; $n += $cnt; push(@pair, @a);
($cnt, $retline, @a) = &delpairsub($retline, "\'") ; $n += $cnt; push(@pair, @a);
($cnt, $retline, @a) = &delpairsub($retline, "\`") ; $n += $cnt; push(@pair, @a);
#
return ($n, $retline, @pair);
}
#################################################
# getpairsub : $aのペア部分を抽出する
# -- PARM --
# $line i : 処理対象の文字列
# $a i : ペアとする文字
# -- RETURN --
# $cnt o : 削除したペアの数
# @pair o : $lineから抽出したペアを配列で持つ
# -- GLOVAL --
#################################################
sub getpairsub {
my ($line, $a) = @_;
my $myfunc = (caller(0))[3]; &dbglog($Lfnc, "$myfunc");
#
my @pair = ();
my $cnt = 0;
# QUOTEの検索
$_ = $line;
while( /$a.*?$a/ ) { # 最短一致を繰り返す
$cnt++;
my $str =$&; #  一致した文字列
push(@pair, $str);
$_ = $'; #  一致した残りを次に検索する
}
return ($cnt, @pair);
}
#################################################
# replaceL : $lineを $from を $to に置換する、引用符内も置換する
# 通常文字列版
# -- PARM --
# $line i : 処理対象の文字列
# $from i : 置換元
# $to i : 置換先
# -- RETURN --
# $cnt o : 置換した数
# $modline o : 置換後の文字列
# -- GLOVAL --
#################################################
sub replaceL {
my ($line, $from, $to) = @_;
my $myfunc = (caller(0))[3]; &dbglog($Lfnc, "$myfunc");
#
my $ll = length($line);
my $lF = length($from);
my $lT = length($to);
my $cnt = 0;
# $modlineを書き換えるので、初期値設定
my $modline = $line;
for(my $ii = 0; $ii <= $ll - $lF; ){
if(substr($modline, $ii, $lF) eq $from) {
# 置換対象があった場合、置換前の行を初回のみ出力する
&dbglog($Ldbg, "$Fn($Lno)($from,TK=$TokenNo,OF=,LN=):$modline") if ($cnt == 0) ;
$cnt++;
my $offset = $ii;
my $tmp1 = substr($modline, 0, $offset); # 一致部分より前
my $tmp2 = substr($modline, $offset + $lF); # 一致した部分より後ろ
$modline = $tmp1 . $to . $tmp2; # 前 + 置換後 + 後
$ii += $lT; # 次の検索開始位置は、置換後文字列分分インクリメント
$ll = length($modline); # ストッパーを再計算する
# 置換ごとに出力
&dbglog($Ldbg, "$Fn($Lno)($from,TK=$TokenNo,OF=$offset,LN=$lT):$modline");
} else {
$ii += 1; # 通常文字列なので、+1インクリメント
}
}
return ($cnt, $modline);
}
#################################################
# replaceLH : 16進文字列の$lineを $from を $to に置換する、引用符内も置換する
# 16進文字列版
# -- PARM --
# $line i : 処理対象の文字列
# $from i : 置換元
# $to i : 置換先
# -- RETURN --
# $cnt o : 置換した数
# $modline o : 置換後の文字列
# -- GLOVAL --
#################################################
sub replaceLH {
my ($line, $from, $to) = @_;
my $myfunc = (caller(0))[3]; &dbglog($Lfnc, "$myfunc");
#
my $ll = length($line);
my $lF = length($from);
my $lT = length($to);
my $cnt = 0;
# $modlineを書き換えるので、初期値設定
my $modline = $line;
for(my $ii = 0; $ii <= $ll - $lF; ){
if(substr($modline, $ii, $lF) eq $from) {
# 置換対象があった場合、置換前の行を初回のみ出力する
&dbglog($Ldbg, "$Fn($Lno)($from,TK=$TokenNo,OF=,LN=):$modline") if ($cnt == 0) ;
$cnt++;
my $offset = $ii;
my $tmp1 = substr($modline, 0, $offset); # 一致より前の部分
my $tmp2 = substr($modline, $offset + $lF); # 一致より後ろの部分
$modline = $tmp1 . $to . $tmp2; # 前 + 置換度 + 後
$ii += $lT; # 次の検索開始位置は、置換後の長さをインクリメント
$ll = length($modline); # ストッパーを再計算
# 置換ごとに出力
my $offset2 = $offset / 2; # 16進は÷2
my $lT2 = $lT / 2; # 16進は÷2
&dbglog($Ldbg, "$Fn($Lno)($from,TK=$TokenNo,OF=$offset2,LN=$lT2):$modline");
} else {
$ii += 2; # 16進は、2バイトインクリメント
}
} # 1-line
return ($cnt, $modline);
}
#################################################
# replaceF : ファイル単位に、@Srch を @Repl に置換する
# -- PARM --
# $fname i : 処理対象のファイル名
# $mode i : R|HR
# -- RETURN --
# $OK
# -- GLOVAL --
# @Srch G : 置換元
# @Repl G : 置換先
# $Fn G : 処理対象ファイル名
# $Lno G : 処理対象行番号
# @SrchF G : 検索対象のファイル名
# @MatchF G : 置換を行なったファイル名
#################################################
sub replaceF {
my ($fname, $mode) = @_; # 引数の取得
my $myfunc = (caller(0))[3]; &dbglog($Lfnc, "$myfunc");
#
my $srch_cnt = @Srch; # @SRchの要素数
# Open IN-file
open(IN, $fname) || die "!!DIE $fname:$!";
binmode(IN);
$Fn = $fname;
# Open OUT-file
my $outbasen = File::Basename::basename $Fn;
my $path = $DnOUT . "/" . $outbasen;
if (-f $path) {
die "!!DIE outfile exist,$path:$!";
} else {
open(OUT, ">$path") || die "!!DIE open,$path:$!" ;
binmode(OUT);
&dbglog($Linf,("processing in $myfunc,$fname -> $path"));
}
push(@SrchF, $fname); # 検索対象ファイル名のプッシュ
my $match = 0; # ファイル単位でマッチしたか
# LOOP until EOF
while( <IN> ) {
chomp; # 改行は検索対象外。xx80 0Aを除くため
my $line = $_; # 入力行
my $lno = $.; # 入力ファイルの行番号
$Lno = $lno;
####################################
# ペアが閉じていない時は、ログ出力して次行へ
####################################
if(&isclosed($line) == $NG) {
print $FdLOG "$fname($lno)!:$line\n";
next;
}
####################################
# $line -> @token -> 置換 -> @token2
# 引用符内は置換しない。
####################################
my @token = &parseline($line);
my $scnt = 0; # 1行内の置換箇所数
my @token2 = (); # 置換後の token
my $ntoken = 0; # 処理中のトークン番号
foreach my $t(@token) {
my $tt = $t;
$TokenNo = $ntoken;
if( $tt =~ /["'`][^"'`]*["'`]/ ) {
# 引用符の時は、トークンをそのまま @token2にpush
push(@token2, $tt);
} elsif($mode eq $ModeREPL) {
# 引用符以外&通常文字列の時は、$ttを置換して @token2にpush
# 通常の文字列の時
my $cnt = 0;
for(my $i = 0; $i < $srch_cnt; $i++) {
my $srchword = $Srch[$i];
my $replword = $Repl[$i];
($cnt, $tt) = &replaceL($tt, $srchword, $replword);
$scnt += $cnt;
} # every srch work
push(@token2, $tt);
} elsif($mode eq $ModeHR) {
# 引用符以外の時&16進文字列は、$ttをPACK&置換し・UNPACKして @token2にpush
# 16進の時
my $cnt = 0;
my $hexstr = unpack("H*", $tt);
# print "UNP>:$Fn($Lno)$srch_cnt:$tt\n" ;
# print "DBG>:$Fn($Lno)$srch_cnt:$hexstr\n" ;
for(my $i = 0; $i < $srch_cnt; $i++) {
my $srchword = $Srch[$i];
my $replword = $Repl[$i];
($cnt, $hexstr) = &replaceLH($hexstr, $srchword, $replword);
$scnt += $cnt ;
} # every srchsword
# print "DBG<:$Fn($Lno)$cnt:$hexstr\n" ;
$tt = pack("H*",$hexstr) ;
# print "PACK:$Fn($Lno)$cnt:$tt\n" ;
push(@token2, $tt);
}
$ntoken++;
} # every token
####################################
# @token2 -> $line2
####################################
my $line2 = "";
foreach my $t(@token2) {
$line2 .= $t;
}
####################################
# 置換があった時は、ログ出力
####################################
if($line2 ne $line) {
$match = 1 ;
print $FdLOG "$fname($lno)R>:$line\n";
print $FdLOG "$fname($lno)R<:$line2\n";
}
print OUT "$line2\n";
} # while <>
if($match != 0) { push(@MatchF, $fname); }
# Close IN-file
close(IN);
close(OUT);
return $OK;
}
#################################################
# searchL : $lineを $srchで検索する
# -- PARM --
# $line i : 処理対象の文字列
# $srch i : 検索対象
# -- RETURN --
# $cnt o : ヒットした数
# $line o : 処理対象をそのまま返却
# -- GLOVAL --
#################################################
sub searchL {
my ($line, $srch) = @_;
# my $myfunc = (caller(0))[3]; &dbglog($Lfnc, "$myfunc");
#
my $ll = length($line);
my $lS = length($srch);
my $cnt = 0;
for(my $ii = 0; $ii <= $ll - $lS; ){
if(substr($line, $ii, $lS) eq $srch) {
$cnt++;
my $offset = $ii;
$ii += $lS;
# 検索ごとにDBG出力
&dbglog($Ldbg, "$Fn($Lno)($srch,TK=$TokenNo,OF=$offset,LN=$lS):$line");
} else {
$ii += 1; # 通常文字列なので、1バイトづつインクリメント
}
} # 1-line
return ($cnt, $line);
}
#################################################
# searchLH : 16進文字列 $lineを $srchで検索する
# -- PARM --
# $line i : 処理対象の文字列
# $srch i : 検索対象
# -- RETURN --
# $cnt o : ヒットした数
# $line o : 処理対象をそのまま返却
# -- GLOVAL --
#################################################
sub searchLH {
my ($line, $srch) = @_;
# my $myfunc = (caller(0))[3]; &dbglog($Lfnc, "$myfunc");
#
my $ll = length($line);
my $lS = length($srch);
my $cnt = 0;
for(my $ii = 0; $ii <= $ll - $lS; ){
if(substr($line, $ii, $lS) eq $srch) {
$cnt++;
my $offset = $ii / 2;
my $lS2 = $lS / 2;
# 検索ごとにDBG出力
&dbglog($Ldbg, "$Fn($Lno)($srch,TK=$TokenNo,OF=$offset,LN=$lS2):$line");
$ii += $lS; # 検索の16進文字列分インクリメント
} else {
$ii += 2; # 16進文字列なので、2バイトインクリメント
}
} # 1-line
return ($cnt, $line);
}
#################################################
# searchF : ファイル単位に、@Srch を 検索する。引用符ないは検索しない
# -- PARM --
# $fname i : 処理対象のファイル名
# -- RETURN --
# $OK
# -- GLOVAL --
# @Srch G : 検索対象
# $Fn G : 処理対象ファイル名
# $Lno G : 処理対象行番号
# @SrchF G : 検索対象のファイル名
# @MatchF G : 置換を行なったファイル名
#################################################
sub searchF {
my ($fname, $mode) = @_; # 引数の取得
my $myfunc = (caller(0))[3]; &dbglog($Lfnc, "$myfunc");
#
my $srch_cnt = @Srch; # @SRchの要素数
# Open IN-file
open(IN, $fname) || die "!!DIE $fname:$!";
binmode(IN);
&dbglog($Linf,("processing in $myfunc,$fname"));
$Fn = $fname;
#
push(@SrchF, $fname); # 検索対象ファイル名のプッシュ
my $match = 0; # ファイル単位でマッチしたか
# LOOP until EOF
while( <IN> ) {
chomp; # 改行は検索対象外。xx80 0Aを除くため
my $line = $_; # 入力行
my $lno = $.; # 入力ファイルの行番号
$Lno = $lno;
####################################
# ペアが閉じていない時は、ログ出力して次へ
####################################
if(&isclosed($line) == $NG) {
print $FdLOG "$fname($lno)!:$line\n";
next;
}
####################################
# $line -> @token -> 検索
# 引用符内は検索しない。
####################################
my @token = &parseline($line); # 引用符/非引用符に分解
my $scnt = 0; # 1行内の検索ヒット数
my $ntoken = 0; # 処理中トークン番号
my @match = (); # 検索にマッチした文字列
foreach my $t(@token) {
my $tt = $t;
$TokenNo = $ntoken;
if( $tt =~ /["'`][^"'`]*["'`]/ ) {
# 引用符の時は、次へ
$ntoken++;
next;
} elsif($mode eq $ModeSRCH) {
# 引用符以外の時 & 通常の文字列の時
my $cnt = 0;
for(my $i = 0; $i < $srch_cnt; $i++) {
my $srchword = $Srch[$i];
($cnt, $tt) = &searchL($tt, $srchword);
$scnt += $cnt;
push(@match, $srchword) if($cnt != 0) ;
} # every srchword
# 引用符以外の時 & 16進の時
# UNPACKして検索
} elsif ($mode eq $ModeHS){
my $cnt = 0;
my $hexstr = unpack("H*", $tt) ;
# print "UNP>:$Fn($Lno)$srch_cnt:$tt\n" ;
# print "DBG>:$Fn($Lno)$srch_cnt:$hexstr\n" ;
for(my $i = 0; $i < $srch_cnt; $i++) {
my $srchword = $Srch[$i]; # 検索16進
($cnt, $hexstr) = &searchLH($hexstr, $srchword);
$scnt += $cnt;
push(@match, $srchword) if($cnt != 0);
} # every srchword
# print "DBG<:$Fn($Lno)$cnt:$hexstr\n" ;
$tt = pack("H*",$hexstr) ;
# print "PACK:$Fn($Lno)$cnt:$tt\n" ;
} # $mode
$ntoken++;
} # every token
####################################
# 検索がヒットしたら、ログ出力
####################################
if($scnt != 0) {
$match = 1 ;
print $FdLOG "$fname($lno)S :";
foreach my $m(@match) {
print $FdLOG "$m ";
}
print $FdLOG "\n";
}
} # while <>
if($match != 0) { push(@MatchF, $fname); }
# Close IN-file
close(IN);
return $OK;
}
#################################################
# recursiveD : ディレクトリ配下の全ファイルを処理する
# -- PARM --
# $dname i : ディレクトリ名
# $mode i : S(earch)|R(eplace)
# -- RETURN --
# $OK
# $NG : パラメタエラー時
# -- GLOVAL --
#################################################
sub recursiveD {
my ($dname, $mode) = @_; # 引数の取得
my $myfunc = (caller(0))[3]; &dbglog($Lfnc, "$myfunc");
#
opendir(DIR1, $dname) || die "!!DIE $dname:$!";
LBL_DIR:
while(my $in_fname = readdir(DIR1)) {
my $fname = "$dname\/$in_fname";
next LBL_DIR if -d $fname; # ディレクトリは処理対象外
&dbglog($Ldbg,("processing in $myfunc,$fname")); # ファイルは処理対象
if ($mode eq $ModeREPL) { &replaceF( $fname, $mode ); }
elsif ($mode eq $ModeHR) { &replaceF( $fname, $mode ); }
elsif ($mode eq $ModeSRCH) { &searchF( $fname, $mode ); }
elsif ($mode eq $ModeHS) { &searchF( $fname, $mode ); }
else { die "!!DIE mode invalid,$mode:$!"; }
}
return $OK;
}
#################################################
# parseline : 引用符と引用符以外の部分に分解する
# -- PARM --
# $line i : 処理対象
# -- RETURN --
# @token : 分解結果
# -- GLOVAL --
#################################################
sub parseline {
my ($line) = @_;
# my $myfunc = (caller(0))[3]; &dbglog($Lfnc, "$myfunc");
#
my $cnt = 0;
my @token = ();
$_ = $line;
while( /["'`][^"'`]*?["'`]/ ) { # 最短一致を繰り返す
$cnt++;
my $pre = $`; # 一致した文字列より前
my $match =$&; #  一致した文字列
push(@token, ($pre,$match));
$_ = $'; #  一致した残りを次に検索する
}
if($cnt == 0) {
push(@token, $line); # マッチしていない時は、そのまま返却
} else {
push(@token, $_); # 最後に残りを追加
}
return (@token);
}
# ---------------------------------------------------------
package main;
# ---------------------------------------------------------
sub usage {
my $basename = basename $0;
print STDERR "\n";
print STDERR "usage: $basename Ver" . $version . "_Rev_" . $revision . "\n";
print STDERR "\n";
print STDERR "$basename --mode S|R|HS|HR --srch SRCH-FILE --dir SEARCHDIR|SEARCHFILE --out OUTDIR --log LOGFILE\n";
print STDERR " [--summary] [--srchdump: [--LL=n]\n";
print STDERR "\n";
print STDERR " --mode : S(earch) | R(eplace) | H(ex)S | H(ex)R \n";
print STDERR " --LL(Loglevel) $Lfnc:fn-trace $Ldbg:dbg $Linf:info $Lerr:err $Ldie:die \n";
print STDERR " --summary : print Searched-file Matched-file to STDOUT\n";
print STDERR " --srchdump : print SRCH-FILE to STDOUT\n";
print STDERR "....\n";
return $OK;
}
sub optdisp {
my $msgtag = ($Optloglevel =~ /^[0-7]$/) ? $Msgtag[$Optloglevel] : "" ;
if( $Optloglevel > 1) {
foreach my $msg (
"--- OPTIONS ---",
"mode=$Optmode" ,
"srch=$Optsrch" ,
"dir=$Optdir" ,
"out=$Optout" ,
"log=$Optlog" ,
"summary=$Optsummary",
"srchdump=$Optsrchdump",
"LL=$Optloglevel,$msgtag",
"---------------" )
{
print STDERR "$msg\n";
}
}
return $OK;
}
sub optck {
#
if ($Opthelp) {
&usage();
exit 1;
}
&optdisp();
#############################
# IN-CHECK
#############################
# Optmode
if ($Optmode eq $ModeSRCH) { $Replace::Mode = $ModeSRCH; }
elsif ($Optmode eq $ModeREPL) { $Replace::Mode = $ModeREPL; }
elsif ($Optmode eq $ModeHS) { $Replace::Mode = $ModeHS; }
elsif ($Optmode eq $ModeHR) { $Replace::Mode = $ModeHR; }
else { die "!!DIE invalid mode,$Optmode:$!"; }
# FILE,DIR
($Optsrch eq '') && &usage() && die "!!DIE SRCH-FILE is null:$!" ;
($Optdir eq '' ) && &usage() && die "!!DIE SEARCH DIR/FILE is null:$!" ;
($Optout eq '' ) && &usage() && die "!!DIE OUTDIR is null:$!" ;
($Optlog eq '') && &usage() && die "!!DIE LOG-FILE is null:$!" ;
#############################
# FILE-CHECK
#############################
# FILE-CHECK
(-f $Optsrch) || &usage() && die "!!DIE SRCH-FILE,$Optsrch:$!";
(-e $Optdir) || &usage() && die "!!DIE SEARECH DIR/FILE,$Optdir:$!";
(-d $Optout) || &usage() && die "!!DIE OUTDIR not found,$Optout:$!";
# loglevel
( $Optloglevel =~ /^[0-7]$/) || die "!!DIE LogLevel is 0-7,$Optloglevel:$!" ;
# (-f $fnLOG) || &usage() && die "!!DIE LOGFILE is exist:$!";
#############################
# CROSS-CHECK
#############################
# Optdir, Optout
(-d $Optdir && ($Optdir eq $Optout)) && die "!!DIE dir[$Optdir] must not same as out[$Optout]:$!" ;
my $dir = dirname $Optdir;
($dir eq $Optout) && die "!!DIE dir[$dir] must not same as out[$Optout]:$!" ;
$Replace::DnOUT = $Optout;
return $OK;
}
#############################
# main
#############################
sub main {
#
my $fnSRCH = $Optsrch;
my $srchdir = $Optdir;
my $fnOUT = $Optout;
my $fnLOG = $Optlog;
my $mode = $Optmode;
# Open outfile
open($FdLOG, ">$fnLOG") || die "!!DIE $fnLOG:$!";
# SRCH-FILE
(-f $fnSRCH) && &Replace::make_Srch( $fnSRCH, $mode );
( $Optsrchdump ) && &Replace::srchdump();
# MAIN
if( $mode eq $ModeREPL || $mode eq $ModeHR ) {
if (-f $srchdir) {
&Replace::replaceF( $srchdir, $mode ) || die "replaceF,dir=$srchdir,mode=$mode:$!";
} elsif (-d $srchdir) {
&Replace::recursiveD( $srchdir, $mode ) || die "recursiveD,dir=$srchdir,mode=$mode:$!";
} else {
die "!!DIE in main:$!";
}
} elsif( $mode eq $ModeSRCH || $mode eq $ModeHS ) {
if (-f $srchdir) {
&Replace::searchF( $srchdir, $mode ) || die "searchF,dir=$srchdir,mode=$mode:$!";
} elsif (-d $srchdir) {
&Replace::recursiveD( $srchdir, $mode ) || die "recursiveD,dir=$srchdir,mode=$mode:$!";
} else {
die "!!DIE in main:$!"
}
} else {
die "!!DIE mode invalid $mode:$!"
}
my $nSrchF = @SrchF;
my $nMatchF = @MatchF;
my $basename = basename $0;
print STDOUT "$basename Ver" . $version . "_Rev_" . $revision . "\n";
print STDOUT "mode=$Optmode\n" ;
print STDOUT "Searched file is : $nSrchF\n";
if( $Optsummary ) {
foreach my $s (@SrchF) {
print STDOUT " $s\n";
}
}
print STDOUT "Matched file is : $nMatchF\n";
if( $Optsummary ) {
foreach my $s (@MatchF) {
print STDOUT " $s\n";
}
}
# Close outfile
close($FdLOG);
return $OK;
}
# -----------------------------------------------------------
# コマンドラインスタート
# -----------------------------------------------------------
# optck is false. exit1
$Replace::Loglevel = $Optloglevel;
(&optck() == $NG) && &usage() && die "!!DIE option invalid:$!";
# SRCH-DUMP
&main();
1; # RETURN TRUE
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment