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  }