mirror of https://github.com/golang/go.git
addressed expansion rules, no negation, no buffers, ascii and one pattern
This commit is contained in:
parent
37f7999e5f
commit
ebae55c43b
|
|
@ -8,6 +8,7 @@
|
||||||
50:example/test:*.t4
|
50:example/test:*.t4
|
||||||
50:text/plain:*,v
|
50:text/plain:*,v
|
||||||
50:application/x-trash:*~
|
50:application/x-trash:*~
|
||||||
|
50:application/x-test-man:*.[1-3]
|
||||||
30:example/do-not-use:*.t4
|
30:example/do-not-use:*.t4
|
||||||
10:example/glob-question-mark:*.foo?ar
|
10:example/glob-question-mark:*.foo?ar
|
||||||
10:example/glob-asterisk:*.foo*r
|
10:example/glob-asterisk:*.foo*r
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,9 @@ package mime
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
"unicode"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
@ -136,76 +136,102 @@ func initMimeForTests() map[string]string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func expand(glob string) ([]string, bool) {
|
func expand(glob string) ([]string, bool) {
|
||||||
runes := []rune(glob)
|
openingBracketIndex := -1
|
||||||
resultSize := 1
|
closingBracketIndex := -1
|
||||||
stringSize := 0
|
|
||||||
|
|
||||||
countLoop:
|
var prefix []byte
|
||||||
for i := 0; i < len(runes); i++ {
|
var suffix []byte
|
||||||
switch runes[i] {
|
var mux *[]byte = &prefix
|
||||||
|
|
||||||
|
for i, c := range glob {
|
||||||
|
if c > unicode.MaxASCII {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
switch c {
|
||||||
case '[':
|
case '[':
|
||||||
for j := i + 1; j < len(runes); j++ {
|
if len(*mux) > 0 && (*mux)[len(*mux)-1] == '\\' {
|
||||||
if runes[j] == ']' {
|
(*mux)[len(*mux)-1] = glob[i]
|
||||||
i = j
|
continue
|
||||||
continue countLoop
|
|
||||||
}
|
|
||||||
if runes[j+1] == '-' {
|
|
||||||
if j+2 >= len(runes) {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
resultSize *= int(runes[j+2]-runes[j]) + 1
|
|
||||||
stringSize++
|
|
||||||
j += 2
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
resultSize++
|
|
||||||
stringSize++
|
|
||||||
}
|
}
|
||||||
|
if openingBracketIndex != -1 {
|
||||||
|
if closingBracketIndex != -1 {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
openingBracketIndex = i
|
||||||
|
mux = &suffix
|
||||||
|
case ']':
|
||||||
|
if openingBracketIndex == -1 {
|
||||||
|
*mux = append(*mux, ']')
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if i == openingBracketIndex+1 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
closingBracketIndex = i
|
||||||
default:
|
default:
|
||||||
stringSize++
|
if openingBracketIndex > -1 && closingBracketIndex == -1 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
*mux = append(*mux, glob[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buffers := make([]bytes.Buffer, resultSize, resultSize)
|
switch {
|
||||||
for i := range buffers {
|
case openingBracketIndex == -1 && closingBracketIndex == -1:
|
||||||
buffers[i].Grow(stringSize)
|
return []string{string(prefix)}, true
|
||||||
|
|
||||||
|
case openingBracketIndex != -1 && closingBracketIndex == -1:
|
||||||
|
return []string{string(prefix) + glob[openingBracketIndex:]}, true
|
||||||
|
|
||||||
|
case openingBracketIndex != -1 && openingBracketIndex+1 == '!':
|
||||||
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < len(runes); i++ {
|
expansion := expandRangeWithoutNegation(glob[openingBracketIndex+1 : closingBracketIndex])
|
||||||
switch runes[i] {
|
if expansion == nil {
|
||||||
case '[':
|
return nil, false
|
||||||
var expanded []rune
|
|
||||||
for j := i + 1; j < len(runes); j++ {
|
|
||||||
if runes[j] == ']' {
|
|
||||||
i = j
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if runes[j+1] == '-' {
|
|
||||||
for k := runes[j]; k <= runes[j+2]; k++ {
|
|
||||||
expanded = append(expanded, k)
|
|
||||||
}
|
|
||||||
j += 2
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
expanded = append(expanded, runes[j])
|
|
||||||
}
|
|
||||||
|
|
||||||
for j, k := 0, 0; j < resultSize; j, k = j+1, (k+1)%len(expanded) {
|
|
||||||
buffers[j].WriteRune(expanded[k])
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
for j := 0; j < resultSize; j++ {
|
|
||||||
buffers[j].WriteRune(runes[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
result := make([]string, 0, resultSize)
|
results := make([]string, len(expansion))
|
||||||
for i := 0; i < resultSize; i++ {
|
for i := 0; i < len(expansion); i++ {
|
||||||
result = append(result, buffers[i].String())
|
results[i] = string(prefix) + string(expansion[i]) + string(suffix)
|
||||||
}
|
}
|
||||||
|
|
||||||
return result, true
|
return results, true
|
||||||
|
}
|
||||||
|
|
||||||
|
func expandRangeWithoutNegation(r string) []byte {
|
||||||
|
var expansion []byte
|
||||||
|
for i := 0; i < len(r); i++ {
|
||||||
|
if r[i] == '!' && i == 0 {
|
||||||
|
// no negations of range expression
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if r[i] != '-' {
|
||||||
|
expansion = append(expansion, r[i])
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if i == 0 || i == len(r)-1 {
|
||||||
|
expansion = append(expansion, '-')
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if r[i+1] < r[i-1] {
|
||||||
|
// invalid character range
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for c := r[i-1] + 1; c <= r[i+1]; c++ {
|
||||||
|
if c == '/' {
|
||||||
|
// '/' cannot be matched: https://man7.org/linux/man-pages/man7/glob.7.html
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
expansion = append(expansion, c)
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
return expansion
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,7 @@ func TestMimeExtension(t *testing.T) {
|
||||||
want []string
|
want []string
|
||||||
}{
|
}{
|
||||||
{typ: "example/glob-range", want: []string{".foo1", ".foo2", ".foo3"}},
|
{typ: "example/glob-range", want: []string{".foo1", ".foo2", ".foo3"}},
|
||||||
|
{typ: "application/x-test-man", want: []string{".1", ".2", ".3"}},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
|
|
@ -67,3 +68,108 @@ func TestMimeExtension(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_expansion(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
glob string
|
||||||
|
ok bool
|
||||||
|
want []string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
glob: "foo",
|
||||||
|
ok: true,
|
||||||
|
want: []string{"foo"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
glob: ".foo[1-3da-c]",
|
||||||
|
ok: true,
|
||||||
|
want: []string{".foo1", ".foo2", ".foo3", ".food", ".fooa", ".foob", ".fooc"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
glob: ".foo[1-3][1-4]",
|
||||||
|
ok: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
glob: `.foo\[1-3`,
|
||||||
|
ok: true,
|
||||||
|
want: []string{".foo[1-3"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
glob: `.foo[1-3`,
|
||||||
|
ok: true,
|
||||||
|
want: []string{".foo[1-3"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
glob: ".foo1-3]",
|
||||||
|
ok: true,
|
||||||
|
want: []string{".foo1-3]"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
glob: ".foo[12-]",
|
||||||
|
ok: true,
|
||||||
|
want: []string{".foo1", ".foo2", ".foo-"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
glob: ".foo[-12]",
|
||||||
|
ok: true,
|
||||||
|
want: []string{".foo-", ".foo1", ".foo2"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
glob: ".foo[3-1]",
|
||||||
|
ok: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
glob: "foo[1-3].bar",
|
||||||
|
ok: true,
|
||||||
|
want: []string{"foo1.bar", "foo2.bar", "foo3.bar"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
glob: ".foo[!1-3]",
|
||||||
|
ok: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
glob: ".foo[!12]",
|
||||||
|
ok: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
glob: ".foo[1-3!a]",
|
||||||
|
ok: true,
|
||||||
|
want: []string{".foo1", ".foo2", ".foo3", ".foo!", ".fooa"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
glob: "[0-12-5]",
|
||||||
|
ok: true,
|
||||||
|
want: []string{"0", "1", "2", "3", "4", "5"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
glob: "[][!]",
|
||||||
|
ok: true,
|
||||||
|
want: []string{"]", "[", "!"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
glob: "[--0*?]",
|
||||||
|
ok: true,
|
||||||
|
want: []string{"-", ".", "0", "*", "?"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
glob: ".foo[]",
|
||||||
|
ok: true,
|
||||||
|
want: []string{".foo[]"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
glob: ".foo[1-3][4-5]",
|
||||||
|
ok: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
got, ok := expand(tt.glob)
|
||||||
|
if ok != tt.ok {
|
||||||
|
t.Errorf("expansion(%q) status = %v; want %v", tt.glob, ok, tt.ok)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(got, tt.want) {
|
||||||
|
t.Errorf("expansion(%q) result = %q; want %q", tt.glob, got, tt.want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue