github.com/hattya/go.sh@v0.0.0-20240328132134-f53276d95cc6/pattern/pattern_windows.go (about) 1 // 2 // go.sh/pattern :: pattern_windows.go 3 // 4 // Copyright (c) 2021 Akinori Hattori <hattya@gmail.com> 5 // 6 // SPDX-License-Identifier: MIT 7 // 8 9 package pattern 10 11 import ( 12 "strings" 13 "unicode/utf8" 14 ) 15 16 func indexSep(pat string) (int, int) { 17 n := len(pat) 18 for { 19 switch i := strings.IndexAny(pat, `\/`); { 20 case i == -1: 21 return -1, 0 22 case pat[i] == '\\' && i+1 < len(pat): 23 if isSep(rune(pat[i+1])) { 24 return n - len(pat[i:]), 2 25 } 26 pat = pat[i+1:] 27 default: 28 return n - len(pat[i:]), 1 29 } 30 } 31 } 32 33 func split(pat string) (string, string) { 34 // drive or volume 35 var b strings.Builder 36 i := 0 37 for j := 0; j < 2; j++ { 38 r, w := unquoteRune(pat[i:]) 39 b.WriteRune(r) 40 i += w 41 } 42 switch s := b.String(); { 43 case s[1] == ':' && ('A' <= s[0] && s[0] <= 'Z' || 'a' <= s[0] && s[0] <= 'z'): 44 // drive letter 45 case isSep(rune(s[0])) && isSep(rune(s[1])): 46 sep := 0 47 for i < len(pat) { 48 r, w := unquoteRune(pat[i:]) 49 if isSep(r) { 50 sep++ 51 if sep == 2 { 52 break 53 } 54 } 55 b.WriteRune(r) 56 i += w 57 } 58 switch s := b.String(); { 59 case len(s) >= 4 && isSep(rune(s[3])) && (s[2] == '.' || s[2] == '?'): 60 // DOS device 61 if len(s) == 7 && strings.HasSuffix(s, "UNC") { 62 for i < len(pat) { 63 r, w := unquoteRune(pat[i:]) 64 if isSep(r) { 65 sep++ 66 if sep == 5 { 67 break 68 } 69 } 70 b.WriteRune(r) 71 i += w 72 } 73 } 74 case sep > 0: 75 // UNC 76 default: 77 b.Reset() 78 i = 0 79 } 80 default: 81 b.Reset() 82 i = 0 83 } 84 // path 85 if r, w := unquoteRune(pat[i:]); isSep(r) { 86 b.WriteRune(r) 87 i += w 88 } 89 90 if b.Len() == 0 { 91 b.WriteByte('.') 92 } 93 return b.String(), pat[i:] 94 } 95 96 func isSep(r rune) bool { 97 return r == '\\' || r == '/' 98 } 99 100 func unquoteRune(s string) (rune, int) { 101 r, w := utf8.DecodeRuneInString(s) 102 if r == '\\' { 103 r, w = utf8.DecodeRuneInString(s[w:]) 104 w++ 105 } 106 return r, w 107 }