1#!/usr/local/bin/perl 2## 3## greple: grep with multiple keywords 4## 5## Copyright (c) 1991-2017 Kazumasa Utashiro 6## 7## Original: Mar 29 1991 8## 9;; our($VERSION) = q$Revision: greple,v 7.1$ =~ /(\d+\.\d+)/g; 10;; my $rcsid = q$Id: greple,v 7.1 2017/03/06 03:29:33 utashiro Exp $; 11## 12## Use and redistribution for ANY PURPOSE are granted as long as all 13## copyright notices are retained. Redistribution with modification 14## is allowed provided that you make your modified version obviously 15## distinguishable from the original one. THIS SOFTWARE IS PROVIDED 16## BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES ARE 17## DISCLAIMED. 18## 19 20use strict; 21use warnings; 22 23require 5.010; 24 25use File::stat; 26use IO::Handle; 27use Pod::Usage; 28use Text::ParseWords qw(shellwords); 29use List::Util qw(min max first sum); 30use Scalar::Util qw(blessed); 31use Cwd qw(getcwd abs_path); 32use Data::Dumper; 33use Carp; 34 35use utf8; 36use Encode; 37use Encode::Guess; 38 39## 40## Setting utf8 warnings fatal makes it easy to find code conversion 41## error, so you can choose appropreate file code or automatic code 42## recognition, but loose a chance to find string in unrelated area. 43## 44use warnings FATAL => 'utf8'; 45 46use Getopt::EX::Loader; 47use Getopt::EX::Func qw(parse_func); 48 49use App::Greple::Common; 50use App::Greple::Util; 51use App::Greple::Grep; 52use App::Greple::Regions; 53use App::Greple::Pattern; 54use App::Greple::Pattern::Holder; 55use App::Greple::Filter; 56 57 58=head1 NAME 59 60 61greple - grep with multiple keywords 62 63 64=head1 SYNOPSIS 65 66 67B<greple> [B<-M>I<module>] [ B<-options> ] pattern [ file... ] 68 69 PATTERN 70 pattern 'and +must -not ?alternative &function' 71 -e pattern regex pattern match across line boundary 72 -r pattern regex pattern cannot be compromised 73 -v pattern regex pattern not to be matched 74 --le pattern lexical expression (same as bare pattern) 75 --re pattern regular expression 76 --fe pattern fixed expression 77 --file file file contains search pattern 78 MATCH 79 -i ignore case 80 --need=[+-]n required positive match count 81 --allow=[+-]n acceptable negative match count 82 STYLE 83 -l list filename only 84 -c print count of matched block only 85 -n print line number 86 -h do not display filenames 87 -H always display filenames 88 -o print only the matching part 89 -m n[,m] max count of blocks to be shown 90 -A[n] after match context 91 -B[n] before match context 92 -C[n] after and before match context 93 --join delete newline in the matched part 94 --joinby=string replace newline in the matched text by string 95 --nonewline do not add newline character at block end 96 --filestyle=style how filename printed (once, separate, line) 97 --linestyle=style how line number printed (separate, line) 98 --separate set filestyle and linestyle both "separate" 99 FILE 100 --glob=glob glob target files 101 --chdir change directory before search 102 --readlist get filenames from stdin 103 COLOR 104 --color=when use terminal color (auto, always, never) 105 --nocolor same as --color=never 106 --colormap=color R, G, B, C, M, Y etc. 107 --colorful use default multiple colors 108 --ansicolor=s ANSI color 16, 256 or 24bit 109 --[no]256 same as --ansicolor 256 or 16 110 --regioncolor use different color for inside/outside regions 111 --uniqcolor use different color for unique string 112 --random use random color each time 113 --face set/unset vidual effects 114 BLOCK 115 -p paragraph mode 116 --all print whole data 117 --block=pattern specify the block of records 118 --blockend=s specify the block end mark (Default: "--\n") 119 REGION 120 --inside=pattern select matches inside of pattern 121 --outside=pattern select matches outside of pattern 122 --include=pattern reduce matches to the area 123 --exclude=pattern reduce matches to outside of the area 124 --strict strict mode for --inside/outside --block 125 CHARACTER CODE 126 --icode=name specify file encoding 127 --ocode=name specify output encoding 128 FILTER 129 --if=filter input filter command 130 --of=filter output filter command 131 --pf=filter post process filter command 132 --noif disable default input filter 133 RUNTIME FUNCTION 134 --print=func print function 135 --continue continue after print function 136 --begin=func call function before search 137 --end=func call function after search 138 OTHER 139 --norc skip reading startup file 140 --man display command or module manual page 141 --show display module file 142 --require=file include perl program 143 --conceal=type conceal run time errors 144 --persist continue even after encoding error 145 -d flags display info (f:file d:dir c:color m:misc s:stat) 146 147=cut 148 149my $rcloader = new Getopt::EX::Loader 150 BASECLASS => 'App::Greple'; 151 152my @opt_e; 153my @opt_v; 154my @opt_r; 155my @opt_re; 156my @opt_le; 157my @opt_fe; 158my @opt_or; 159 160my @opt_if; 161my @opt_of; 162my @opt_pf; 163my @opt_glob; 164my @opt_icode; 165my @opt_block; 166my @opt_inside; 167my @opt_outside; 168my @opt_include; 169my @opt_exclude; 170my @opt_chdir; 171my @opt_begin; 172my @opt_end; 173my $opt_noif; 174my $opt_all; 175my $opt_blockend; 176my $opt_color = 'auto'; 177my $opt_ansicolor = '256'; 178my @opt_colormap; 179my $opt_colorful = 1; 180my @opt_face; 181my $opt_uniqcolor; 182my $opt_random; 183my $opt_regioncolor; 184my $opt_icode; 185my $opt_ocode; 186my $opt_man; 187my $opt_show; 188my $opt_join; 189my $opt_joinby = ""; 190my $opt_newline = 1; 191my $opt_clean; 192my $opt_readlist; 193my $opt_need; 194my $opt_allow = 0; 195my @opt_need; 196my @opt_allow; 197my $opt_strict = 0; 198my @opt_print; 199my $opt_continue; 200my $opt_filestyle = 'line'; 201my $opt_linestyle = 'line'; 202my %opt_conceal = (read => 1, skip => 0); 203my $opt_persist = 0; 204my $opt_usage; 205 206my $opt_c; 207my @opt_d = (); 208my @opt_f; 209my $opt_h; 210my $opt_i; 211my $opt_n; 212my $opt_o; 213my $opt_m; 214my $opt_p; 215my $opt_l; 216my $opt_A = 0; 217my $opt_B = 0; 218my $opt_C = 0; 219my $opt_H; 220#my $opt_M; 221 222my @optargs = ( 223 'e|and=s' => \@opt_e, 224 'r|must=s' => \@opt_r, 225 'v|not=s' => \@opt_v, 226 'or=s' => \@opt_or, 227 'le=s' => \@opt_le, 228 're=s' => \@opt_re, 229 'fe=s' => \@opt_fe, 230 'need=s' => \@opt_need, 231 'allow=s' => \@opt_allow, 232 'i|ignore-case!' => \$opt_i, 233 'l' => \$opt_l, 234 'c|count' => \$opt_c, 235 'n|line-number!' => \$opt_n, 236 'h|no-filename' => \$opt_h, 237 'H' => \$opt_H, 238 'filestyle|fs=s' => \$opt_filestyle, 239 'linestyle|ls=s' => \$opt_linestyle, 240 'separate', => sub { 241 $opt_filestyle = $opt_linestyle = $_[0] 242 }, 243 'o|only-matching!' => \$opt_o, 244 'm|max-count=s' => \$opt_m, 245 'p|paragraph!' => \$opt_p, 246 'A|after-context:2' => \$opt_A, 247 'B|before-context:2' => \$opt_B, 248 'C|context:2' => \$opt_C, 249 'all' => \$opt_all, 250 'f|file=s' => \@opt_f, 251 'readlist!' => \$opt_readlist, 252 'd=s' => \@opt_d, 253 'man' => \$opt_man, 254 'show' => \$opt_show, 255 'icode=s' => \@opt_icode, 256 'ocode=s' => \$opt_ocode, 257 'join!' => \$opt_join, 258 'joinby=s' => \$opt_joinby, 259 'newline!' => \$opt_newline, 260 'if=s' => \@opt_if, 261 'of=s' => \@opt_of, 262 'pf=s' => \@opt_pf, 263 'noif' => \$opt_noif, 264 'block=s' => \@opt_block, 265 'blockend:s' => \$opt_blockend, 266 'inside=s' => \@opt_inside, 267 'outside=s' => \@opt_outside, 268 'include=s' => \@opt_include, 269 'exclude=s' => \@opt_exclude, 270 'strict!' => \$opt_strict, 271 'chdir=s' => \@opt_chdir, 272 'glob=s' => \@opt_glob, 273 'begin=s' => \@opt_begin, 274 'end=s' => \@opt_end, 275 'clean!' => \$opt_clean, 276 'color=s' => \$opt_color, 277 'colormap|colormode|addcolor|cm:s' 278 => \@opt_colormap, 279 'nocolor|nocolour' => sub { $opt_color = 'never' }, 280 'colorful!' => \$opt_colorful, 281 'face=s' => \@opt_face, 282 'uniqcolor|uc!' => \$opt_uniqcolor, 283 'random!' => \$opt_random, 284 'ansicolor=s' => \$opt_ansicolor, 285 '256!' => sub { $opt_ansicolor = $_[1] ? '256' : '16' }, 286 'regioncolor|rc!' => \$opt_regioncolor, 287 'print=s' => \@opt_print, 288 'continue!' => \$opt_continue, 289 'conceal=i' => \%opt_conceal, 290 'persist!' => \$opt_persist, 291 'usage:s' => \$opt_usage, 292 'M:s' => sub { 293 warn "Use -M option at the beginning with module name.\n"; 294 if (my @modules = uniq($rcloader->modules())) { 295 warn "Available modules:\n"; 296 warn "\t", join("\n\t", @modules), "\n"; 297 } 298 exit 2; 299 }, 300); 301 302sub newopt { 303 push @optargs, @_; 304} 305 306my %optargs; 307sub setopt { 308 unless (%optargs) { 309 for (my $i = 0; $i <= $#optargs; $i += 2) { 310 my($spec, $ref) = @optargs[$i, $i + 1]; 311 while ($spec =~ /\G(\w+)\|?/g) { 312 $optargs{$1} = $ref; 313 } 314 } 315 } 316 my $opt = ref $_[0] eq 'HASH' ? shift : {}; 317 my $name = shift; 318 if (exists $optargs{$name}) { 319 my $ref = $optargs{$name}; 320 if (ref $ref eq 'ARRAY') { 321 if ($opt->{append}) { 322 push @$ref, @_; 323 } else { 324 @$ref = @_; 325 } 326 } 327 elsif (ref $ref eq 'CODE') { 328 &$ref($name, @_); 329 } 330 elsif (ref $ref eq 'SCALAR') { 331 $$ref = shift; 332 } 333 else { 334 die "Object error."; 335 } 336 } 337} 338 339binmode STDERR, ":encoding(utf8)"; 340 341 342## 343## @ARGV staff 344## 345 346require Getopt::Long; 347my $parser = new Getopt::Long::Parser 348 config => [ qw(bundling no_getopt_compat) ] ; 349sub configure_getopt { $parser->configure(@_) } 350 351configure_getopt qw(debug) if $ENV{DEBUG_GETOPT}; 352$Getopt::EX::Loader::debug = 1 if $ENV{DEBUG_GETOPTEX}; 353 354## decode 355map { $_ = decode 'utf8', $_ unless utf8::is_utf8($_) } @ARGV; 356 357## ~/.greplerc 358(@ARGV and $ARGV[0] eq "--norc" and shift) or 359 $rcloader->load(FILE => "$ENV{HOME}/.greplerc"); 360 361## modules 362$rcloader->deal_with(\@ARGV); 363 364push @optargs, $rcloader->builtins; 365 366## ENV 367$ENV{'GREPLEOPTS'} and unshift @ARGV, shellwords($ENV{'GREPLEOPTS'}); 368 369 370## GetOptions 371my @SAVEDARGV = @ARGV; 372$parser->getoptions(@optargs) || pod2usage; 373 374our %opt_d; 375@opt_d = map { split // } @opt_d; 376@opt_d{@opt_d} = @opt_d; 377 378if ($opt_d{o}) { 379 warn "\@ARGV = ", join(' ', shellquote(@SAVEDARGV)), "\n"; 380} 381 382if (exists $opt_conceal{all}) { 383 $opt_conceal{$_} = $opt_conceal{all} for keys %opt_conceal; 384} 385 386## -m option 387my $splicer = do { 388 my($offset, $length); 389 if (not defined $opt_m) { 390 undef; 391 } elsif (($offset) = $opt_m =~ /^(-?\d+)$/) { 392 sub { splice @{+shift}, $offset } 393 } elsif (($offset, $length) = $opt_m =~ /^(-?\d+),(-?\d+)?$/) { 394 sub { splice @{+shift}, $offset, $length } 395 } else { 396 die "$opt_m: option format error.\n"; 397 } 398}; 399 400my $file_code; 401my $default_icode = 'utf8'; # default input encoding 402my @default_icode_list = qw(euc-jp 7bit-jis); 403my $output_code; 404my $default_ocode = 'utf8'; # default output encoding 405 406$output_code = $opt_ocode || $default_ocode; 407binmode STDOUT, ":encoding($output_code)"; 408 409## show unused option characters 410if ($opt_d{u}) { 411 my $s = join('','0'..'9',"\n",'a'..'z',"\n",'A'..'Z',"\n"); 412 map { /^([0-9a-zA-Z])(?:\|[^=]+)*(?:=[is])?$/ && $s =~ s/$1/./ } @optargs; 413 die $s; 414} 415 416## show man pages 417if ($opt_man or $opt_show) { 418 my @bucket = $rcloader->buckets; 419 if (@bucket and (my $mod = $bucket[-1]->title) ne ".greplerc") { 420 my @perldocopt = $opt_show ? '-m' : () ; 421 my $jp = first { -x "$_/perldocjp" } split /:/, $ENV{PATH}; 422 my $perldoc = $jp ? "perldocjp" : "perldoc"; 423 $ENV{PERL5LIB} = join ':', @INC; 424 my $command = "$perldoc @perldocopt App::Greple::$mod"; 425 warn $command, "\n" if $opt_d{m}; 426 exec $command or die $!; 427 } 428 pod2usage({-verbose => 2}); 429 die; 430} 431 432## setup file encoding 433if (@opt_icode) { 434 @opt_icode = map { split /[,\s]+/ } @opt_icode; 435 if (grep { s/^\+// } @opt_icode) { 436 unshift @opt_icode, @default_icode_list; 437 } 438 @opt_icode = uniq(@opt_icode); 439 if (@opt_icode > 1) { 440 @opt_icode = grep { !/(?:auto|guess)$/i } @opt_icode; 441 Encode::Guess->set_suspects(@opt_icode); 442 $file_code = 'Guess'; 443 } 444 elsif ($opt_icode[0] =~ /^(?:guess|auto)$/i) { 445 Encode::Guess->set_suspects(@default_icode_list); 446 $file_code = 'Guess'; 447 } else { 448 $file_code = $opt_icode[0]; 449 } 450} 451else { 452 $file_code = $default_icode; 453} 454 455## 456## Patterns 457## 458 459my $pat_holder = new App::Greple::Pattern::Holder; 460 461my $FLAG_BASE = FLAG_NONE; 462$FLAG_BASE |= FLAG_IGNORECASE if $opt_i; 463 464if (@opt_f) { 465 for my $opt_f (@opt_f) { 466 $pat_holder->append({ flag => $FLAG_BASE, type => 'file' }, 467 $opt_f); 468 } 469} else { 470 if (@opt_le + @opt_re + @opt_fe + @opt_or + @opt_e + @opt_r == 0) { 471 &usage if @ARGV == 0; 472 unshift @opt_le, shift @ARGV; 473 } 474} 475 476for ([ \@opt_r, FLAG_REGEX | FLAG_COOK | FLAG_REQUIRED ], 477 [ \@opt_v, FLAG_REGEX | FLAG_COOK | FLAG_NEGATIVE ], 478 [ \@opt_le, FLAG_REGEX | FLAG_COOK | FLAG_LEXICAL ], 479 [ \@opt_or, FLAG_REGEX | FLAG_COOK | FLAG_OR ], 480 [ \@opt_e, FLAG_REGEX | FLAG_COOK ], 481 [ \@opt_re, FLAG_REGEX ], 482 [ \@opt_fe, FLAG_NONE ]) 483{ 484 my($opt, $flag) = @$_; 485 $pat_holder->append({ flag => $FLAG_BASE | $flag, type => 'pattern' }, 486 @$opt) if @$opt; 487} 488 489## 490## set $opt_need and $opt_alow 491## 492{ 493 my $must = grep({ $_->is_required } $pat_holder->patterns); 494 my $posi = grep({ $_->is_positive } $pat_holder->patterns) - $must; 495 my $nega = grep({ $_->is_negative } $pat_holder->patterns); 496 497 $opt_need = $must ? 0 : $posi; 498 for (@opt_need) { 499 if (/^-(\d+)$/) { # --need -n 500 $opt_need = $posi - $1; 501 } 502 elsif (/^\+(\d+)$/) { # --need +n 503 $opt_need += $1; 504 } 505 elsif (/^(\d+)$/) { # --need n 506 $opt_need = $1 - $must; 507 } 508 else { 509 die "$_ is not valid count.\n" 510 } 511 } 512 513 $opt_allow = 0; 514 for (@opt_allow) { 515 if (/^-(\d+)$/) { # --allow -n 516 $opt_allow = $nega - $1; 517 } 518 elsif (/^\+(\d+)$/) { # --allow +n 519 $opt_allow += $1; 520 } 521 elsif (/^(\d+)$/) { # --allow n 522 $opt_allow = $1; 523 } 524 else { 525 die "$_ is not valid count.\n" 526 } 527 } 528} 529 530## 531## setup input/output filter 532## 533my $filter_d = new App::Greple::Filter; 534$filter_d->parse(@opt_if); 535unless ($opt_noif) { 536 $filter_d->append( 537 [ sub { s/\.Z$// }, 'zcat' ], 538 [ sub { s/\.g?z$// }, 'gunzip -c' ], 539 [ sub { m/\.pdf$/i }, 'pdftotext -nopgbrk - -' ], 540 [ sub { s/\.gpg$// }, 'gpg --quiet --no-mdc-warning --decrypt' ]); 541} 542 543##------------------------------------------------------------ 544## miscellaneous setups 545## 546 547my @argv_files; 548my $start_directory; 549my $need_filename = ($opt_H or $opt_l); 550my $current_file; 551 552if (@opt_chdir) { 553 $start_directory = getcwd; 554 @opt_chdir = uniq(map { glob $_ } @opt_chdir); 555 push @argv_files, splice(@ARGV); 556 unless ($opt_h or 557 (@opt_chdir == 1 and @argv_files == 1 and @opt_glob == 0)) { 558 $need_filename++; 559 } 560} 561elsif (@opt_glob) { 562 push @ARGV, map(glob, @opt_glob); 563} 564 565push(@ARGV, '-') unless @ARGV || @argv_files || @opt_glob || $opt_readlist; 566if ((@ARGV > 1 or $opt_readlist) and not $opt_h) { 567 $need_filename++; 568} 569 570$opt_join = 1 if $opt_joinby ne ""; 571 572##------------------------------------------------------------ 573## colors 574## 575my %colormap = ( 576 FILE => "G", 577 LINE => "Y", 578 BLOCKEND => "", 579 ); 580 581my @colors; 582 583require Getopt::EX::Colormap; 584my $color_handler = new Getopt::EX::Colormap 585 HASH => \%colormap, 586 LIST => \@colors, 587 ; 588$color_handler->load_params(@opt_colormap); 589 590my @default_color = 591 $opt_ansicolor eq '16' 592 ? qw(RD GD BD CD MD YD) 593 : qw(DK/544 DK/454 DK/445 594 DK/455 DK/545 DK/554 595 DK/543 DK/453 DK/435 596 DK/534 DK/354 DK/345 597 DK/444 598 DK/433 DK/343 DK/334 599 DK/344 DK/434 DK/443 600 DK/333) 601 ; 602 603if ($color_handler->list == 0) { 604 $color_handler->append 605 ($opt_colorful ? @default_color : $default_color[0]); 606} 607 608if ($opt_ansicolor eq '24bit') { 609 no warnings 'once'; 610 $Getopt::EX::Colormap::COLOR_RGB24 = 1; 611} 612 613if (@opt_face) { 614 my $remove = 0; 615 for my $flag (map { split // } @opt_face) { 616 if ($flag eq '-' or $flag eq '+') { 617 $remove = $flag eq '-'; 618 next; 619 } 620 map { $remove ? s/$flag//g : s/^/$flag/ } @colors; 621 } 622} 623 624my $need_color = (($opt_color eq 'always') 625 or (($opt_color eq 'auto') and (!$opt_o and -t STDOUT))); 626 627if ($opt_d{c}) { 628 my $dump = sub { 629 local $_ = Dumper shift; 630 s/(?<=')([\w\/]+)(?=')/color($1, $1)/ge; 631 $_; 632 }; 633 warn 'colormap = ', $dump->(\%colormap); 634 warn 'colors = ', $dump->(\@colors); 635} 636 637sub _file { $color_handler->color('FILE' , @_) } 638sub _line { $color_handler->color('LINE' , @_) } 639sub _delim { $color_handler->color('DELIM' , @_) } 640sub _blockend { $color_handler->color('BLOCKEND', @_) } 641 642sub index_color { 643 $color_handler->index_color(@_); 644} 645 646sub color { 647 $color_handler->color(@_); 648} 649 650my $uniq_color = new UniqIndex 651 ignore_newline => 1; 652 653sub dump_uniqcolor { 654 my $list = $uniq_color->list; 655 for my $i (0 .. $#{ $list }) { 656 warn sprintf "%d %s\n", $i, index_color($i, $list->[$i]); 657 } 658} 659 660 661my $blockend = "--\n"; 662if (defined $opt_blockend) { 663 ($blockend = $opt_blockend) =~ s/(?<=.)$/\n/; 664} 665if ($opt_C) { 666 $opt_A ||= $opt_C; 667 $opt_B ||= $opt_C; 668} 669my %stat = ( 670 files => 0, 671 match_effective => 0, 672 match_positive => 0, 673 match_negative => 0, 674 match_block => 0, 675 time_start => [], 676 time_end => [], 677 ); 678 679## 680## Setup functions 681## 682for my $set ( 683 [ "print" , \@opt_print , 0 ], 684 [ "begin" , \@opt_begin , 0 ], 685 [ "end" , \@opt_end , 0 ], 686 [ "block" , \@opt_block , 1 ], # need & 687 [ "inside" , \@opt_inside , 1 ], # need & 688 [ "outside", \@opt_outside, 1 ], # need & 689 [ "include", \@opt_include, 1 ], # need & 690 [ "exclude", \@opt_exclude, 1 ], # need & 691 ) { 692 my($cat, $opt, $pattern) = @$set; 693 for (@{$opt}) { 694 next if $_->can('call'); 695 /^&\w+/ or next if $pattern; 696 $_ = parse_func($_) or die "$cat function format error: $_\n"; 697 } 698} 699 700my $regions = new App::Greple::Regions::Holder; 701for my $set ( 702 [ \@opt_inside, REGION_INSIDE | REGION_UNION ], 703 [ \@opt_outside, REGION_OUTSIDE | REGION_UNION ], 704 [ \@opt_include, REGION_INSIDE | REGION_INTERSECT ], 705 [ \@opt_exclude, REGION_OUTSIDE | REGION_INTERSECT ]) 706{ 707 my($opt, $flag) = @$set; 708 for my $spec (@$opt) { 709 append $regions FLAG => $flag, SPEC => $spec; 710 } 711} 712 713##------------------------------------------------------------ 714 715if ($opt_d{m}) { 716 warn "Search pattern:\n"; 717 my $i; 718 for my $pat ($pat_holder->patterns) { 719 my $type = 720 $pat->is_function ? 'func' : 721 $pat->is_required ? 'must' : 722 $pat->is_negative ? 'not ' : 723 $pat->is_positive ? 'and ' : 'unknown'; 724 my $target = $pat->cooked; 725 warn sprintf(" %s %s\n", 726 $type, 727 @colors > 1 ? index_color($i++, $target) : $target); 728 } 729 warn sprintf "need = %d, allow = %d\n", $opt_need, $opt_allow; 730} 731 732## push post-process filter 733if (@opt_pf) { 734 push_output_filter(\*STDOUT, @opt_pf); 735} 736 737usage() and exit if defined $opt_usage; 738 739open SAVESTDIN, '<&', \*STDIN or die "open: $!"; 740open SAVESTDOUT, '>&', \*STDOUT or die "open: $!"; 741open SAVESTDERR, '>&', \*STDERR or die "open: $!"; 742 743sub recover_stdin { 744 open STDIN, '<&', \*SAVESTDIN or die "open: $!"; 745} 746sub recover_stderr { 747 open STDERR, '>&', \*SAVESTDERR or die "open: $!"; 748 binmode STDERR, ':encoding(utf8)'; 749} 750sub recover_stdout { 751 close STDOUT; 752 open STDOUT, '>&', \*SAVESTDOUT or die "open: $!"; 753} 754sub close_stdout { 755 close SAVESTDOUT; 756 close STDOUT; 757} 758 759sub read_stdin { <SAVESTDIN> } 760 761my($before_read, $after_read); 762if ($opt_conceal{read}) { 763 $before_read = sub { close STDERR }; 764 $after_read = sub { recover_stderr }; 765} 766 767##------------------------------------------------------------ 768## now ready to run. 769## 770 771## record start time 772if ($opt_d{s}) { 773 $stat{time_start} = [times]; 774} 775 776grep_files(); 777 778if ($opt_uniqcolor and $opt_d{m}) { 779 dump_uniqcolor(); 780} 781 782## show statistic info 783if ($opt_d{s}) { 784 785 $stat{time_end} = [times]; 786 my @s = @{$stat{time_start}}; 787 my @e = @{$stat{time_end}}; 788 printf(STDERR "cpu %.3fu %.3fs\n", $e[0]-$s[0], $e[1]-$s[1]); 789 790 local $" = ', '; 791 for my $k (sort keys %stat) { 792 my $v = $stat{$k}; 793 print STDERR 794 "$k: ", 795 ref $v eq 'ARRAY' ? "(@$v)" : $v, 796 "\n"; 797 } 798} 799 800close_stdout; 801 802if ($opt_d{p}) { 803 open STDOUT, ">&STDERR"; 804 system "ps -lww -p $$"; 805 system "lsof -p $$"; 806} 807 808exit($stat{match_effective} == 0); 809 810###################################################################### 811 812sub grep_files { 813 FILE: 814 while (defined($current_file = open_nextfile())) { 815 816 &$before_read() if $before_read; 817 my $content = eval { local $/; <STDIN> }; 818 &$after_read() if $after_read; 819 820 if (not defined $content) { 821 warn $@ if $@; 822 if (not $opt_persist) { 823 warn "SKIP $current_file\n" unless $opt_conceal{skip}; 824 next FILE; 825 } 826 827 # Try again 828 binmode STDIN, ':raw'; 829 $content = eval { local $/; <STDIN> }; 830 if (not defined $content) { 831 warn "SKIP* $current_file\n" unless $opt_conceal{skip}; 832 next FILE; 833 } 834 binmode STDOUT, ':raw'; 835 } 836 837 warn $current_file, ":\n" if $opt_d{f}; 838 839 my $matched = grep_data(\$content); 840 841 no warnings 'uninitialized'; # why ? 842 $stat{match_effective} += $matched; 843 $stat{files}++; 844 } continue { 845 close STDIN; # wait; # wait for 4.019 or earlier? 846 # recover STDIN for opening '-' and some weird command which needs 847 # STDIN opened (like unzip) 848 recover_stdin; 849 } 850} 851 852sub usage { 853 pod2usage(-verbose => 0, -exitval => "NOEXIT"); 854 855 my $quote = qr/[\\(){}\|\*?]/; 856 for my $bucket ($rcloader->buckets) { 857 my $title = $bucket->title; 858 print " $title options:\n"; 859 for my $name ($bucket->options) { 860 my $help = $opt_usage ? "" : $bucket->help($name) // ""; 861 next if $help eq 'ignore'; 862 my @option = $bucket->getopt($name, ALL => 1); 863 printf(" %-20s %s\n", $name, 864 $help || join(' ', shellquote(@option))); 865 } 866 print "\n"; 867 } 868 869 print "$rcsid\n" if $rcsid =~ /:/; 870 871 exit 2; 872} 873 874sub open_nextfile { 875 876 ## 877 ## --chdir 878 ## 879 while (@ARGV == 0 and @opt_chdir and (@argv_files or @opt_glob)) { 880 my $dir = shift @opt_chdir; 881 warn "chdir $dir/\n" if $opt_d{d}; 882 chdir $start_directory or die "$!: $start_directory\n"; 883 chdir $dir or die "$!: $dir\n"; 884 push @ARGV, @argv_files, map(glob, @opt_glob); 885 } 886 887 my $file; 888 while (defined($file = shift(@ARGV)) || 889 defined($file = $opt_readlist && read_stdin)) { 890 $file =~ s/\n+$//; 891 892 if (0) {} 893 elsif ($file =~ /^http:\/\//) { 894 open(STDIN, '-|') || exec("w3m -dump $file") || die "w3m: $!\n"; 895 } 896 else { 897 open(STDIN, $file) or do { 898 warn "$file: $!\n" unless -l $file; 899 next; 900 }; 901 } 902 903 if (my @filters = $filter_d->get_filters($file)) { 904 push_input_filter(@filters); 905 } 906 907 if ($file_code eq 'binary') { 908 # binmode STDIN, ":raw"; 909 } else { 910 binmode STDIN, ":encoding($file_code)"; 911 } 912 913 return $file; 914 } 915 undef; 916} 917 918###################################################################### 919 920sub grep_data { 921 local *_ = shift; 922 923 ## 924 ## --begin 925 ## 926 for my $f (@opt_begin) { 927 $f->call(&FILELABEL => $current_file); 928 } 929 930 my $grep = new App::Greple::Grep ( 931 text => \$_, 932 filename => $current_file, 933 pattern => $pat_holder, 934 regions => $regions, 935 after => $opt_A, 936 before => $opt_B, 937 paragraph => $opt_p, 938 only => $opt_o, 939 all => $opt_all, 940 block => \@opt_block, 941 need => $opt_need, 942 allow => $opt_allow, 943 strict => $opt_strict, 944 region_index => $opt_regioncolor, 945 stat => \%stat, 946 )->run; 947 my $matched = $grep->matched; 948 949 $splicer->($grep->result_ref) if $splicer; 950 951 if ($opt_l) { 952 print "$current_file\n" if $matched; 953 } 954 elsif ($opt_c) { 955 print "$current_file:" if $need_filename; 956 print scalar $grep->blocks, "\n"; 957 } 958 elsif (@{$grep->result_ref}) { 959 # open output filter 960 @opt_of && push_output_filter(\*STDOUT, @opt_of); 961 display_result($grep); 962 @opt_of && recover_stdout; 963 } 964 965 ## 966 ## --end 967 ## 968 for my $f (@opt_end) { 969 $f->call(&FILELABEL => $current_file); 970 } 971 972 s/./\000/gs if $opt_clean; 973 974 $matched; 975} 976 977sub display_result { 978 my $grep = shift; 979 my $file = $grep->{filename}; 980 981 if ($need_filename and $opt_filestyle eq 'once') { 982 print $file, ":\n"; 983 } 984 985 my $need_blockend = 986 $opt_blockend || $opt_p || $opt_A || $opt_B || @opt_block; 987 988 my $line = 1; 989 my $lastpos = 0; 990 for my $result ($grep->result) { 991 992 my($block_start, $block_end) = @{shift @$result}; 993 my $block = $grep->cut($block_start, $block_end); 994 995 for my $func (@opt_print) { 996 for ($block) { 997 $_ = $func->call(&FILELABEL => $file, matched => $result); 998 } 999 } 1000 if (@opt_print and not $opt_continue) { 1001 print $block if defined $block; 1002 next; 1003 } 1004 1005 if ($opt_n) { 1006 my $gap = $grep->cut($lastpos, $block_start); 1007 $line += $gap =~ tr/\n/\n/; 1008 } 1009 $lastpos = $block_end; 1010 1011 if (my $nl = 0, 1) { 1012 if ($need_filename and $opt_filestyle eq 'separate') { 1013 print _file("$current_file:"); 1014 $nl++; 1015 } 1016 if ($opt_n and $opt_linestyle eq 'separate') { 1017 print _line("$line:"); 1018 $nl++; 1019 } 1020 print "\n" if $nl; 1021 } 1022 1023 my $mark = "\001"; 1024 for my $matched (reverse @$result) { 1025 my($ms, $me, $pi) = @$matched; 1026 next if $ms == $me; 1027 1028 $ms = max($ms - $block_start, 0); 1029 $me -= $block_start; 1030 my $s = substr($block, $ms, $me - $ms); 1031 1032 if ($opt_join) { 1033 if ($opt_n and $opt_linestyle eq 'line') { 1034 $s =~ s/(?<!\A)\n(?!\z)/$mark/g; 1035 } else { 1036 $s =~ s/(?<!\A)\n(?!\z)/$opt_joinby/g; 1037 } 1038 } 1039 1040 # --random 1041 if ($opt_random) { 1042 $pi = rand(@colors); 1043 } 1044 # --uniqcolor 1045 elsif ($opt_uniqcolor) { 1046 $pi = $uniq_color->index($s); 1047 } 1048 1049 substr($block, $ms, $me - $ms, 1050 $need_color ? index_color($pi, $s) : $s); 1051 } 1052 if ($opt_n) { 1053 if ($opt_linestyle eq 'line') { 1054 my $increment = $block =~ /[\n$mark]/ ? 1 : 0; 1055 $block =~ s{(?:($mark)|(?<=\n)|\A)(?=.)}{ 1056 my $s = $1 ? $opt_joinby 1057 : _line("$line:"); 1058 $line += $increment; 1059 $s; 1060 }gse; 1061 } else { 1062 $line += $block =~ tr/\n/\n/; 1063 } 1064 } 1065 1066 if ($need_filename and $opt_filestyle eq 'line') { 1067 my $s = _file("$file:"); 1068 $block =~ s/^/$s/mg; 1069 } 1070 1071 print $block; 1072 print "\n" if $opt_newline and not $block =~ /\n\z/; 1073 print _blockend($blockend) if $need_blockend; 1074 } 1075} 1076 1077 1078__END__ 1079 1080 1081=head1 DESCRIPTION 1082 1083 1084=head2 MULTIPLE KEYWORDS 1085 1086 1087B<greple> has almost the same function as Unix command L<egrep(1)> but 1088the search is done in the manner similar to search engine. For 1089example, next command print lines those contain all of `foo' and `bar' 1090and `baz'. 1091 1092 greple 'foo bar baz' ... 1093 1094Each word can be found in any order and/or any place in the string. 1095So this command find all of following texts. 1096 1097 foo bar baz 1098 baz bar foo 1099 the foo, bar and baz 1100 1101If you want to use OR syntax, prepend question (`?') mark on each 1102token, or use regular expression. 1103 1104 greple 'foo bar baz ?yabba ?dabba ?doo' 1105 greple 'foo bar baz yabba|dabba|doo' 1106 1107This command will print the line which contains all of `foo', `bar' 1108and `baz' and one or more from `yabba', `dabba' or `doo'. 1109 1110NOT operator can be specified by prefixing the token by minus (`-') 1111sign. Next example will show the line which contain both `foo' and 1112bar' but none of `yabba' or `dabba' or `doo'. 1113 1114 greple 'foo bar -yabba -dabba -doo' 1115 1116This can be written as this using B<-e> and B<-v> option. 1117 1118 greple -e foo -e bar -v yabba -v dabba -v doo 1119 greple -e foo -e bar -v 'yabba|dabba|doo' 1120 1121If `+' is placed to positive matching pattern, that pattern is marked 1122as required, and match required count is automatically set to the 1123number of required pattern. So 1124 1125 greple '+foo bar baz' 1126 1127commands implicitly set the option C<--need 1>, and consequently print 1128all lines including `foo'. If you want to search lines which includes 1129either or both of `bar' and `baz', use like this: 1130 1131 greple '+foo bar baz' --need 2 1132 greple '+foo bar baz' --need +1 1133 1134=head2 LINE ACROSS MATCH 1135 1136 1137B<greple> also search the pattern across the line boundaries. This is 1138especially useful to handle Asian multi-byte text. Japanese text can 1139be separated by newline almost any place of the text. So the search 1140pattern may spread out on multiple lines. 1141 1142As for ascii text, space character in the pattern matches any kind of 1143space including newline. Next example will search the word sequence 1144of `foo', `bar' and 'baz', even they spread out to multiple lines. 1145 1146 greple -e 'foo bar baz' 1147 1148Option B<-e> is necessary because space is taken as a token separator 1149in the bare or B<--le> pattern. 1150 1151 1152=head1 OPTIONS 1153 1154 1155=head2 PATTERNS 1156 1157 1158If no specific option is given, B<greple> takes the first argument as 1159a search pattern specified by B<--le> option. All of these patterns 1160can be specified multiple times. 1161 1162Command itself is written in Perl, and any kind of Perl style regular 1163expression can be used in patterns. See L<perlre(1)> for detail. 1164 1165Note that multiple line modifier (C<m>) is set when executed, so put 1166C<(?-m)> at the beginning of regex if you want to explicitly disable 1167it. 1168 1169Order of capture group in the pattern is not guaranteed. Please avoid 1170to use direct index, and use relative or named capture group instead. 1171For example, repeated character can be written as S<C<(\w)\g{-1}>> 1172or S<C<(?E<lt>cE<gt>\w)\g{c}>>. 1173 1174=over 7 1175 1176=item B<--le>=I<pattern> 1177 1178Treat the string as a collection of tokens separated by spaces. Each 1179token is interpreted by the first character. Token start with `-' 1180means negative pattern, `?' means alternative, and `+' does required. 1181 1182Next example print lines which contains `foo' and `bar', and one or 1183more of `yabba' and 'dabba', and none of `baz' and `doo'. 1184 1185 greple --le='foo bar -baz ?yabba ?dabba -doo' 1186 1187Multiple `?' preceded tokens are treated all mixed together. That 1188means `?A|B ?C|D' is equivalent to `?A|B|C|D'. If you want to mean 1189`(A or B) and (C or D)', use AND syntax instead: `A|B C|D'. 1190 1191If the pattern start with ampersand (`&'), it is treated as a 1192function, and the function is called instead of searching pattern. 1193Function call interface is same as the one for block/region options. 1194 1195If you have a definition of I<odd_line> function in you F<.greplerc>, 1196which is described in this manual later, you can print odd number 1197lines like this: 1198 1199 greple -n '&odd_line' file 1200 1201This is the summary of start character for B<--le> option: 1202 1203 + Required pattern 1204 - Negative match pattern 1205 ? Alternative pattern 1206 & Function call 1207 1208=item B<-e> I<pattern>, B<--and>=I<pattern> 1209 1210Specify positive match token. Next two commands are equivalent. 1211 1212 greple 'foo bar baz' 1213 greple -e foo -e bar -e baz 1214 1215First character is not interpreted, so next commands will search the 1216pattern `-baz'. 1217 1218 greple -e -baz 1219 1220Space characters are treated specially by B<-e> and B<-v> options. 1221They are replaced by the pattern which matches any number of 1222white spaces including newline. So the pattern can be expand to 1223multiple lines. Next commands search the series of word `foo', `bar' 1224and `baz' even if they are separated by newlines. 1225 1226 greple -e 'foo bar baz' 1227 1228=item B<-r> I<pattern>, B<--must>=I<pattern> 1229 1230Specify required match token. Next two commands are equivalent. 1231 1232 greple '+foo bar baz' 1233 greple -r foo -e bar -e baz 1234 1235=item B<-v> I<pattern>, B<--not>=I<pattern> 1236 1237Specify negative match token. Because it does not affect to the bare 1238pattern argument, you can narrow down the search result like this. 1239 1240 greple foo file 1241 greple foo file -v bar 1242 greple foo file -v bar -v baz 1243 1244=item B<--re>=I<pattern> 1245 1246Specify regular expression. No special treatment for space and wide 1247characters. 1248 1249=item B<--fe>=I<pattern> 1250 1251Specify fixed string pattern, like fgrep. 1252 1253=item B<-i>, B<--ignore-case> 1254 1255Ignore case. 1256 1257=item B<--need>=I<n> 1258 1259=item B<--allow>=I<n> 1260 1261Option to compromise matching condition. Option B<--need> specifies 1262the required match count, and B<--allow> the number of negative 1263condition to be overlooked. 1264 1265 greple --need=2 --allow=1 'foo bar baz -yabba -dabba -doo' 1266 1267Above command prints the line which contains two or more from `foo', 1268`bar' and `baz', and does not include more than one of `yabba', 1269`dabba' or `doo'. 1270 1271Using option B<--need>=I<1>, B<greple> produces same result as B<grep> 1272command. 1273 1274 grep -e foo -e bar -e baz 1275 greple --need=1 -e foo -e bar -e baz 1276 1277When the count I<n> is negative value, it is subtracted from default 1278value. 1279 1280=item B<-f> I<file>, B<--file>=I<file> 1281 1282Specify the file which contains search pattern. When file contains 1283multiple lines, patterns on each lines are search in OR context. 1284 1285Blank line and the line starting with sharp (#) character is ignored. 1286Two slashes (//) and following string are taken as a comment and 1287removed with preceding spaces. 1288 1289Multiple file can be specified, but they will be mixed into single 1290pattern. 1291 1292=back 1293 1294 1295=head2 STYLES 1296 1297 1298=over 7 1299 1300=item B<-l> 1301 1302List filename only. 1303 1304=item B<-c>, B<--count> 1305 1306Print count of matched block. 1307 1308=item B<-n>, B<--line-number> 1309 1310Show line number. 1311 1312=item B<-h>, B<--no-filename> 1313 1314Do not display filename. 1315 1316=item B<-H> 1317 1318Display filename always. 1319 1320=item B<-o>, B<--only-matching> 1321 1322Print matched string only. 1323 1324=item B<-m> I<n>[,I<m>], B<--max-count>=I<n>[,I<m>] 1325 1326Set the maximum count of blocks to be shown to I<n>. 1327 1328Actually I<n> and I<m> are simply passed to perl L<splice> function as 1329I<offset> and I<length>. Works like this: 1330 1331 greple -m 10 # get first 10 blocks 1332 greple -m 0,-10 # get last 10 blocks 1333 greple -m 0,10 # remove first 10 blocks 1334 greple -m -10 # remove last 10 blocks 1335 greple -m 10,10 # remove 10 blocks from 10th (10-19) 1336 1337This option does not affect to search performance and command exit 1338status. 1339 1340=item B<-A>[I<n>], B<--after-context>[=I<n>] 1341 1342=item B<-B>[I<n>], B<--before-context>[=I<n>] 1343 1344=item B<-C>[I<n>], B<--context>[=I<n>] 1345 1346Print I<n>-blocks before/after matched string. The value I<n> can be 1347omitted and the default is 2. When used with B<--paragraph> or 1348B<--block> option, I<n> means number of paragraph or block. 1349 1350Actually, these options expand the area of logical operation. It 1351means 1352 1353 grep -C1 'foo bar baz' 1354 1355matches following text. 1356 1357 foo 1358 bar 1359 baz 1360 1361Moreover 1362 1363 greple -C1 'foo baz' 1364 1365also matches this text, because matching blocks around `foo' and `bar' 1366overlaps each other and makes single block. 1367 1368=item B<--join> 1369 1370=item B<--joinby>=I<string> 1371 1372Convert newline character found in matched string to empty or specified 1373I<string>. Using B<--join> with B<-o> (only-matching) option, you can 1374collect searching sentence list in one per line form. This is 1375sometimes useful for Japanese text processing. For example, next 1376command prints the list of KATAKANA words, including those spread 1377across multiple lines. 1378 1379 greple -ho --join '\p{InKatakana}+(\n\p{InKatakana}+)*' 1380 1381Space separated word sequence can be processed with B<--joinby> 1382option. Next example prints all `for *something*' pattern in pod 1383documents within Perl script. 1384 1385 greple -Mperl --pod -ioe '\bfor \w+' --joinby ' ' 1386 1387=item B<--[no]newline> 1388 1389Since B<greple> can handle arbitrary blocks other than normal text 1390lines, they sometimes do not end by newline character. In that case, 1391extra newline is appended at the end of block to be shown. Option 1392B<--nonewline> disables this behaviour. 1393 1394=item B<--filestyle>=I<line>|I<once>|I<separate>, B<--fs> 1395 1396Default style is I<line>, and B<greple> prints filename at the 1397beginning of each line. Style I<once> prints the filename only once 1398at the first time. Style I<separate> prints filename in the separate 1399line before each line or block. 1400 1401=item B<--linestyle>=I<line>|I<separate>, B<--ls> 1402 1403Default style is I<line>, and B<greple> prints line numbers at the 1404beginning of each line. Style I<separate> prints line number in the 1405separate line before each line or block. 1406 1407=item B<--separate> 1408 1409Shortcut for B<--filestyle>=I<separate> B<--linestyle>=I<separate>. 1410This is convenient to use block mode search and visiting each location 1411from supporting tool, such as Emacs. 1412 1413=back 1414 1415 1416=head2 FILES 1417 1418 1419=over 7 1420 1421=item B<--glob>=I<pattern> 1422 1423Get files matches to specified pattern and use them as a target files. 1424Using B<--chdir> and B<--glob> makes easy to use B<greple> for fixed 1425common job. 1426 1427=item B<--chdir>=I<directory> 1428 1429Change directory before processing files. When multiple directories 1430are specified in B<--chdir> option, by using wildcard form or 1431repeating option, B<--glob> file expansion will be done for every 1432directories. 1433 1434 greple --chdir '/usr/man/man?' --glob '*.[0-9]' ... 1435 1436=item B<--readlist> 1437 1438Get filenames from standard input. Read standard input and use each 1439line as a filename for searching. You can feed the output from other 1440command like L<find(1)> for B<greple> with this option. Next example 1441searches string from files modified within 7 days: 1442 1443 find . -mtime -7 -print | greple --readlist pattern 1444 1445Using B<find> module, this can be done like: 1446 1447 greple -Mfind . -mtime -7 -- pattern 1448 1449=back 1450 1451 1452=head2 COLORS 1453 1454 1455=over 7 1456 1457=item B<--color>=I<auto>|I<always>|I<never>, B<--nocolor> 1458 1459Use terminal color capability to emphasize the matched text. Default 1460is `auto': effective when STDOUT is a terminal and option B<-o> is not 1461given, not otherwise. Option value `always' and `never' will work as 1462expected. 1463 1464Option B<--nocolor> is alias for B<--color>=I<never>. 1465 1466=item B<--colormap>=I<spec> 1467 1468Specify color map. Default is RD: RED and BOLD. 1469 1470Color specification is combination of single uppercase character 1471representing 8 colors : 1472 1473 R Red 1474 G Green 1475 B Blue 1476 C Cyan 1477 M Magenta 1478 Y Yellow 1479 K Black 1480 W White 1481 1482and alternative (usually brighter) colors in lowercase: 1483 1484 r, g, b, c, m, y, k, w 1485 1486or RGB value and 24 grey levels if using ANSI 256 color terminal : 1487 1488 000000 .. FFFFFF : 24bit RGB colors 1489 000 .. 555 : 6x6x6 RGB 216 colors 1490 L00 .. L23 : 24 grey levels 1491 1492=over 4 1493 1494Note that, when values are all same in 24bit RGB, it is converted to 149524 grey level, otherwise 6x6x6 216 color. 1496 1497=back 1498 1499with other special effects : 1500 1501 Z Zero (reset) 1502 D Double-struck (boldface) 1503 P Pale (dark) 1504 I Italic 1505 S Stand-out (reverse video) 1506 V Vanish (concealed) 1507 U Underline 1508 F Flash (blink) 1509 1510 ; No effect 1511 X No effect 1512 1513If the spec includes C</>, left side is considered for foreground 1514color and right side is for background. If multiple colors are 1515given in same spec, all indicators are produced in the order of 1516their presence. As a result, the last one takes effect. 1517 1518Effect characters are case insensitive, and can be found anywhere and 1519in any order in color spec string. Because C<X> and C<;> takes no 1520effect, you can use them to improve readability, like C<SxD;K/544>. 1521 1522Samples: 1523 1524 RGB 6x6x6 24bit color 1525 === ======= ============= ================== 1526 B 005 0000FF : blue foreground 1527 /M /505 /FF00FF : magenta background 1528 K/W 000/555 000000/FFFFFF : black on white 1529 R/G 500/050 FF0000/00FF00 : red on green 1530 W/w L03/L20 303030/c6c6c6 : grey on grey 1531 1532Multiple colors can be specified separating by white space or comma, 1533or by repeating options. Those colors will be applied for each 1534pattern keywords. Next command will show word `foo' in red, `bar' in 1535green and `baz' in blue. 1536 1537 greple --colormap='R G B' 'foo bar baz' 1538 1539 greple --cm R -e foo --cm G -e bar --cm B -e baz 1540 1541=item B<--colormap>=I<field>=I<spec>,I<field>=I<spec>,... 1542 1543Another form of colormap option to specify the color for fields: 1544 1545 FILE File name 1546 LINE Line number 1547 BLOCKEND Block end mark 1548 1549=item B<--colormap>=I<&func> B<--colormap>=I<sub{...}> 1550 1551You can also set the name of perl subroutine name or definition to be 1552called handling matched words. Target word is passed as variable 1553C<$_>, and the return value of the subroutine will be displayed. 1554 1555Next command convert all words in C comment to upper case. 1556 1557 greple --all '/\*(?s:.*?)\*/' --cm 'sub{uc}' 1558 1559You can quote matched string instead of coloring (this emulates 1560deprecated option B<--quote>): 1561 1562 greple --cm 'sub{"<".$_.">"}' ... 1563 1564It is possible to use this definition with field names. Next example 1565print line numbers in seven digits. 1566 1567 greple -n --cm 'LINE=sub{s/(\d+)/sprintf("%07d",$1)/e;$_}' 1568 1569Experimentally, function can be combined with other normal color 1570specifications. Also the form I<&func;> can be repeated. 1571 1572 greple --cm 'BF/544;sub{uc}' 1573 1574 greple --cm 'R;&func1;&func2;&func3' 1575 1576=item B<--[no]colorful> 1577 1578Shortcut for B<--colormap>='I<RD GD BD CD MD YD>' in ANSI 16 colors 1579mode, and B<--colormap>='I<D/544 D/454 D/445 D/455 D/454 D/554>' and 1580other combination of 3, 4, 5 for 256 colors mode. Enabled by default. 1581 1582=item B<--ansicolor>=I<16>|I<256>|I<24bit> 1583 1584If set as I<16>, use ANSI 16 colors as a default color set, otherwise 1585ANSI 256 colors. When set as I<24bit>, 6 hex digits notation produces 158624bit color sequence. Default is I<256>. 1587 1588=item B<--[no]256> 1589 1590Shortcut for B<--ansicolor>=I<256> or I<16>. 1591 1592=item B<--regioncolor> 1593 1594Use different colors for each B<--inside>/B<outside> regions. 1595Disabled by default. 1596 1597=item B<--uniqcolor> 1598 1599Use different colors for different string matched. 1600Disabled by default. 1601 1602Next example prints all words start by `color' and display them all in 1603different colors. 1604 1605 greple --uniqcolor 'colou?r\w*' 1606 1607=item B<--random> 1608 1609Use random selected color to display matched string each time. 1610Disabled by default. 1611 1612=item B<--face>=[-+]I<effect> 1613 1614Set or unset specified I<effect> for all color specs. Use `+' 1615(optional) to set, and `-' to unset. Effect is a single character 1616expressing: S (Stand-out), U (Underline), D (Double-struck), F (Flash). 1617 1618Next example remove D (double-struck) effect. 1619 1620 greple --face -D 1621 1622Multiple effects can be set/unset at once. 1623 1624 greple --face SF-D 1625 1626=back 1627 1628 1629=head2 BLOCKS 1630 1631 1632=over 7 1633 1634=item B<-p>, B<--paragraph> 1635 1636Print the paragraph which contains the pattern. Each paragraph is 1637delimited by two or more successive newline characters by default. Be 1638aware that an empty line is not paragraph delimiter if which contains 1639space characters. Example: 1640 1641 greple -np 'setuid script' /usr/man/catl/perl.l 1642 1643 greple -pe '^struct sockaddr' /usr/include/sys/socket.h 1644 1645It changes the unit of context specified by B<-A>, B<-B>, B<-C> 1646options. 1647 1648=item B<--all> 1649 1650Treat entire file contents as a single block. This is almost 1651identical to following command. 1652 1653 greple --block='(?s).*' 1654 1655=item B<--block>=I<pattern>, B<--block>=I<&sub> 1656 1657Specify the record block to display. Default block is a single line. 1658 1659Next example behave almost same as B<--paragraph> option, but is less 1660efficient. 1661 1662 greple --block='(.+\n)+' 1663 1664Next command treat the data as a series of 10-line blocks. 1665 1666 greple -n --block='(.*\n){1,10}' 1667 1668When blocks are not continuous and there are gaps between them, the 1669match occurred outside blocks are ignored. 1670 1671If multiple block options are supplied, overlapping blocks are merged 1672into single block. 1673 1674Please be aware that this option is sometimes quite time consuming, 1675because it finds all blocks before processing. 1676 1677=item B<--blockend>=I<string> 1678 1679Change the end mark displayed after B<-pABC> or B<--block> options. 1680Default value is "--\n". 1681 1682=back 1683 1684 1685=head2 REGIONS 1686 1687 1688=over 7 1689 1690=item B<--inside>=I<pattern> 1691 1692=item B<--outside>=I<pattern> 1693 1694Option B<--inside> and B<--outside> limit the text area to be matched. 1695For simple example, if you want to find string `and' not in the word 1696`command', it can be done like this. 1697 1698 greple --outside=command and 1699 1700The block can be larger and expand to multiple lines. Next command 1701searches from C source, excluding comment part. 1702 1703 greple --outside '(?s)/\*.*?\*/' 1704 1705Next command searches only from POD part of the perl script. 1706 1707 greple --inside='(?s)^=.*?(^=cut|\Z)' 1708 1709When multiple B<inside> and B<outside> regions are specified, those 1710regions are mixed up in union way. 1711 1712In multiple color environment, and if single keyword is specified, 1713matches in each B<--inside>/B<outside> regions are printed in 1714different colors. Forcing this operation with multiple keywords, use 1715B<--regioncolor> option. 1716 1717=item B<--inside>=I<&function> 1718 1719=item B<--outside>=I<&function> 1720 1721If the pattern name begins by ampersand (&) character, it is treated 1722as a name of subroutine which returns a list of blocks. Using this 1723option, user can use arbitrary function to determine from what part of 1724the text they want to search. User defined function can be defined in 1725F<.greplerc> file or by module option. 1726 1727=item B<--include>=I<pattern> 1728 1729=item B<--exclude>=I<pattern> 1730 1731=item B<--include>=I<&function> 1732 1733=item B<--exclude>=I<&function> 1734 1735B<--include>/B<exclude> option behave exactly same as 1736B<--inside>/B<outside> when used alone. 1737 1738When used in combination, B<--include>/B<exclude> are mixed in AND 1739manner, while B<--inside>/B<outside> are in OR. 1740 1741Thus, in the next example, first line prints all matches, and second 1742does none. 1743 1744 greple --inside PATTERN --outside PATTERN 1745 1746 greple --include PATTERN --exclude PATTERN 1747 1748You can make up desired matches using B<--inside>/B<outside> option, 1749then remove unnecessary part by B<--include>/B<exclude> 1750 1751=item B<--strict> 1752 1753Limit the match area strictly. 1754 1755By default, B<--block>, B<--inside>/B<outside>, 1756B<--include>/B<exclude> option allows partial match within the 1757specified area. For instance, 1758 1759 greple --inside and command 1760 1761matches pattern C<command> because the part of matched string is 1762included in specified inside-area. Partial match fails when option 1763B<--strict> provided, and longer string never matches within shorter 1764area. 1765 1766Interestingly enough, above example 1767 1768 greple --include PATTERN --exclude PATTERN 1769 1770produces output, as a matter of fact. Think of the situation 1771searching, say, C<' PATTERN '> with this condition. Matched area 1772includes surrounding spaces, and meets the both condition partially. 1773This match does not occur when option B<--strict> is given, either. 1774 1775=back 1776 1777 1778=head2 CHARACTER CODE 1779 1780 1781=over 7 1782 1783=item B<--icode>=I<code> 1784 1785Target file is assumed to be encoded in utf8 by default. Use this 1786option to set specific encoding. When handling Japanese text, you may 1787choose from 7bit-jis (jis), euc-jp or shiftjis (sjis). Multiple code 1788can be supplied using multiple option or combined code names with 1789space or comma, then file encoding is guessed from those code sets. 1790Use encoding name `guess' for automatic recognition from default code 1791list which is euc-jp and 7bit-jis. Following commands are all 1792equivalent. 1793 1794 greple --icode=guess ... 1795 greple --icode=euc-jp,7bit-jis ... 1796 greple --icode=euc-jp --icode=7bit-jis ... 1797 1798Default code set are always included suspect code list. If you have 1799just one code adding to suspect list, put + mark before the code name. 1800Next example does automatic code detection from euc-kr, ascii, utf8 1801and UTF-16/32. 1802 1803 greple --icode=+euc-kr ... 1804 1805If the string "B<binary>" is given as encoding name, no character 1806encoding is expeted and all files are processed as binary data. 1807 1808=item B<--ocode>=I<code> 1809 1810Specify output code. Default is utf8. 1811 1812=back 1813 1814 1815=head2 FILTER 1816 1817 1818=over 7 1819 1820=item B<--if>=I<filter>, B<--if>=I<EXP>:I<filter> 1821 1822You can specify filter command which is applied to each files before 1823search. If only one filter command is specified, it is applied to all 1824files. If filter information include colon, first field will be perl 1825expression to check the filename saved in variable $_. If it 1826successes, next filter command is pushed. 1827 1828 greple --if=rev perg 1829 greple --if='/\.tar$/:tar tvf -' 1830 1831If the command doesn't accept standard input as processing data, you 1832may be able to use special device: 1833 1834 greple --if='nm /dev/stdin' crypt /usr/lib/lib* 1835 1836Filters for compressed and gzipped file is set by default unless 1837B<--noif> option is given. Default action is like this: 1838 1839 greple --if='s/\.Z$//:zcat --if='s/\.g?z$//:gunzip -c' 1840 1841File with I<.gpg> suffix is filtered by B<gpg> command. In that case, 1842passphrase is asked for each file. If you want to input passphrase 1843only once to find from multiple files, use B<-Mpgp> module. 1844 1845If the filter start with C<&>, perl subroutine is called instead of 1846external command. You can define the subroutine in F<.greplerc> or 1847modules. B<Greple> simply call the subroutine, so it should be 1848responsible for process control. 1849 1850=item B<--noif> 1851 1852Disable default input filter. Which means compressed files will not 1853be decompressed automatically. 1854 1855=item B<--of>=I<filter>, B<--of>=I<&func> 1856 1857Specify output filter which process the output of B<greple> command. 1858Filter command can be specified in multiple times, and they are 1859invoked for each file to be processed. So next command reset the line 1860number for each files. 1861 1862 greple --of 'cat -n' string file1 file2 ... 1863 1864If the filter start with C<&>, perl subroutine is called instead of 1865external command. You can define the subroutine in F<.greplerc> or 1866modules. 1867 1868Output filter command is executed only when matched string exists to 1869avoid invoking many unnecessary processes. No effect for option 1870B<-c>. 1871 1872=item B<--pf>=I<filter>, B<--pf>=I<&func> 1873 1874Similar to B<--of> filter but invoked just once and takes care of 1875entire output from B<greple> command. 1876 1877=back 1878 1879 1880=head2 RUNTIME FUNCTIONS 1881 1882 1883=over 7 1884 1885=item B<--print>=I<function>, B<--print>=I<sub{...}> 1886 1887Specify user defined function executed before data print. Text to be 1888printed is replaced by the result of the function. Arbitrary function 1889can be defined in F<.greplerc> file. Matched data is placed in 1890variable C<$_>. Other information is passed by key-value pair in the 1891arguments. Filename is passed by C<file> key. Matched information is 1892passed by C<matched> key, in the form of perl array reference: 1893C<[[start,end],[start,end]...]>. 1894 1895Simplest function is B<--print>='I<sub{$_}>'. Coloring capability can 1896be used like this: 1897 1898 # ~/.greplerc 1899 __PERL__ 1900 sub print_simple { 1901 my %attr = @_; 1902 for my $r (reverse @{$attr{matched}}) { 1903 my($s, $e) = @$r; 1904 substr($_, $s, $e - $s, color('B', substr($_, $s, $e - $s))); 1905 } 1906 $_; 1907 } 1908 1909Then, you can use this function in the command line. 1910 1911 greple --print=print_simple ... 1912 1913It is possible to use multiple B<--print> options. In that case, 1914second function will get the result of the first function. The 1915command will print the final result of the last function. 1916 1917=item B<--continue> 1918 1919When B<--print> option is given, B<greple> will immediately print the 1920result returned from print function and finish the cycle. Option 1921B<--continue> forces to continue normal printing process after print 1922function called. So please be sure that all data being consistent. 1923 1924=item B<--begin>=I<function>(I<...>), B<--begin>=I<function>=I<...> 1925 1926Option B<--begin> specify the function executed at the beginning of 1927each file processing. This I<function> have to be called from B<main> 1928package. So if you define the function in the module package, use the 1929full package name or export properly. 1930 1931=item B<--end>=I<function>(I<...>), B<--end>=I<function>=I<...> 1932 1933Option B<--end> is almost same as B<--begin>, except that the function 1934is called after the file processing. 1935 1936=item B<-M>I<module>::I<function(...)>, B<-M>I<module>::I<function=...> 1937 1938Function can be given with module option, following module name. In 1939this form, the function will be called with module package name. So 1940you don't have to export it. Because it is called only once at the 1941beginning of command execution, before starting file processing, 1942C<FILELABEL> parameter is not given exceptionally. 1943 1944=back 1945 1946For these run-time functions, optional argument list can be set in the 1947form of C<key> or C<key=value>, connected by comma. These arguments 1948will be passed to the function in key => value list. Sole key will 1949have the value one. Also processing file name is passed with the key 1950of C<FILELABEL> constant. As a result, the option in the next form: 1951 1952 --begin function(key1,key2=val2) 1953 --begin function=key1,key2=val2 1954 1955will be transformed into following function call: 1956 1957 function(&FILELABEL => "filename", key1 => 1, key2 => "val2") 1958 1959As described earlier, C<FILELABEL> parameter is not given to the 1960function specified with module option. So 1961 1962 -Mmodule::function(key1,key2=val2) 1963 -Mmodule::function=key1,key2=val2 1964 1965simply becomes: 1966 1967 function(key1 => 1, key2 => "val2") 1968 1969The function can be defined in F<.greplerc> or modules. Assign the 1970arguments into hash, then you can access argument list as member of 1971the hash. It's safe to delete FILELABEL key if you expect random 1972parameter is given. Content of the target file can be accessed by 1973C<$_>. Ampersand (C<&>) is required to avoid the hash key is 1974interpreted as a bare word. 1975 1976 sub function { 1977 my %arg = @_; 1978 my $filename = delete $arg{&FILELABEL}; 1979 $arg{key1}; # 1 1980 $arg{key2}; # "val2" 1981 $_; # contents 1982 } 1983 1984 1985=head2 OTHERS 1986 1987 1988=over 7 1989 1990=item B<--norc> 1991 1992Do not read startup file: F<~/.greplerc>. 1993 1994=item B<--usage> 1995 1996B<Greple> print usage and exit with option B<--usage>, or no valid 1997parameter is not specified. In this case, module option is displayed 1998with help information if available. If you want to see how they are 1999expanded, supply something not empty to B<--usage> option, like: 2000 2001 greple -Mmodule --usage=expand 2002 2003=item B<--man> 2004 2005Show manual page. 2006Display module's manual page when used with B<-M> option. 2007 2008=item B<--show> 2009 2010Show module file contents. Use with B<-M> option. 2011 2012=item B<--require>=I<filename> 2013 2014Include arbitrary perl program. 2015 2016=begin comment 2017 2018=item B<-d> I<flags> 2019 2020Display informations. Various kind of debug, diagnostic, monitor 2021information can be display by giving appropriate flag to -d option. 2022 2023 d: directory information 2024 e: eval string 2025 f: processing file name 2026 m: misc debug information 2027 o: option related information 2028 p: run `ps' command before termination (on Unix) 2029 s: statistic information 2030 u: unused options 2031 v: internal match information 2032 2033=end comment 2034 2035=item B<--conceal> I<type>=I<val> 2036 2037Conceal runtime errors. Repeatable. Types are: 2038 2039=over 4 2040 2041=item B<read> 2042 2043(Default 1) Errors occured during file read. Mainly unicode related 2044errors when reading binary or umbiguous text file. 2045 2046=item B<skip> 2047 2048(Default 0) File skip warings produced when fatal error was occured 2049during file read. Occurs when reading binary files with automatic 2050character code recognition. 2051 2052=item B<all> 2053 2054Set same value for all types. 2055 2056=back 2057 2058=item B<--persist> 2059 2060As B<greple> tries to read data as a character string, sometimes fails 2061to convert them into internal representation, and the file is skipped 2062without processing. When option B<--persist> is specified, command 2063does not give up the file, and tries to read as binary data. 2064 2065Next command will show strings in binary file. 2066 2067 greple -o --re '(?a)\w{4,}' --persist --uc /bin/* 2068 2069When processing all files as binary data, use B<--icode=binary> 2070instead. 2071 2072=back 2073 2074 2075=head1 ENVIRONMENT and STARTUP FILE 2076 2077 2078Environment variable GREPLEOPTS is used as a default options. They 2079are inserted before command line options. 2080 2081Before starting execution, I<greple> reads the file named F<.greplerc> 2082on user's home directory. Following directives can be used. 2083 2084=over 7 2085 2086=item B<option> I<name> string 2087 2088Argument I<name> of `option' directive is user defined option name. 2089The rest are processed by I<shellwords> routine defined in 2090Text::ParseWords module. Be sure that this module sometimes requires 2091escape backslashes. 2092 2093Any kind of string can be used for option name but it is not combined 2094with other options. 2095 2096 option --fromcode --outside='(?s)\/\*.*?\*\/' 2097 option --fromcomment --inside='(?s)\/\*.*?\*\/' 2098 2099If the option named B<default> is defined, it will be used as a 2100default option. 2101 2102For the purpose to include following arguments within replaced 2103strings, two special notations can be used in option definition. 2104String C<$E<lt>nE<gt>> is replaced by the I<n>th argument after the 2105substituted option, where I<n> is number start from one. String 2106C<$E<lt>shiftE<gt>> is replaced by following command line argument and 2107the argument is removed from option list. 2108 2109For example, when 2110 2111 option --line --le &line=$<shift> 2112 2113is defined, command 2114 2115 greple --line 10,20-30,40 2116 2117will be evaluated as this: 2118 2119 greple --le &line=10,20-30,40 2120 2121=item B<expand> I<name> I<string> 2122 2123Define local option I<name>. Command B<expand> is almost same as 2124command B<option> in terms of its function. However, option defined 2125by this command is expanded in, and only in, the process of 2126definition, while option definition is expanded when command arguments 2127are processed. 2128 2129This is similar to string macro defined by following B<define> 2130command. But macro expantion is done by simple string replacement, so 2131you have to use B<expand> to define option composed by multiple 2132arguments. 2133 2134=item B<define> I<name> string 2135 2136Define macro. This is similar to B<option>, but argument is not 2137processed by I<shellwords> and treated just a simple text, so 2138meta-characters can be included without escape. Macro expansion is 2139done for option definition and other macro definition. Macro is not 2140evaluated in command line option. Use option directive if you want to 2141use in command line, 2142 2143 define (#kana) \p{InKatakana} 2144 option --kanalist --nocolor -o --join --re '(#kana)+(\n(#kana)+)*' 2145 help --kanalist List up Katakana string 2146 2147=item B<help> I<name> 2148 2149If `help' directive is used for same option name, it will be printed 2150in usage message. If the help message is `ignore', corresponding line 2151won't show up in the usage. 2152 2153=item B<builtin> I<spec> I<variable> 2154 2155Define built-in option which should be processed by option parser. 2156Arguments are assumed to be L<Getopt::Long> style spec, and 2157I<variable> is string start with C<$>, C<@> or C<%>. They will be 2158replaced by a reference to the object which the string represent. 2159 2160See B<pgp> module for example. 2161 2162=item B<autoload> I<module> I<options> 2163 2164Define module which should be loaded automatically when specified 2165option is found in the command arguments. 2166 2167For example, 2168 2169 autoload -Mdig --dig 2170 2171replaces option "I<--dig>" to "I<-Mdig --dig>", and I<dig> module is 2172loaded before processing I<--dig> option. 2173 2174=back 2175 2176Environment variable substitution is done for string specified by 2177`option' and `define' directives. Use Perl syntax B<$ENV{NAME}> for 2178this purpose. You can use this to make a portable module. 2179 2180When I<greple> found C<__PERL__> line in F<.greplerc> file, the rest 2181of the file is evaluated as a Perl program. You can define your own 2182subroutines which can be used by B<--inside>/B<outside>, 2183B<--include>/B<exclude>, B<--block> options. 2184 2185For those subroutines, file content will be provided by global 2186variable C<$_>. Expected response from the subroutine is the list of 2187array references, which is made up by start and end offset pairs. 2188 2189For example, suppose that the following function is defined in your 2190F<.greplerc> file. Start and end offset for each pattern match can be 2191taken as array element C<$-[0]> and C<$+[0]>. 2192 2193 __PERL__ 2194 sub odd_line { 2195 my @list; 2196 my $i; 2197 while (/.*\n/g) { 2198 push(@list, [ $-[0], $+[0] ]) if ++$i % 2; 2199 } 2200 @list; 2201 } 2202 2203You can use next command to search pattern included in odd number 2204lines. 2205 2206 % greple --inside '&odd_line' pattern files... 2207 2208 2209=head1 MODULE 2210 2211 2212Modules can be specified only at the beginning of command line by 2213B<-M>I<module> option. Name I<module> is prepended by B<App::Greple>, 2214so place the module file in F<App/Greple/> directory in Perl library. 2215 2216If the package name is declared properly, C<__DATA__> section in the 2217module file will be interpreted same as F<.greplerc> file content. 2218 2219Using B<-M> without module argument will print available module list. 2220Option B<--man> will display module document when used with B<-M> 2221option. Use B<--show> option to see the module itself. 2222 2223See this sample module code. This sample define options to search 2224from pod, comment and other segment in Perl script. Those capability 2225can be implemented both in function and macro. 2226 2227 package App::Greple::perl; 2228 2229 BEGIN { 2230 use Exporter (); 2231 our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS); 2232 2233 $VERSION = sprintf "%d.%03d", q$Revision: 7.1 $ =~ /(\d+)/g; 2234 2235 @ISA = qw(Exporter); 2236 @EXPORT = qw(&pod &comment &podcomment); 2237 %EXPORT_TAGS = ( ); 2238 @EXPORT_OK = qw(); 2239 } 2240 our @EXPORT_OK; 2241 2242 END { } 2243 2244 my $pod_re = qr{^=\w+(?s:.*?)(?:\Z|^=cut\s*\n)}m; 2245 my $comment_re = qr{^(?:[ \t]*#.*\n)+}m; 2246 2247 sub pod { 2248 my @list; 2249 while (/$pod_re/g) { 2250 push(@list, [ $-[0], $+[0] ] ); 2251 } 2252 @list; 2253 } 2254 sub comment { 2255 my @list; 2256 while (/$comment_re/g) { 2257 push(@list, [ $-[0], $+[0] ] ); 2258 } 2259 @list; 2260 } 2261 sub podcomment { 2262 my @list; 2263 while (/$pod_re|$comment_re/g) { 2264 push(@list, [ $-[0], $+[0] ] ); 2265 } 2266 @list; 2267 } 2268 2269 1; 2270 2271 __DATA__ 2272 2273 define :comment: ^(\s*#.*\n)+ 2274 define :pod: ^=(?s:.*?)(?:\Z|^=cut\s*\n) 2275 2276 #option --pod --inside :pod: 2277 #option --comment --inside :comment: 2278 #option --code --outside :pod:|:comment: 2279 2280 option --pod --inside '&pod' 2281 option --comment --inside '&comment' 2282 option --code --outside '&podcomment' 2283 2284You can use the module like this: 2285 2286 greple -Mperl --pod default greple 2287 2288 greple -Mperl --colorful --code --comment --pod default greple 2289 2290If special subroutine B<initialize()> is defined in the module, it is 2291called at the beginning with C<Getopt::EX::Module> object as a 2292first argument. Second argument is the reference to C<@ARGV>, and you 2293can modify actual C<@ARGV> using it. See B<find> module as a sample. 2294 2295 2296=head1 HISTORY 2297 2298 2299Most capability of B<greple> is derived from B<mg> command, which has 2300been developing from early 1990's by the same author. Because modern 2301standard B<grep> family command becomes to have similar capabilities, 2302it is a time to clean up entire functionalities, totally remodel the 2303option interfaces, and change the command name. (2013.11) 2304 2305 2306=head1 AUTHOR 2307 2308 2309Kazumasa Utashiro 2310 2311 2312=head1 SEE ALSO 2313 2314 2315L<grep(1)>, L<perl(1)> 2316 2317L<github|http://kaz-utashiro.github.io/greple/> 2318 2319L<Getopt::EX> 2320 2321=head1 LICENSE 2322 2323 2324Copyright (c) 1991-2017 Kazumasa Utashiro 2325 2326Use and redistribution for ANY PURPOSE are granted as long as all 2327copyright notices are retained. Redistribution with modification is 2328allowed provided that you make your modified version obviously 2329distinguishable from the original one. THIS SOFTWARE IS PROVIDED BY 2330THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES ARE 2331DISCLAIMED. 2332