// Package grep is a simple grep program.
package grep
import (
"bufio"
"log"
"os"
"strconv"
"strings"
)
type config struct {
lineNum bool // print line numbers for matches
onlyFile bool // only print filenames with match
caseInsens bool // case-insensitive search
invert bool // collect non-matching lines
exact bool // match full lines, no partials
}
func newConfig(flags []string) *config {
c := config{}
for _, f := range flags {
switch f {
case "-n":
c.lineNum = true
case "-l":
c.onlyFile = true
case "-i":
c.caseInsens = true
case "-v":
c.invert = true
case "-x":
c.exact = true
}
}
return &c
}
// Search finds pattern in files. Behavior adjusted with flags.
func Search(pattern string, flags []string, files []string) []string {
c := newConfig(flags)
ret := []string{}
for _, fname := range files {
f, err := os.Open(fname)
if err != nil {
log.Panicln(err)
}
defer f.Close()
buff := bufio.NewScanner(f)
for i := 1; buff.Scan(); i++ {
line, matchLine := buff.Text(), buff.Text()
if c.caseInsens {
pattern = strings.ToLower(pattern)
matchLine = strings.ToLower(line)
}
if c.match(matchLine, pattern) {
if c.onlyFile {
ret = append(ret, fname)
break
} else {
var out strings.Builder
if len(files) > 1 {
out.WriteString(fname + ":")
}
if c.lineNum {
out.WriteString(strconv.Itoa(i) + ":")
}
out.WriteString(line)
ret = append(ret, out.String())
}
}
}
}
return ret
}
func (c *config) match(line, pattern string) bool {
if c.exact {
if c.invert {
return !(pattern == line)
}
return pattern == line
}
if c.invert {
return !strings.Contains(line, pattern)
}
return strings.Contains(line, pattern)
}