glob/glob.go

336 lines
5.5 KiB
Go
Raw Normal View History

2015-11-30 17:58:20 +03:00
package glob
import (
"strings"
"fmt"
)
const (
2015-11-30 19:01:49 +03:00
any = `*`
superAny = `**`
singleAny = `?`
escape = `\`
2015-11-30 17:58:20 +03:00
)
2015-11-30 19:01:49 +03:00
var chars = []string{any, superAny, singleAny, escape}
2015-11-30 17:58:20 +03:00
2015-12-01 17:22:17 +03:00
type globKind int
const(
glob_raw globKind = iota
glob_multiple_separated
glob_multiple_super
glob_single
glob_composite
glob_prefix
glob_suffix
glob_prefix_suffix
)
2015-11-30 18:33:50 +03:00
// Glob represents compiled glob pattern.
2015-11-30 18:24:20 +03:00
type Glob interface {
2015-11-30 17:58:20 +03:00
Match(string) bool
2015-12-01 17:22:17 +03:00
search(string) (int, int, bool)
kind() globKind
2015-11-30 17:58:20 +03:00
}
2015-11-30 19:01:49 +03:00
// New creates Glob for given pattern and uses other given (if any) strings as separators.
// The pattern syntax is:
//
// pattern:
// { term }
// term:
// `*` matches any sequence of non-separator characters
// `**` matches any sequence of characters
// `?` matches any single non-separator character
// c matches character c (c != `*`, `**`, `?`, `\`)
// `\` c matches character c
2015-11-30 18:24:20 +03:00
func New(pattern string, d ...string) Glob {
2015-11-30 19:01:49 +03:00
chunks := parse(pattern, nil, strings.Join(d, ""), false)
2015-11-30 17:58:20 +03:00
2015-12-01 17:22:17 +03:00
switch len(chunks) {
case 1:
return chunks[0].glob
case 2:
if chunks[0].glob.kind() == glob_raw && chunks[1].glob.kind() == glob_multiple_super {
return &prefix{chunks[0].str}
}
if chunks[1].glob.kind() == glob_raw && chunks[0].glob.kind() == glob_multiple_super {
return &suffix{chunks[1].str}
}
case 3:
if chunks[0].glob.kind() == glob_raw && chunks[1].glob.kind() == glob_multiple_super && chunks[2].glob.kind() == glob_raw {
return &prefix_suffix{chunks[0].str, chunks[2].str}
}
2015-11-30 17:58:20 +03:00
}
2015-12-01 17:22:17 +03:00
var c []Glob
for _, chunk := range chunks {
c = append(c, chunk.glob)
}
return &composite{c}
}
type token struct {
glob Glob
str string
2015-11-30 17:58:20 +03:00
}
2015-12-01 17:22:17 +03:00
func parse(p string, m []token, d string, esc bool) []token {
2015-11-30 19:01:49 +03:00
var e bool
2015-11-30 17:58:20 +03:00
if len(p) == 0 {
2015-11-30 18:24:20 +03:00
return m
2015-11-30 17:58:20 +03:00
}
2015-11-30 18:33:50 +03:00
i, c := firstIndexOfChars(p, chars)
2015-11-30 17:58:20 +03:00
if i == -1 {
2015-12-01 17:22:17 +03:00
return append(m, token{raw{p}, p})
2015-11-30 17:58:20 +03:00
}
if i > 0 {
2015-12-01 17:22:17 +03:00
m = append(m, token{raw{p[0:i]}, p[0:i]})
2015-11-30 17:58:20 +03:00
}
2015-11-30 19:01:49 +03:00
if esc {
2015-12-01 17:22:17 +03:00
m = append(m, token{raw{c}, c})
2015-11-30 19:01:49 +03:00
} else {
switch c {
case escape:
e = true
case superAny:
2015-12-01 17:22:17 +03:00
m = append(m, token{multiple{}, c})
2015-11-30 19:01:49 +03:00
case any:
2015-12-01 17:22:17 +03:00
m = append(m, token{multiple{d}, c})
2015-11-30 19:01:49 +03:00
case singleAny:
2015-12-01 17:22:17 +03:00
m = append(m, token{single{d}, c})
2015-11-30 19:01:49 +03:00
}
2015-11-30 17:58:20 +03:00
}
2015-11-30 19:01:49 +03:00
return parse(p[i+len(c):], m, d, e)
2015-11-30 17:58:20 +03:00
}
2015-12-01 17:22:17 +03:00
// raw represents raw string to match
2015-11-30 17:58:20 +03:00
type raw struct {
s string
}
2015-12-01 17:22:17 +03:00
2015-11-30 17:58:20 +03:00
func (self raw) Match(s string) bool {
return self.s == s
}
2015-12-01 17:22:17 +03:00
func (self raw) kind() globKind {
return glob_raw
}
func (self raw) search(s string) (i int, l int, ok bool) {
index := strings.Index(s, self.s)
if index == -1 {
return
}
i = index
l = len(self.s)
ok = true
return
}
2015-11-30 17:58:20 +03:00
func (self raw) String() string {
return fmt.Sprintf("[raw:%s]", self.s)
}
2015-12-01 17:22:17 +03:00
// multiple represents *
2015-11-30 17:58:20 +03:00
type multiple struct {
2015-11-30 19:01:49 +03:00
separators string
2015-11-30 17:58:20 +03:00
}
2015-11-30 18:24:20 +03:00
2015-11-30 17:58:20 +03:00
func (self multiple) Match(s string) bool {
2015-11-30 19:01:49 +03:00
return strings.IndexAny(s, self.separators) == -1
2015-11-30 17:58:20 +03:00
}
2015-11-30 18:24:20 +03:00
2015-12-01 17:22:17 +03:00
func (self multiple) search(s string) (i int, l int, ok bool) {
if self.Match(s) {
return 0, len(s), true
}
return
}
func (self multiple) kind() globKind {
if self.separators == "" {
return glob_multiple_super
} else {
return glob_multiple_separated
}
}
2015-11-30 17:58:20 +03:00
func (self multiple) String() string {
2015-11-30 19:01:49 +03:00
return fmt.Sprintf("[multiple:%s]", self.separators)
2015-11-30 17:58:20 +03:00
}
2015-12-01 17:22:17 +03:00
// single represents ?
2015-11-30 17:58:20 +03:00
type single struct {
2015-11-30 19:01:49 +03:00
separators string
2015-11-30 17:58:20 +03:00
}
2015-11-30 18:24:20 +03:00
func (self single) Match(s string) bool {
2015-11-30 19:01:49 +03:00
return len(s) == 1 && strings.IndexAny(s, self.separators) == -1
2015-11-30 17:58:20 +03:00
}
2015-11-30 18:24:20 +03:00
2015-12-01 17:22:17 +03:00
func (self single) search(s string) (i int, l int, ok bool) {
if self.Match(s) {
return 0, 1, true
}
return
}
func (self single) kind() globKind {
return glob_single
}
2015-11-30 17:58:20 +03:00
func (self single) String() string {
2015-11-30 19:01:49 +03:00
return fmt.Sprintf("[single:%s]", self.separators)
2015-11-30 17:58:20 +03:00
}
2015-12-01 17:22:17 +03:00
// composite
2015-11-30 17:58:20 +03:00
type composite struct {
2015-11-30 18:24:20 +03:00
chunks []Glob
2015-11-30 17:58:20 +03:00
}
2015-12-01 17:22:17 +03:00
func (self composite) kind() globKind {
return glob_composite
}
func (self composite) search(s string) (i int, l int, ok bool) {
if self.Match(s) {
return 0, len(s), true
}
return
}
2015-11-30 17:58:20 +03:00
2015-12-01 17:22:17 +03:00
func m(chunks []Glob, s string) bool {
var prev Glob
for _, c := range chunks {
if c.kind() == glob_raw {
i, l, ok := c.search(s)
if !ok {
2015-11-30 17:58:20 +03:00
return false
}
if prev != nil {
2015-12-01 17:22:17 +03:00
if !prev.Match(s[:i]) {
2015-11-30 17:58:20 +03:00
return false
}
prev = nil
}
2015-12-01 17:22:17 +03:00
s = s[i+l:]
2015-11-30 17:58:20 +03:00
continue
}
prev = c
}
if prev != nil {
2015-12-01 17:22:17 +03:00
return prev.Match(s)
2015-11-30 17:58:20 +03:00
}
2015-12-01 17:22:17 +03:00
return len(s) == 0
}
func (self composite) Match(s string) bool {
return m(self.chunks, s)
2015-11-30 17:58:20 +03:00
}
2015-11-30 18:24:20 +03:00
func firstIndexOfChars(p string, any []string) (min int, c string) {
l := len(p)
min = l
weight := 0
for _, s := range any {
w := len(s)
i := strings.Index(p, s)
2015-11-30 19:01:49 +03:00
if i != -1 && i <= min && w >= weight {
2015-11-30 18:24:20 +03:00
min = i
weight = w
c = s
}
}
if min == l {
return -1, ""
}
return
2015-12-01 17:22:17 +03:00
}
type prefix struct {
s string
}
func (self prefix) kind() globKind {
return glob_prefix
}
func (self prefix) search(s string) (i int, l int, ok bool) {
if self.Match(s) {
return 0, len(s), true
}
return
}
func (self prefix) Match(s string) bool {
return strings.HasPrefix(s, self.s)
}
type suffix struct {
s string
}
func (self suffix) kind() globKind {
return glob_suffix
}
func (self suffix) search(s string) (i int, l int, ok bool) {
if self.Match(s) {
return 0, len(s), true
}
return
}
func (self suffix) Match(s string) bool {
return strings.HasSuffix(s, self.s)
}
type prefix_suffix struct {
p, s string
}
func (self prefix_suffix) kind() globKind {
return glob_prefix_suffix
}
func (self prefix_suffix) search(s string) (i int, l int, ok bool) {
if self.Match(s) {
return 0, len(s), true
}
return
}
func (self prefix_suffix) Match(s string) bool {
return strings.HasPrefix(s, self.p) && strings.HasSuffix(s, self.s)
}