#!/usr/bin/perl
use
vars
qw($opt_a $opt_f $opt_o $opt_n $opt_t)
;
my
$Program
= basename($0);
sub
usage {
warn
"usage: $Program [-afo] [-n length] [-t {d|o|x}] [file ...]\n"
;
exit
EX_FAILURE;
}
getopts(
'afon:t:'
) or usage();
if
(
defined
$opt_n
) {
if
(
$opt_n
!~ m/\A[0-9]\Z/ ||
$opt_n
== 0) {
warn
"$Program: invalid minimum string length '$opt_n'\n"
;
exit
EX_FAILURE;
}
}
else
{
$opt_n
= 4;
}
if
(
$opt_o
) {
$opt_t
=
'o'
;
}
elsif
(
defined
$opt_t
) {
my
%EXPECT
= (
'd'
=> 1,
'o'
=> 1,
'x'
=> 1,
);
usage()
unless
$EXPECT
{
$opt_t
};
}
my
$offset_format
=
"\%07$opt_t "
;
my
$punctuation
=
join
'\\'
,
split
//,
q/`~!@#$%^&*()-+={}|[]\:";'<>?,.\/
/;
my
$printable
=
'\w \t'
.
$punctuation
;
my
$chunksize
= 4096;
for
my
$filename
(
@ARGV
)
{
next
if
-d
$filename
;
my
$in
;
unless
(
open
$in
,
'<'
,
$filename
) {
warn
"$Program: Can't open '$filename': $!\n"
;
exit
EX_FAILURE;
}
binmode
$in
;
scanfile(
$in
,
$filename
);
close
$in
;
}
unless
(
@ARGV
) {
scanfile(
*STDIN
,
'<stdin>'
);
}
exit
EX_SUCCESS;
sub
scanfile {
my
(
$fh
,
$filename
) =
@_
;
my
$offset
= 0;
while
(
$_
or
read
(
$fh
,
$_
,
$chunksize
))
{
$offset
+=
length
($1)
if
s/^([^
$printable
]+)//o;
my
$string
=
''
;
do
{
$string
.= $1
if
s/^([
$printable
]+)//o;
}
until
(
$_
or !
read
(
$fh
,
$_
,
$chunksize
));
if
(
length
(
$string
) >=
$opt_n
)
{
print
$filename
,
':'
if
$opt_f
;
printf
$offset_format
,
$offset
if
$opt_t
;
print
$string
,
"\n"
;
}
$offset
+=
length
(
$string
);
}
}