OSDN Git Service

Merge pull request #201 from Bytom/v0.1
[bytom/vapor.git] / vendor / github.com / miekg / dns / labels.go
diff --git a/vendor/github.com/miekg/dns/labels.go b/vendor/github.com/miekg/dns/labels.go
new file mode 100644 (file)
index 0000000..ca8c204
--- /dev/null
@@ -0,0 +1,190 @@
+package dns
+
+// Holds a bunch of helper functions for dealing with labels.
+
+// SplitDomainName splits a name string into it's labels.
+// www.miek.nl. returns []string{"www", "miek", "nl"}
+// .www.miek.nl. returns []string{"", "www", "miek", "nl"},
+// The root label (.) returns nil. Note that using
+// strings.Split(s) will work in most cases, but does not handle
+// escaped dots (\.) for instance.
+// s must be a syntactically valid domain name, see IsDomainName.
+func SplitDomainName(s string) (labels []string) {
+       if len(s) == 0 {
+               return nil
+       }
+       fqdnEnd := 0 // offset of the final '.' or the length of the name
+       idx := Split(s)
+       begin := 0
+       if IsFqdn(s) {
+               fqdnEnd = len(s) - 1
+       } else {
+               fqdnEnd = len(s)
+       }
+
+       switch len(idx) {
+       case 0:
+               return nil
+       case 1:
+               // no-op
+       default:
+               end := 0
+               for i := 1; i < len(idx); i++ {
+                       end = idx[i]
+                       labels = append(labels, s[begin:end-1])
+                       begin = end
+               }
+       }
+
+       return append(labels, s[begin:fqdnEnd])
+}
+
+// CompareDomainName compares the names s1 and s2 and
+// returns how many labels they have in common starting from the *right*.
+// The comparison stops at the first inequality. The names are downcased
+// before the comparison.
+//
+// www.miek.nl. and miek.nl. have two labels in common: miek and nl
+// www.miek.nl. and www.bla.nl. have one label in common: nl
+//
+// s1 and s2 must be syntactically valid domain names.
+func CompareDomainName(s1, s2 string) (n int) {
+       // the first check: root label
+       if s1 == "." || s2 == "." {
+               return 0
+       }
+
+       l1 := Split(s1)
+       l2 := Split(s2)
+
+       j1 := len(l1) - 1 // end
+       i1 := len(l1) - 2 // start
+       j2 := len(l2) - 1
+       i2 := len(l2) - 2
+       // the second check can be done here: last/only label
+       // before we fall through into the for-loop below
+       if equal(s1[l1[j1]:], s2[l2[j2]:]) {
+               n++
+       } else {
+               return
+       }
+       for {
+               if i1 < 0 || i2 < 0 {
+                       break
+               }
+               if equal(s1[l1[i1]:l1[j1]], s2[l2[i2]:l2[j2]]) {
+                       n++
+               } else {
+                       break
+               }
+               j1--
+               i1--
+               j2--
+               i2--
+       }
+       return
+}
+
+// CountLabel counts the the number of labels in the string s.
+// s must be a syntactically valid domain name.
+func CountLabel(s string) (labels int) {
+       if s == "." {
+               return
+       }
+       off := 0
+       end := false
+       for {
+               off, end = NextLabel(s, off)
+               labels++
+               if end {
+                       return
+               }
+       }
+}
+
+// Split splits a name s into its label indexes.
+// www.miek.nl. returns []int{0, 4, 9}, www.miek.nl also returns []int{0, 4, 9}.
+// The root name (.) returns nil. Also see SplitDomainName.
+// s must be a syntactically valid domain name.
+func Split(s string) []int {
+       if s == "." {
+               return nil
+       }
+       idx := make([]int, 1, 3)
+       off := 0
+       end := false
+
+       for {
+               off, end = NextLabel(s, off)
+               if end {
+                       return idx
+               }
+               idx = append(idx, off)
+       }
+}
+
+// NextLabel returns the index of the start of the next label in the
+// string s starting at offset.
+// The bool end is true when the end of the string has been reached.
+// Also see PrevLabel.
+func NextLabel(s string, offset int) (i int, end bool) {
+       quote := false
+       for i = offset; i < len(s)-1; i++ {
+               switch s[i] {
+               case '\\':
+                       quote = !quote
+               default:
+                       quote = false
+               case '.':
+                       if quote {
+                               quote = !quote
+                               continue
+                       }
+                       return i + 1, false
+               }
+       }
+       return i + 1, true
+}
+
+// PrevLabel returns the index of the label when starting from the right and
+// jumping n labels to the left.
+// The bool start is true when the start of the string has been overshot.
+// Also see NextLabel.
+func PrevLabel(s string, n int) (i int, start bool) {
+       if n == 0 {
+               return len(s), false
+       }
+       lab := Split(s)
+       if lab == nil {
+               return 0, true
+       }
+       if n > len(lab) {
+               return 0, true
+       }
+       return lab[len(lab)-n], false
+}
+
+// equal compares a and b while ignoring case. It returns true when equal otherwise false.
+func equal(a, b string) bool {
+       // might be lifted into API function.
+       la := len(a)
+       lb := len(b)
+       if la != lb {
+               return false
+       }
+
+       for i := la - 1; i >= 0; i-- {
+               ai := a[i]
+               bi := b[i]
+               if ai >= 'A' && ai <= 'Z' {
+                       ai |= 'a' - 'A'
+               }
+               if bi >= 'A' && bi <= 'Z' {
+                       bi |= 'a' - 'A'
+               }
+               if ai != bi {
+                       return false
+               }
+       }
+       return true
+}