fnmatch.go 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. // Copyright (C) 2014 The Syncthing Authors.
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this file,
  5. // You can obtain one at http://mozilla.org/MPL/2.0/.
  6. package fnmatch
  7. import (
  8. "path/filepath"
  9. "regexp"
  10. "runtime"
  11. "strings"
  12. )
  13. const (
  14. NoEscape = (1 << iota)
  15. PathName
  16. CaseFold
  17. )
  18. func Convert(pattern string, flags int) (*regexp.Regexp, error) {
  19. any := "."
  20. switch runtime.GOOS {
  21. case "windows":
  22. flags |= NoEscape | CaseFold
  23. pattern = filepath.FromSlash(pattern)
  24. if flags&PathName != 0 {
  25. any = `[^\\]`
  26. }
  27. case "darwin":
  28. flags |= CaseFold
  29. fallthrough
  30. default:
  31. if flags&PathName != 0 {
  32. any = `[^/]`
  33. }
  34. }
  35. if flags&NoEscape != 0 {
  36. pattern = strings.Replace(pattern, `\`, `\\`, -1)
  37. } else {
  38. pattern = strings.Replace(pattern, `\*`, "[:escapedstar:]", -1)
  39. pattern = strings.Replace(pattern, `\?`, "[:escapedques:]", -1)
  40. pattern = strings.Replace(pattern, `\.`, "[:escapeddot:]", -1)
  41. }
  42. // Characters that are special in regexps but not in glob, must be
  43. // escaped.
  44. for _, char := range []string{`.`, `+`, `$`, `^`, `(`, `)`, `|`} {
  45. pattern = strings.Replace(pattern, char, `\`+char, -1)
  46. }
  47. pattern = strings.Replace(pattern, `**`, `[:doublestar:]`, -1)
  48. pattern = strings.Replace(pattern, `*`, any+`*`, -1)
  49. pattern = strings.Replace(pattern, `[:doublestar:]`, `.*`, -1)
  50. pattern = strings.Replace(pattern, `?`, any, -1)
  51. pattern = strings.Replace(pattern, `[:escapedstar:]`, `\*`, -1)
  52. pattern = strings.Replace(pattern, `[:escapedques:]`, `\?`, -1)
  53. pattern = strings.Replace(pattern, `[:escapeddot:]`, `\.`, -1)
  54. pattern = `^` + pattern + `$`
  55. if flags&CaseFold != 0 {
  56. pattern = `(?i)` + pattern
  57. }
  58. return regexp.Compile(pattern)
  59. }
  60. // Match matches the pattern against the string, with the given flags, and
  61. // returns true if the match is successful.
  62. func Match(pattern, s string, flags int) (bool, error) {
  63. exp, err := Convert(pattern, flags)
  64. if err != nil {
  65. return false, err
  66. }
  67. return exp.MatchString(s), nil
  68. }