dns/labels.go

140 lines
2.9 KiB
Go
Raw Normal View History

2013-05-13 00:15:52 +10:00
// Copyright 2011 Miek Gieben. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
2012-01-11 01:55:52 +11:00
package dns
// Holds a bunch of helper functions for dealing with labels.
// SplitLabels splits a domainname string into its labels.
// www.miek.nl. returns []string{"www", "miek", "nl"}
2012-02-15 08:43:04 +11:00
// The root label (.) returns nil.
2012-01-11 01:55:52 +11:00
func SplitLabels(s string) []string {
2013-06-22 01:17:12 +10:00
idx := Split(s)
switch len(idx) {
case 0:
2012-02-24 05:37:08 +11:00
return nil
2013-06-22 01:17:12 +10:00
case 1:
return []string{s}
default:
begin := 0
end := 0
labels := make([]string, 0)
for i := 1; i < len(idx); i++ {
end = idx[i]
labels = append(labels, s[begin:end])
begin = end
2012-01-11 01:55:52 +11:00
}
2013-06-22 01:17:12 +10:00
return labels
2012-01-11 01:55:52 +11:00
}
2013-06-22 01:17:12 +10:00
panic("dns: not reached")
2012-01-11 01:55:52 +11:00
}
2013-06-21 06:36:13 +10:00
// CompareLabels compares the names s1 and s2 and
2012-01-11 02:04:32 +11:00
// returns how many labels they have in common starting from the right.
2012-09-05 04:08:55 +10:00
// The comparison stops at the first inequality. The labels are not downcased
// before the comparison.
2012-01-11 02:04:32 +11:00
//
// 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
2012-01-11 01:55:52 +11:00
func CompareLabels(s1, s2 string) (n int) {
2013-06-21 06:36:13 +10:00
s1 = Fqdn(s1)
s2 = Fqdn(s2)
l1 := Split(s1)
l2 := Split(s2)
2012-01-11 01:55:52 +11:00
2013-06-21 18:53:24 +10:00
// the first check: root label
2013-06-21 06:36:13 +10:00
if l1 == nil || l2 == nil {
return
}
j1 := len(l1) - 1 // end
i1 := len(l1) - 2 // start
j2 := len(l2) - 1
i2 := len(l2) - 2
2013-06-21 18:53:24 +10:00
// the second check can be done here: last/only label
// before we fall through into the for-loop below
2013-06-21 06:36:13 +10:00
if s1[l1[j1]:] == s2[l2[j2]:] {
n++
} else {
return
}
2012-01-11 01:55:52 +11:00
for {
2013-06-21 06:36:13 +10:00
if i1 < 0 || i2 < 0 {
break
}
2013-06-21 06:36:13 +10:00
if s1[l1[i1]:l1[j1]] == s2[l2[i2]:l2[j2]] {
n++
} else {
break
}
2013-06-21 06:36:13 +10:00
j1--
i1--
j2--
i2--
}
return
}
2013-06-21 06:36:13 +10:00
// LenLabels returns the number of labels in the string s
func LenLabels(s string) (labels int) {
if s == "." {
return
}
2013-06-21 06:36:13 +10:00
s = Fqdn(s) // TODO(miek): annoyed I need this
off := 0
end := false
for {
off, end = nextLabel(s, off)
labels++
if end {
return
}
}
2013-06-21 06:36:13 +10:00
}
2013-06-21 06:36:13 +10:00
// Split splits a name s into its label indexes.
// www.miek.nl. returns []int{0, 4, 9}. The root name (.) returns nil.
func Split(s string) []int {
if s == "." {
2013-06-21 06:36:13 +10:00
return nil
}
2013-06-21 06:36:13 +10:00
s = Fqdn(s) // Grrr!
idx := []int{0} // TODO(miek): could allocate more (10) and then extend when needed
off := 0
end := false
2013-06-21 06:36:13 +10:00
for {
2013-06-21 06:36:13 +10:00
off, end = nextLabel(s, off)
if end {
2013-06-21 06:36:13 +10:00
return idx
}
2013-06-21 06:36:13 +10:00
idx = append(idx, off)
}
}
2013-06-21 06:36:13 +10:00
// nextLabel returns the index of the start of the next label in the
// string s. The bool end is true when the end of the string has been
// reached.
func nextLabel(s string, offset int) (i int, end bool) {
2013-06-21 06:36:13 +10:00
// The other label function are quite generous with memory,
// this one does not allocate.
quote := false
2013-06-21 06:36:13 +10:00
for i = offset; i < len(s)-1; i++ {
switch s[i] {
case '\\':
quote = !quote
default:
quote = false
case '.':
if quote {
quote = !quote
continue
}
2013-06-21 06:36:13 +10:00
return i + 1, false
}
}
2013-06-21 06:36:13 +10:00
return i + 1, true
}