func (c *Config) GetAll(alias, key string) ([]string, error) {
	lowerKey := strings.ToLower(key)
	all := []string(nil)
	for _, host := range c.Hosts {
		if !host.Matches(alias) {
			continue
		}
		for _, node := range host.Nodes {
			switch t := node.(type) {
			case *Empty:
				continue
			case *KV:
				lkey := strings.ToLower(t.Key)
				if lkey == "match" {
					panic("can't handle Match directives")
				}
				if lkey == lowerKey {
					all = append(all, t.Value)
				}
			case *Include:
				val, _ := t.GetAll(alias, key)
				if len(val) > 0 {
					all = append(all, val...)
				}
			default:
				return nil, fmt.Errorf("unknown Node type %v", t)
			}
		}
	}
	return all, nil
}
GetAll returns all values in the configuration that match the alias and
contains key, or nil if none are present.
package ssh_config
import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	osuser "os/user"
	"path/filepath"
	"regexp"
	"runtime"
	"strings"
	"sync"
)
const version = "1.0"
var _ = version
type configFinder func() string
type UserSettings struct {
	IgnoreErrors       bool
	systemConfig       *Config
	systemConfigFinder configFinder
	userConfig         *Config
	userConfigFinder   configFinder
	loadConfigs        sync.Once
	onceErr            error
}
func homedir() string {
	user, err := osuser.Current()
	if err == nil {
		return user.HomeDir
	} else {
		return os.Getenv("HOME")
	}
}
func userConfigFinder() string {
	return filepath.Join(homedir(), ".ssh", "config")
}
var DefaultUserSettings = &UserSettings{
	IgnoreErrors:       false,
	systemConfigFinder: systemConfigFinder,
	userConfigFinder:   userConfigFinder,
}
func systemConfigFinder() string {
	return filepath.Join("/", "etc", "ssh", "ssh_config")
}
func findVal(c *Config, alias, key string) (string, error) {
	if c == nil {
		return "", nil
	}
	val, err := c.Get(alias, key)
	if err != nil || val == "" {
		return "", err
	}
	if err := validate(key, val); err != nil {
		return "", err
	}
	return val, nil
}
func findAll(c *Config, alias, key string) ([]string, error) {
	if c == nil {
		return nil, nil
	}
	return c.GetAll(alias, key)
}
func Get(alias, key string) string {
	return DefaultUserSettings.Get(alias, key)
}
func GetAll(alias, key string) []string {
	return DefaultUserSettings.GetAll(alias, key)
}
func GetStrict(alias, key string) (string, error) {
	return DefaultUserSettings.GetStrict(alias, key)
}
func GetAllStrict(alias, key string) ([]string, error) {
	return DefaultUserSettings.GetAllStrict(alias, key)
}
func (u *UserSettings) Get(alias, key string) string {
	val, err := u.GetStrict(alias, key)
	if err != nil {
		return ""
	}
	return val
}
func (u *UserSettings) GetAll(alias, key string) []string {
	val, _ := u.GetAllStrict(alias, key)
	return val
}
func (u *UserSettings) GetStrict(alias, key string) (string, error) {
	u.doLoadConfigs()
	if u.onceErr != nil && u.IgnoreErrors == false {
		return "", u.onceErr
	}
	val, err := findVal(u.userConfig, alias, key)
	if err != nil || val != "" {
		return val, err
	}
	val2, err2 := findVal(u.systemConfig, alias, key)
	if err2 != nil || val2 != "" {
		return val2, err2
	}
	return Default(key), nil
}
func (u *UserSettings) GetAllStrict(alias, key string) ([]string, error) {
	u.doLoadConfigs()
	if u.onceErr != nil && u.IgnoreErrors == false {
		return nil, u.onceErr
	}
	val, err := findAll(u.userConfig, alias, key)
	if err != nil || val != nil {
		return val, err
	}
	val2, err2 := findAll(u.systemConfig, alias, key)
	if err2 != nil || val2 != nil {
		return val2, err2
	}
	if def := Default(key); def != "" {
		return []string{def}, nil
	}
	return []string{}, nil
}
func (u *UserSettings) doLoadConfigs() {
	u.loadConfigs.Do(func() {
		var filename string
		if u.userConfigFinder == nil {
			filename = userConfigFinder()
		} else {
			filename = u.userConfigFinder()
		}
		var err error
		u.userConfig, err = parseFile(filename)
		if err != nil && os.IsNotExist(err) == false {
			u.onceErr = err
			return
		}
		if u.systemConfigFinder == nil {
			filename = systemConfigFinder()
		} else {
			filename = u.systemConfigFinder()
		}
		u.systemConfig, err = parseFile(filename)
		if err != nil && os.IsNotExist(err) == false {
			u.onceErr = err
			return
		}
	})
}
func parseFile(filename string) (*Config, error) {
	return parseWithDepth(filename, 0)
}
func parseWithDepth(filename string, depth uint8) (*Config, error) {
	b, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, err
	}
	return decodeBytes(b, isSystem(filename), depth)
}
func isSystem(filename string) bool {
	return strings.HasPrefix(filepath.Clean(filename), "/etc/ssh")
}
func Decode(r io.Reader) (*Config, error) {
	b, err := ioutil.ReadAll(r)
	if err != nil {
		return nil, err
	}
	return decodeBytes(b, false, 0)
}
func decodeBytes(b []byte, system bool, depth uint8) (c *Config, err error) {
	defer func() {
		if r := recover(); r != nil {
			if _, ok := r.(runtime.Error); ok {
				panic(r)
			}
			if e, ok := r.(error); ok && e == ErrDepthExceeded {
				err = e
				return
			}
			err = errors.New(r.(string))
		}
	}()
	c = parseSSH(lexSSH(b), system, depth)
	return c, err
}
type Config struct {
	Hosts    []*Host
	depth    uint8
	position Position
}
func (c *Config) Get(alias, key string) (string, error) {
	lowerKey := strings.ToLower(key)
	for _, host := range c.Hosts {
		if !host.Matches(alias) {
			continue
		}
		for _, node := range host.Nodes {
			switch t := node.(type) {
			case *Empty:
				continue
			case *KV:
				lkey := strings.ToLower(t.Key)
				if lkey == "match" {
					panic("can't handle Match directives")
				}
				if lkey == lowerKey {
					return t.Value, nil
				}
			case *Include:
				val := t.Get(alias, key)
				if val != "" {
					return val, nil
				}
			default:
				return "", fmt.Errorf("unknown Node type %v", t)
			}
		}
	}
	return "", nil
}