Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
branch: master
Fetching contributors…

Cannot retrieve contributors at this time

executable file 312 lines (255 sloc) 6.679 kb
#! parrot
=head1 NAME
pgegrep - A simple grep using PGE for matching
=head1 SYNOPSIS
B<pgegrep> [I<OPTIONS>] B<PATTERN> [I<FILE...>]
=head1 DESCRIPTION
pgegrep aims to be a small and easy to use program in replacement of the
standard grep utility. Regex support is whatever PGE will allow. It
searches through files line by line and tests if the given pattern matches.
=head1 OPTIONS
=over 4
=item -v
=item --invert-match
print lines not matching PATTERN
=item -V
=item --version
print the version and exit
=item --help
show this help and exit
=item -r
=item --recursive
recursively descend into directories
=item -L
=item --files-without-matches
print a list of files that do not match PATTERN
=item -l
=item --files-with-matches
print a list of files that do match PATTERN
=item -a
=item --text
treat binary files as text.
This uses a basic heuristic to discover if a file is binary or not. Files are
read line by line, and it keeps processing "normally" until a control character
is found, and then stops and goes onto the next file is that line matches.
=item -n
=item --line-number
print the line number for each match
=item -H
=item --with-filename
print the filename for each match
=back
=cut
# Readability improved!
.include 'hllmacros.pir'
# for getstdin and friends
.loadlib 'io_ops'
.sub main :main
.param pmc argv # the script name, then our options.
.local string progname
progname = shift argv
load_bytecode 'Getopt/Obj.pbc'
load_bytecode 'PGE.pbc'
.local pmc getopts
getopts = new [ 'Getopt';'Obj' ]
getopts.'notOptStop'(1)
push getopts, 'with-filename|H'
push getopts, 'files-with-matches|l'
push getopts, 'files-without-matches|L'
push getopts, 'line-number|n'
push getopts, 'text|a'
push getopts, 'recursive|r'
push getopts, 'invert-match|v'
push getopts, 'version|V'
push getopts, 'help'
push_eh handler
.local pmc opts
opts = getopts.'get_options'(argv)
$I0 = defined opts['help']
.If($I0, {
showhelp()
})
$I0 = defined opts['version']
.If($I0, {
showversion()
})
.local int argc
argc = elements argv
.Unless(argc>1, { # need rule and at least one file
showhelp()
.return()
})
.local string rule
.local pmc p6rule_compile, matchsub
rule = shift argv
p6rule_compile = compreg 'PGE::Perl6Regex'
matchsub = p6rule_compile(rule)
.If(null matchsub, { die 'Unable to compile regex' })
.local int i, filecount
.local string filename
.local pmc File, OS, files, handle
files = new 'ResizableStringArray'
files = argv
filecount = files
# define with-filename if there's more than one file
.If(filecount >= 2, { opts['with-filename'] = 1 })
$P0 = loadlib 'file'
File = new 'File'
$P0 = loadlib 'os'
OS = new 'OS'
# This must be here, or else it'll get filled with junk data we use stdin...
i = 0
.Unless(filecount, {
# no args, use stdin
stdindashhack:
handle = getstdin
filename = '(standard input)'
goto stdinhack
})
.For(, i < filecount, inc i, {
filename = files[i]
.If(filename == '-', {
goto stdindashhack
})
$I1 = File.'is_file'(filename)
.IfElse($I1, {
# Is a file
handle = open filename, 'r'
},{
# Not a file, hopefully a directory
$I1 = File.'is_dir'(filename)
$I0 = defined opts['recursive']
$I1 &= $I0
.Unless($I1, {
printerr "pgegrep: '"
printerr filename
printerr "': Operation not supported.\n"
goto nextfor_0
})
$P0 = OS.'readdir'(filename)
.Foreach($S0, $P0, {
.If($S0 != '.', {
.If($S0 != '..', {
$S1 = filename . '/'
$S0 = $S1 . $S0
$P1 = new 'ResizableStringArray'
$P1[0] = $S0
$I0 = i + 1
splice files, $P1, $I0, 0
}) })
})
filecount = files
goto nextfor_0
})
stdinhack:
checkfile(handle, filename, matchsub, opts)
close handle
nextfor_0:
})
end
handler:
.local pmc exception, pmcmsg
.local string message
.get_results (exception)
pmcmsg = getattribute exception, 'message'
pop_eh
message = pmcmsg
message = "pgegrep: " . message
die message
.end
.sub checkfile
.param pmc handle
.param string filename
.param pmc matchsub
.param pmc opts
.local pmc match
.local string line
.local int lineno, linelen, matched
lineno = 1
matched = 0 # Only used for --files-without-matches
line = readline handle
linelen = length line
.local pmc p6rule_compile, cntrlchar
$S0 = '<+cntrl-[\t\r\n]>'
p6rule_compile = compreg 'PGE::Perl6Regex'
cntrlchar = p6rule_compile($S0)
.For(, linelen, {
line = readline handle
linelen = length line
inc lineno
}, {
match = matchsub(line)
$I1 = istrue match
match = cntrlchar(line)
$I2 = istrue match
$I0 = defined opts['files-without-matches']
.If($I0, {
.If($I1, { matched = 1 })
goto next
})
$I0 = defined opts['files-with-matches']
$I0 = $I0 && $I1
.If($I0, {
say filename
.return()
})
$I0 = defined opts['invert-match']
not $I0
$I1 = xor $I1, $I0
.Unless($I1, {
$I0 = defined opts['text']
$I0 = xor $I0, $I2
.If($I0, {
print 'Binary file '
print filename
say ' matches'
.return()
})
$I0 = defined opts['with-filename']
$I1 = defined opts['recursive']
$I0 = $I0 || $I1
.If($I0, {
print filename
print ':'
})
$I0 = defined opts['line-number']
.If($I0, {
print lineno
print ':'
})
print line
})
#---------
next:
})
$I0 = defined opts['files-without-matches']
.If($I0, { say filename })
.return()
.end
.sub showhelp
print <<'HELP'
Usage: pgegrep [OPTIONS] PATTERN [FILE...]
Search for the Perl 6 Rule PATTERN in each file.
-v --invert-match print lines not matching PATTERN
-V --version print the version and exit
--help show this help and exit
-r --recursive recursively descend into directories
-L --files-without-matches print a list of files that do not match PATTERN
-l --files-with-matches print a list of files that do match PATTERN
-a --text treat binary files as text
-n --line-number print the line number for each match
-H --with-filename print the filename for each match
HELP
end
.end
.sub showversion
print <<'VERSION'
pgegrep v0.0.1
VERSION
end
.end
# Local Variables:
# mode: pir
# fill-column: 100
# End:
# vim: expandtab shiftwidth=4 ft=pir:
Jump to Line
Something went wrong with that request. Please try again.