commit before ov-res changes

This commit is contained in:
Araq
2010-12-07 17:11:28 +01:00
parent ee445dc022
commit 2fb8ced454

191
tools/nimgrep.nim Executable file
View File

@@ -0,0 +1,191 @@
#
#
# Nimrod Grep Utility
# (c) Copyright 2010 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
import
os, strutils, parseopt, pegs, re, terminal
const
Usage = """
Usage: nimgrep [options] [pattern] [files/directory]
Options:
--find, -f find the pattern (default)
--replace, -r replace the pattern
--peg pattern is a peg (default)
--re pattern is a regular expression
--recursive process directories recursively
--confirm confirm each occurence/replacement; there is a chance
to abort any time without touching the file(s)
--stdin read pattern from stdin (to avoid the shell's confusing
quoting rules)
--word, -w the pattern should have word boundaries
--ignore_case, -i be case insensitive
--ignore_style, -y be style insensitive
"""
type
TOption = enum
optFind, optReplace, optPeg, optRegex, optRecursive, optConfirm, optStdin,
optWord, optIgnoreCase, optIgnoreStyle
TOptions = set[TOption]
TConfirmEnum = enum
ceAbort, ceYes, ceAll, ceNo, ceNone
var
filename = ""
pattern = ""
replacement = ""
options: TOptions
proc ask(msg: string): string =
stdout.write(msg)
result = stdin.readline()
proc Confirm: TConfirmEnum =
while true:
case normalize(ask("[a]bort; [y]es, a[l]l, [n]o, non[e]: "))
of "a", "abort": return ceAbort
of "y", "yes": return ceYes
of "l", "all": return ceAll
of "n", "no": return ceNo
of "e", "none": return ceNone
else: nil
proc highlight(a, b, c: string) =
stdout.write(a)
terminal.WriteStyled(b)
stdout.writeln(c)
proc countLines(s: string, first = 0, last = s.high): int =
var i = first
while i <= last:
if s[i] == '\13':
inc result
if i < last and s[i+1] == '\10': inc(i)
elif s[i] == '\10':
inc result
inc i
proc processFile(filename: string) =
var buffer = system.readFile(filename)
if isNil(buffer): quit("cannot open file: " & filename)
var pegp: TPeg
var rep: TRegex
var result: string
if optRegex in options:
if optIgnoreCase in options:
rep = re(pattern, {reExtended, reIgnoreCase})
else:
rep = re(pattern)
else:
pegp = peg(pattern)
if optReplace in options:
result = newString(buffer.len)
setLen(result, 0)
var line = 1
var i = 0
var matches: array[0..re.MaxSubpatterns-1. string]
var reallyReplace = true
while i < buffer.len:
var t: tuple[first, last: int]
if optRegex in options:
quit "to implement"
else:
t = findBounds(buffer, pegp, matches, i)
if t.first <= 0: break
inc(line, countLines(buffer, i, t.first-1))
var wholeMatch = buffer.copy(t.first, t.last)
echo "line ", line, ": ", wholeMatch
if optReplace in options:
var r = replace(wholeMatch, pegp, replacement)
if optConfirm in options:
case Confirm()
of ceAbort:
of ceYes:
of ceAll:
reallyReplace = true
of ceNo:
reallyReplace = false
of ceNone:
reallyReplace = false
if reallyReplace:
inc(line, countLines(buffer, t.first, t.last))
i = t.last+1
proc walker(dir: string) =
for kind, path in walkDir(dir):
case kind
of pcFile: processFile(path)
of pcDirectory:
if optRecursive in options:
walker(path)
else: nil
proc writeHelp() = quit(Usage)
proc writeVersion() = quit("1.0")
proc checkOptions(subset: TOptions, a, b: string) =
if subset <= options:
quit("cannot specify both '$#' and '$#'" % [a, b])
for kind, key, val in getopt():
case kind
of cmdArgument:
if options.contains(optStdIn):
filename = key
elif pattern.len == 0:
pattern = key
elif options.contains(optReplace) and replacement.len == 0:
replacement = key
else:
filename = key
of cmdLongOption, cmdShortOption:
case normalize(key)
of "find", "f": incl(options, optFind)
of "replace", "r": incl(options, optReplace)
of "peg": incl(options, optPeg)
of "re": incl(options, optRegex)
of "recursive": incl(options, optRecursive)
of "confirm": incl(options, optConfirm)
of "stdin": incl(options, optStdin)
of "word", "w": incl(options, optWord)
of "ignorecase", "i": incl(options, optIgnoreCase)
of "ignorestyle", "y": incl(options, optIgnoreStyle)
of "help", "h": writeHelp()
of "version", "v": writeVersion()
else: writeHelp()
of cmdEnd: assert(false) # cannot happen
checkOptions({optFind, optReplace}, "find", "replace")
checkOptions({optPeg, optRegex}, "peg", "re")
checkOptions({optIgnoreCase, optIgnoreStyle}, "ignore_case", "ignore_style")
checkOptions({optIgnoreCase, optPeg}, "ignore_case", "peg")
if optStdin in options:
pattern = ask("pattern [ENTER to exit]: ")
if IsNil(pattern) or pattern.len == 0: quit(0)
if optReplace in options:
replacement = ask("replacement [supports $1, $# notations]: ")
if pattern.len == 0:
writeHelp()
else:
if filename.len == 0: filename = os.getCurrentDir()
walker(filename)