3 // Holds a bunch of helper functions for dealing with labels.
5 // SplitDomainName splits a name string into it's labels.
6 // www.miek.nl. returns []string{"www", "miek", "nl"}
7 // .www.miek.nl. returns []string{"", "www", "miek", "nl"},
8 // The root label (.) returns nil. Note that using
9 // strings.Split(s) will work in most cases, but does not handle
10 // escaped dots (\.) for instance.
11 // s must be a syntactically valid domain name, see IsDomainName.
12 func SplitDomainName(s string) (labels []string) {
16 fqdnEnd := 0 // offset of the final '.' or the length of the name
32 for i := 1; i < len(idx); i++ {
34 labels = append(labels, s[begin:end-1])
39 return append(labels, s[begin:fqdnEnd])
42 // CompareDomainName compares the names s1 and s2 and
43 // returns how many labels they have in common starting from the *right*.
44 // The comparison stops at the first inequality. The names are downcased
45 // before the comparison.
47 // www.miek.nl. and miek.nl. have two labels in common: miek and nl
48 // www.miek.nl. and www.bla.nl. have one label in common: nl
50 // s1 and s2 must be syntactically valid domain names.
51 func CompareDomainName(s1, s2 string) (n int) {
52 // the first check: root label
53 if s1 == "." || s2 == "." {
60 j1 := len(l1) - 1 // end
61 i1 := len(l1) - 2 // start
64 // the second check can be done here: last/only label
65 // before we fall through into the for-loop below
66 if equal(s1[l1[j1]:], s2[l2[j2]:]) {
75 if equal(s1[l1[i1]:l1[j1]], s2[l2[i2]:l2[j2]]) {
88 // CountLabel counts the the number of labels in the string s.
89 // s must be a syntactically valid domain name.
90 func CountLabel(s string) (labels int) {
97 off, end = NextLabel(s, off)
105 // Split splits a name s into its label indexes.
106 // www.miek.nl. returns []int{0, 4, 9}, www.miek.nl also returns []int{0, 4, 9}.
107 // The root name (.) returns nil. Also see SplitDomainName.
108 // s must be a syntactically valid domain name.
109 func Split(s string) []int {
113 idx := make([]int, 1, 3)
118 off, end = NextLabel(s, off)
122 idx = append(idx, off)
126 // NextLabel returns the index of the start of the next label in the
127 // string s starting at offset.
128 // The bool end is true when the end of the string has been reached.
129 // Also see PrevLabel.
130 func NextLabel(s string, offset int) (i int, end bool) {
132 for i = offset; i < len(s)-1; i++ {
149 // PrevLabel returns the index of the label when starting from the right and
150 // jumping n labels to the left.
151 // The bool start is true when the start of the string has been overshot.
152 // Also see NextLabel.
153 func PrevLabel(s string, n int) (i int, start bool) {
164 return lab[len(lab)-n], false
167 // equal compares a and b while ignoring case. It returns true when equal otherwise false.
168 func equal(a, b string) bool {
169 // might be lifted into API function.
176 for i := la - 1; i >= 0; i-- {
179 if ai >= 'A' && ai <= 'Z' {
182 if bi >= 'A' && bi <= 'Z' {