package main import ( "bufio" "fmt" "os" "strings" ) type Error struct { File string Line int Err error } func (e Error) Error() string { if e.Line > 0 { return fmt.Sprintf("%v:%v: %v", e.File, e.Line, e.Err) } else { return fmt.Sprintf("%v: %v", e.File, e.Err) } } func parseConfigLine(line string) (key, val string) { line = strings.TrimRight(line, "\t ") keylen := strings.IndexAny(line, "\t =") if keylen < 0 { keylen = len(line) } variable := line[:keylen] value := strings.TrimLeft(line[keylen:], "\t ") if strings.HasPrefix(value, "=") { value = strings.TrimLeft(value[1:], "\t ") } return variable, value } func readConfigFile(fname string) (map[string][]string, error) { config_tree := make(map[string][]string) fp, err := os.Open(fname) if err != nil { return nil, Error{File: fname, Err: err} } buffer := bufio.NewScanner(fp) lineno := 0 ignore := false for buffer.Scan() { line := buffer.Text() lineno++ if len(line) == 0 || line[0] == '#' { continue } if ignore { if strings.HasPrefix(line, "-----END") { ignore = false } continue } if strings.HasPrefix(line, "-----BEGIN") { ignore = true continue } variable, value := parseConfigLine(line) if len(value) == 0 { err = fmt.Errorf("No value for variable: %s", variable) return nil, Error{File: fname, Line: lineno, Err: err} } variable = strings.ToLower(variable) config_tree[variable] = append(config_tree[variable], value) } err = buffer.Err() if err != nil { return nil, Error{File: fname, Err: err} } return config_tree, nil } // Returns a list of public addresses for a host-config in Go // "net.Dial" format. func getAddresses(cfg map[string][]string) []struct{ Node, Port string } { var result []struct{ Node, Port string } for _, node := range cfg["address"] { var port string space := strings.IndexByte(node, ' ') if space < 0 { if ports, portsOk := cfg["port"]; portsOk { port = ports[0] } else { port = "655" } } else { port = node[space+1:] node = node[:space] } result = append(result, struct{ Node, Port string }{node, port}) } return result }