// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris

package net

import (
	
	
	
	
)

// nssConf represents the state of the machine's /etc/nsswitch.conf file.
type nssConf struct {
	err     error                  // any error encountered opening or parsing the file
	sources map[string][]nssSource // keyed by database (e.g. "hosts")
}

type nssSource struct {
	source   string // e.g. "compat", "files", "mdns4_minimal"
	criteria []nssCriterion
}

// standardCriteria reports all specified criteria have the default
// status actions.
func ( nssSource) () bool {
	for ,  := range .criteria {
		if !.standardStatusAction( == len(.criteria)-1) {
			return false
		}
	}
	return true
}

// nssCriterion is the parsed structure of one of the criteria in brackets
// after an NSS source name.
type nssCriterion struct {
	negate bool   // if "!" was present
	status string // e.g. "success", "unavail" (lowercase)
	action string // e.g. "return", "continue" (lowercase)
}

// standardStatusAction reports whether c is equivalent to not
// specifying the criterion at all. last is whether this criteria is the
// last in the list.
func ( nssCriterion) ( bool) bool {
	if .negate {
		return false
	}
	var  string
	switch .status {
	case "success":
		 = "return"
	case "notfound", "unavail", "tryagain":
		 = "continue"
	default:
		// Unknown status
		return false
	}
	if  && .action == "return" {
		return true
	}
	return .action == 
}

func parseNSSConfFile( string) *nssConf {
	,  := os.Open()
	if  != nil {
		return &nssConf{err: }
	}
	defer .Close()
	return parseNSSConf()
}

func parseNSSConf( io.Reader) *nssConf {
	,  := readFull()
	if  != nil {
		return &nssConf{err: }
	}
	 := new(nssConf)
	.err = foreachLine(, func( []byte) error {
		 = trimSpace(removeComment())
		if len() == 0 {
			return nil
		}
		 := bytealg.IndexByte(, ':')
		if  == -1 {
			return errors.New("no colon on line")
		}
		 := string(trimSpace([:]))
		 := [+1:]
		for {
			 = trimSpace()
			if len() == 0 {
				break
			}
			 := bytealg.IndexByte(, ' ')
			var  string
			if  == -1 {
				 = string()
				 = nil // done
			} else {
				 = string([:])
				 = trimSpace([+1:])
			}
			var  []nssCriterion
			// See if there's a criteria block in brackets.
			if len() > 0 && [0] == '[' {
				 := bytealg.IndexByte(, ']')
				if  == -1 {
					return errors.New("unclosed criterion bracket")
				}
				var  error
				,  = parseCriteria([1:])
				if  != nil {
					return errors.New("invalid criteria: " + string([1:]))
				}
				 = [+1:]
			}
			if .sources == nil {
				.sources = make(map[string][]nssSource)
			}
			.sources[] = append(.sources[], nssSource{
				source:   ,
				criteria: ,
			})
		}
		return nil
	})
	return 
}

// parses "foo=bar !foo=bar"
func parseCriteria( []byte) ( []nssCriterion,  error) {
	 = foreachField(, func( []byte) error {
		 := false
		if len() > 0 && [0] == '!' {
			 = true
			 = [1:]
		}
		if len() < 3 {
			return errors.New("criterion too short")
		}
		 := bytealg.IndexByte(, '=')
		if  == -1 {
			return errors.New("criterion lacks equal sign")
		}
		lowerASCIIBytes()
		 = append(, nssCriterion{
			negate: ,
			status: string([:]),
			action: string([+1:]),
		})
		return nil
	})
	return
}