Skip to content

Instantly share code, notes, and snippets.

@greggirwin
Created July 29, 2017 20:17
Show Gist options
  • Select an option

  • Save greggirwin/2dfe6bc45f596592c890b52d1d7f9475 to your computer and use it in GitHub Desktop.

Select an option

Save greggirwin/2dfe6bc45f596592c890b52d1d7f9475 to your computer and use it in GitHub Desktop.
RGrep (Rebol Grep)
REBOL [
Title: "Grep in REBOL"
File: %rgrep.r
Author: "Gregg Irwin"
Version: 0.0.2
Comment: {
rgrep searches one or more input files for lines containing a match
to a specified pattern. Refinements on EXEC are a shot at familiar
switches used with GREP. Not sure if we need them, though /quiet does
allow a nice optimization as we can break out on the first match.
By default:
It prints the matching lines.
It is case insensitive.
At its core, rgrep uses rawk.
Could be part of a shell emulator called RUSH - REBOL Unix SHell. :)
}
history: [
0.0.1 [01-Mar-2002 {Intitial Release}]
0.0.2 [10-Apr-2002
{Changed 'files parameter to 'sources to match new RAWK.}
]
]
TBD: [
{Figure out how we want to return results for more processing.
It should be easy to return a block of filenames with the count,
or a block of line numbers. Printing the results is nice, but
building tools for pipe and filter processing means we need to
be able to pass results around easily.}
{Instead of just files, could you pass in other series! types?
rawk would need to build in support for that as well, but think
of the possibilities! Maybe adding a RESULTS word in the object
which is populated when EXEC runs. Then the user can just
interrogate it, copy it out, etc.}
{Regex support for patterns, beyond simple wildcards.}
{/custom refinement for specifying a custom pattern, or even a
complete rawk program.}
{/quiet works like grep, but wouldn't it be nice to have a switch
that let us get *all* the results but without dumping them to the
screen?}
]
Example: {
rgrep/exec "greP" read %.
rgrep/exec/case "grep" read %.
rgrep/exec/any "gR?p" read %.
rgrep/exec/case/any "gr?p" read %.
}
]
include/check %rawk.r
rgrep-ctx: make object! [
set 'rgrep func [
{Search files for lines containing a match to pattern.
(This is what you call to use rgrep)}
pattern [string!]
sources [block! any-string!]
/deep "Recurse into sub-directories"
/list "List only file names with matching lines."
/count "List files and the number of lines that matched in each."
/quiet "Return only true or false (i.e. whether a match was found)."
/invert "Invert test. Success if no match."
/case "Make comparison case sensitive"
/any "Enables the * and ? wildcards"
/callback cbk-fn [function!] "Progress callback function. Just called for 'begin-file and 'end right now. Should take one arg."
/local prog result pat ct line-ct
][
; Do we want to return a block of info?
;info-blk: [count 0 lines []]
;line-info: [number 0 data ""]
ct: 0
; We want to build a rule like one of the following. Looking at the
; code to build it, would it be clearer just to list the hard-coded
; cases and use EITHER to select them (handling /invert after)?
;[find __ pattern] [find/case __ pattern] [find/any __ pattern]
;[find/case/any __ pattern]
pat: reduce compose/deep [
(either invert [to-lit-word 'not][])
to-path [find (either case ['case][]) (either any ['any] [])]
'__ 'pattern
]
;print mold pat
; Would it help us to define a common action to build upon?
;act: copy [result: true]
; Default rawk program, if no refinements are used.
prog: reduce [
pat [print [_fnr tab _filename tab mold trim __] result: true]
;'begin-file [print ["Searching:" _filename "for" mold pattern]]
'begin-file [cbk-fn ['begin-file _filename pattern]]
]
; Now, we'll check for each refinement they may have passed us.
; Each one basically indicates a different mode of operation.
; We just use a slightly different rawk program for each one.
if list [
prog: reduce [
pat [ct: add ct 1 print _filename result: true next-file]
'begin [print ["Found" mold pattern "in:"]]
'end [print [ct "files contained" mold pattern]]
]
]
if count [
prog: reduce [
pat [ct: add ct 1 line-ct: add line-ct 1 result: true]
'begin-file [line-ct: 0]
'end-file [if line-ct > 0 [print [_filename tab line-ct]]]
'end [print [ct "lines contained" mold pattern]]
]
]
if quiet [
prog: reduce [
pat [result: true exit]
]
]
; Now the rawk program has been set and we can run it.
;print mold prog
result: false
either deep [rawk/deep sources prog] [rawk sources prog]
print [rawk-ctx/_nr "total lines searched"]
result
]
]
; rgrep/exec/case/any "gr?p" read %.
; print ""
; print "find grep /invert"
; rgrep/exec/invert "grep" read %.
; print ""
; rgrep/exec "file" read %.
; print ""
;
; print "/list option"
; rgrep/exec/list "file" read %.
; print ""
;
; print ["/quiet result:" rgrep/exec/quiet "file" read %.]
; print ["/quiet result:" rgrep/exec/quiet random "2#3%4lks09(*SD)" read %.]
; print ""
; print ["/quiet/invert result:" rgrep/exec/quiet/invert "file" read %.]
; print ["/quiet/invert result:" rgrep/exec/quiet/invert random "2#3%4lks09(*SD)" read %.]
; print ""
; print "/count option"
; rgrep/exec/count "file" read %.
; print ""
; print "/invert/count option"
; rgrep/exec/invert/count "file" read %.
; print ""
;change-dir %/c/rebol/gregg/
;rgrep/exec "file" read %.
; change-dir %../nix-shell/
; ;print read %.
; print "/count option"
; rgrep/exec/count "file" read %.
; print ""
; print "/list option"
; rgrep/exec/list "file" read %.
; print ""
; change-dir %../../fromM/
; ;print read %.
; ;print "default: ginger"
; ;rgrep/exec "ginger" read %.
; ;print ""
; print "/count option"
; rgrep/exec/count "ginger" read %.
; print ""
; print "/list option"
; rgrep/exec/list "ginger" read %.
; print ""
; print "/quiet option"
; print rgrep/exec/quiet "ginger" read %.
; print ""
;
; change-dir %/c/rebol/scripts/library/
; ;print read %.
; print {"carl" /count option}
; rgrep/exec/count "carl" read %.
; print ""
; print {"carl" /list option}
; rgrep/exec/list "carl" read %.
; print ""
;
; halt
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment