2014-11-16 13:13:20 -07:00
|
|
|
// Copyright (C) 2014 The Syncthing Authors.
|
2014-09-29 12:43:32 -07:00
|
|
|
//
|
2015-03-07 13:36:35 -07:00
|
|
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
|
|
// You can obtain one at http://mozilla.org/MPL/2.0/.
|
2014-08-26 01:11:25 -07:00
|
|
|
|
|
|
|
package fnmatch
|
|
|
|
|
|
|
|
import (
|
|
|
|
"path/filepath"
|
|
|
|
"regexp"
|
|
|
|
"runtime"
|
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2015-04-04 13:03:03 -07:00
|
|
|
NoEscape = (1 << iota)
|
|
|
|
PathName
|
|
|
|
CaseFold
|
2014-08-26 01:11:25 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
func Convert(pattern string, flags int) (*regexp.Regexp, error) {
|
2014-08-26 04:07:59 -07:00
|
|
|
any := "."
|
|
|
|
|
2014-09-16 14:14:03 -07:00
|
|
|
switch runtime.GOOS {
|
|
|
|
case "windows":
|
2015-04-04 13:03:03 -07:00
|
|
|
flags |= NoEscape | CaseFold
|
2014-08-26 01:11:25 -07:00
|
|
|
pattern = filepath.FromSlash(pattern)
|
2015-04-04 13:03:03 -07:00
|
|
|
if flags&PathName != 0 {
|
2014-08-26 04:07:59 -07:00
|
|
|
any = "[^\\\\]"
|
|
|
|
}
|
2014-09-16 14:14:03 -07:00
|
|
|
case "darwin":
|
2015-04-04 13:03:03 -07:00
|
|
|
flags |= CaseFold
|
2014-09-16 14:14:03 -07:00
|
|
|
fallthrough
|
|
|
|
default:
|
2015-04-04 13:03:03 -07:00
|
|
|
if flags&PathName != 0 {
|
2014-09-16 14:14:03 -07:00
|
|
|
any = "[^/]"
|
|
|
|
}
|
2014-08-26 01:11:25 -07:00
|
|
|
}
|
2014-09-16 14:14:03 -07:00
|
|
|
|
2015-03-30 13:41:12 -07:00
|
|
|
// Support case insensitive ignores
|
|
|
|
ignore := strings.TrimPrefix(pattern, "(?i)")
|
|
|
|
if ignore != pattern {
|
2015-04-04 13:03:03 -07:00
|
|
|
flags |= CaseFold
|
2015-03-30 13:41:12 -07:00
|
|
|
pattern = ignore
|
|
|
|
}
|
|
|
|
|
2015-04-04 13:03:03 -07:00
|
|
|
if flags&NoEscape != 0 {
|
2014-08-26 01:11:25 -07:00
|
|
|
pattern = strings.Replace(pattern, "\\", "\\\\", -1)
|
|
|
|
} else {
|
|
|
|
pattern = strings.Replace(pattern, "\\*", "[:escapedstar:]", -1)
|
|
|
|
pattern = strings.Replace(pattern, "\\?", "[:escapedques:]", -1)
|
|
|
|
pattern = strings.Replace(pattern, "\\.", "[:escapeddot:]", -1)
|
|
|
|
}
|
2015-02-20 02:11:01 -07:00
|
|
|
|
|
|
|
// Characters that are special in regexps but not in glob, must be
|
|
|
|
// escaped.
|
|
|
|
for _, char := range []string{".", "+", "$", "^", "(", ")", "|"} {
|
|
|
|
pattern = strings.Replace(pattern, char, "\\"+char, -1)
|
|
|
|
}
|
|
|
|
|
2014-08-26 01:11:25 -07:00
|
|
|
pattern = strings.Replace(pattern, "**", "[:doublestar:]", -1)
|
|
|
|
pattern = strings.Replace(pattern, "*", any+"*", -1)
|
|
|
|
pattern = strings.Replace(pattern, "[:doublestar:]", ".*", -1)
|
|
|
|
pattern = strings.Replace(pattern, "?", any, -1)
|
2015-02-20 02:11:01 -07:00
|
|
|
|
2014-08-26 01:11:25 -07:00
|
|
|
pattern = strings.Replace(pattern, "[:escapedstar:]", "\\*", -1)
|
|
|
|
pattern = strings.Replace(pattern, "[:escapedques:]", "\\?", -1)
|
|
|
|
pattern = strings.Replace(pattern, "[:escapeddot:]", "\\.", -1)
|
2015-02-20 02:11:01 -07:00
|
|
|
|
2014-08-26 01:11:25 -07:00
|
|
|
pattern = "^" + pattern + "$"
|
2015-04-04 13:03:03 -07:00
|
|
|
if flags&CaseFold != 0 {
|
2014-08-26 01:11:25 -07:00
|
|
|
pattern = "(?i)" + pattern
|
|
|
|
}
|
|
|
|
return regexp.Compile(pattern)
|
|
|
|
}
|
|
|
|
|
2015-04-28 13:32:10 -07:00
|
|
|
// Match matches the pattern against the string, with the given flags, and
|
|
|
|
// returns true if the match is successful.
|
2014-08-26 01:11:25 -07:00
|
|
|
func Match(pattern, s string, flags int) (bool, error) {
|
|
|
|
exp, err := Convert(pattern, flags)
|
|
|
|
if err != nil {
|
|
|
|
return false, err
|
|
|
|
}
|
|
|
|
return exp.MatchString(s), nil
|
|
|
|
}
|