irc-go/ircmap/istring.go
2017-06-13 17:18:10 -06:00

77 lines
1.8 KiB
Go

// written by Daniel Oaks <daniel@danieloaks.net>
// released under the ISC license
package ircmap
import (
"strings"
"golang.org/x/text/secure/precis"
"github.com/DanielOaks/go-idn/idna2003/stringprep"
)
// MappingType values represent the types of IRC casemapping we support.
type MappingType int
const (
// NONE represents no casemapping.
NONE MappingType = 0 + iota
// ASCII represents the traditional "ascii" casemapping.
ASCII
// RFC1459 represents the casemapping defined by "rfc1459"
RFC1459
// RFC3454 represents the UTF-8 nameprep casefolding as used by mammon-ircd.
RFC3454
// RFC7613 represents the UTF-8 casefolding currently being drafted by me
// with the IRCv3 WG.
RFC7613
)
var (
// Mappings is a mapping of ISUPPORT CASEMAP strings to our MappingTypes.
Mappings = map[string]MappingType{
"ascii": ASCII,
"rfc1459": RFC1459,
"rfc3454": RFC3454,
"rfc7613": RFC7613,
}
)
// rfc1459Fold casefolds only the special chars defined by RFC1459 -- the
// others are handled by the strings.ToLower earlier.
func rfc1459Fold(r rune) rune {
if '[' <= r && r <= ']' {
r += '{' - '['
}
return r
}
// Casefold returns a string, lowercased/casefolded according to the given
// mapping as defined by this package (or an error if the given string is not
// valid in the chosen mapping).
func Casefold(mapping MappingType, input string) (string, error) {
var out string
var err error
if mapping == ASCII || mapping == RFC1459 {
// strings.ToLower ONLY replaces a-z, no unicode stuff so we're safe
// to use that here without any issues.
out = strings.ToLower(input)
if mapping == RFC1459 {
out = strings.Map(rfc1459Fold, out)
}
} else if mapping == RFC3454 {
out, err = stringprep.Nameprep(input)
} else if mapping == RFC7613 {
out, err = precis.UsernameCaseMapped.CompareKey(input)
}
return out, err
}