<commit_before>package safearray

import "github.com/go-ole/com"

// COMArray is how COM handles arrays.
type COMArray struct {
	Dimensions   uint16
	FeaturesFlag uint16
	ElementsSize uint32
	LocksAmount  uint32
	Data         uint32
	Bounds       uintptr
}

// Bounds defines the array boundaries.
type Bounds struct {
	Elements   uint32
	LowerBound int32
}

// SafeArray storage container with helpers.
//
// It is recommended that you use this type instead of the COMArray, because
// the bounds is a pointer to the SafeArrayBounds and not referenced directly.
type Array struct {
	Array *COMArray

	// bounds contains a mirror of the COMArray.Bounds in the Go type.
	bounds []Bounds
}

// Destroy SafeArray object.
func (sa *Array) Destroy() error {
	return Destroy(sa.Array)
}

// DestroyData removes safe array data.
func (sa *Array) DestroyData() error {
	return DestroyData(sa.Array)
}

// DestroyDescriptor removes safe array descriptor.
func (sa *Array) DestroyDescriptor() error {
	return DestroyDescriptor(sa.Array)
}

// Duplicate SafeArray to another SafeArray.
//
// This copies the underlying COMArray object into another Array object.
func (sa *Array) Duplicate() (*Array, error) {
	saCopy, err := Duplicate(sa.Array)
	return &Array{saCopy}, err
}

// DuplicateDataTo takes current SafeArray Data and copies to given SafeArray.
//
// This copies the underlying COMArray data into another SafeArray
// COMArray object.
func (sa *Array) DuplicateDataTo(duplicate *Array) error {
	return DuplicateData(sa.Array, duplicate.Array)
}

// Dimensions is the total number of array of arrays.
//
// For example is dimensions returns 3, then you have:
//
//     array[0][]
//     array[1][]
//     array[2][]
//
// And so on for other lengths.
func (sa *Array) Dimensions() (uint32, error) {
	return GetDimensions(sa.Array)
}

func (sa *Array) ResetDimensions(bounds []Bounds) error {
	sa.bounds = bounds
	return ResetDimensions(sa.Array, &sa.bounds[0])
}

// ElementSize is the type's size.
func (sa *Array) ElementSize() (uint32, error) {
	return GetElementSize(sa.Array)
}

// TotalElements returns total elements for given dimension.
//
// Dimensions start at 1, this will only be corrected if you enter '0'.
func (sa *Array) TotalElements(dimension uint32) (totalElements int64, err error) {
	if dimension < 1 {
		dimension = 1
	}

	// Get array bounds
	var LowerBounds int64
	var UpperBounds int64

	LowerBounds, err = GetLowerBound(sa.Array, dimension)
	if err != nil {
		return
	}

	UpperBounds, err = GetUpperBound(sa.Array, dimension)
	if err != nil {
		return
	}

	totalElements = UpperBounds - LowerBounds + 1
	return
}

// SetElementAt with element value at index.
//
// XXX: Index must be defined on how it works with multidimensional arrays.
func (sa *Array) SetElementAt(index int64, element interface{}) error {
	return PutElement(sa.Array, index, &element)
}

// ElementAt returns element at index.
//
// Returned value will need to be converted to the type you require, because it
// is an interface{}.
//
// XXX: Index must be defined on how it works with multidimensional arrays.
func (sa *Array) ElementAt(index int64) (interface{}, error) {
	return GetElement(sa.Array, index)
}

// ElementFor puts element value into given element.
//
// You do not need to convert element. It will be typed to the interface. This
// is an unsafe operation. Element must be passed by reference.
//
// XXX: Index must be defined on how it works with multidimensional arrays.
func (sa *Array) ElementFor(index int64, element interface{}) error {
	return PutElementIn(sa.Array, index, &element)
}

// SetInterfaceID sets the IID for the COM array.
//
// This is only used when serving COM arrays to clients.
func (sa *Array) SetInterfaceID(interfaceID *com.GUID) error {
	return SetInterfaceID(sa.Array, &interfaceID)
}

// InterfaceID may return the IID, if the array type is a COM object.
func (sa *Array) InterfaceID() (*com.GUID, error) {
	return GetInterfaceID(sa.Array)
}

func (sa *Array) VariantType() (varType com.VariantType, err error) {
	vt, err := GetVariantType(sa.Array)
	varType = com.VariantType(vt)
	return
}

// Lock for modification.
func (sa *Array) Lock() error {
	return Lock(sa.Array)
}

// UnlockArray for reading.
func (sa *Array) Unlock() error {
	return Unlock(sa.Array)
}

// RecordInfo retrieves IRecordInfo for SafeArray.
//
// XXX: Must implement IRecordInfo interface for this to return.
func (sa *Array) RecordInfo() (interface{}, error) {
	return GetRecordInfo(sa.Array)
}

// SetRecordInfo sets IRecordInfo for SafeArray.
//
// XXX: Must implement IRecordInfo interface for this to return.
func (sa *Array) SetRecordInfo(info interface{}) error {
	return SetRecordInfo(sa.Array, info)
}

// ToArray converts SafeArray data to arbitrary type slice.
func (sa *Array) ToArray(value interface{}) (err error) {
	// TODO: Complete.
	dimensions := GetDimensions(sa.Array)
}
<commit_msg>* Rename length helpers to better describe their function. * Complete more of the helpers for converting to a Go Array. (Needs to be tested.)<commit_after>package safearray

import (
	"errors"
	"reflect"
	"unsafe"

	"github.com/go-ole/com"
	"github.com/go-ole/idispatch"
	"github.com/go-ole/iunknown"
)

// COMArray is how COM handles arrays.
type COMArray struct {
	Dimensions   uint16
	FeaturesFlag uint16
	ElementsSize uint32
	LocksAmount  uint32
	Data         uint32

	// This must hold the bytes for two Bounds objects. Use binary.Read() to
	// get the contents.
	Bounds [16]byte
}

// Bounds defines the array boundaries.
type Bounds struct {
	Elements   uint32
	LowerBound int32
}

// SafeArray storage container with helpers.
//
// It is recommended that you use this type instead of the COMArray, because
// the bounds is a pointer to the SafeArrayBounds and not referenced directly.
type Array struct {
	Array *COMArray

	// bounds contains a mirror of the COMArray.Bounds in the Go type.
	bounds []Bounds
}

// Destroy SafeArray object.
func (sa *Array) Destroy() error {
	return Destroy(sa.Array)
}

// DestroyData removes safe array data.
func (sa *Array) DestroyData() error {
	return DestroyData(sa.Array)
}

// DestroyDescriptor removes safe array descriptor.
func (sa *Array) DestroyDescriptor() error {
	return DestroyDescriptor(sa.Array)
}

// Duplicate SafeArray to another SafeArray.
//
// This copies the underlying COMArray object into another Array object.
func (sa *Array) Duplicate() (*Array, error) {
	saCopy, err := Duplicate(sa.Array)
	return &Array{saCopy}, err
}

// DuplicateDataTo takes current SafeArray Data and copies to given SafeArray.
//
// This copies the underlying COMArray data into another SafeArray
// COMArray object.
func (sa *Array) DuplicateDataTo(duplicate *Array) error {
	return DuplicateData(sa.Array, duplicate.Array)
}

// Dimensions is the total number of array of arrays.
//
// For example is dimensions returns 3, then you have:
//
//     array[0][]
//     array[1][]
//     array[2][]
//
// And so on for other lengths.
func (sa *Array) Dimensions() (uint32, error) {
	return GetDimensions(sa.Array)
}

func (sa *Array) ResetDimensions(bounds []Bounds) error {
	sa.bounds = bounds
	return ResetDimensions(sa.Array, &sa.bounds[0])
}

// ElementSize is the type's size.
func (sa *Array) ElementSize() (uint32, error) {
	return GetElementSize(sa.Array)
}

// Length returns total elements for SafeArray.
func (sa *Array) Length() (totalElements int64, err error) {
	totalElements = 0
	dimensions, err := sa.Dimensions()
	if err != nil {
		return
	}

	for dimension := uint32(1); dimension <= dimensions; dimension++ {
		length, err := sa.DimensionLength(dimension)
		if err != nil {
			return
		}
		totalElements += length
	}

	return
}

// DimensionLength returns total elements for given dimension.
//
// Dimensions start at 1, this will only be corrected if you enter '0'.
func (sa *Array) DimensionLength(dimension uint32) (totalElements int64, err error) {
	if dimension < 1 {
		dimension = 1
	}

	// Get array bounds
	var LowerBounds int64
	var UpperBounds int64

	LowerBounds, err = GetLowerBound(sa.Array, dimension)
	if err != nil {
		return
	}

	UpperBounds, err = GetUpperBound(sa.Array, dimension)
	if err != nil {
		return
	}

	totalElements = UpperBounds - LowerBounds + 1
	return
}

// SetElementAt with element value at index.
//
// XXX: Index must be defined on how it works with multidimensional arrays.
func (sa *Array) SetElementAt(index int64, element interface{}) error {
	return PutElement(sa.Array, index, &element)
}

// ElementAt returns element at index.
//
// Returned value will need to be converted to the type you require, because it
// is an interface{}.
//
// XXX: Index must be defined on how it works with multidimensional arrays.
func (sa *Array) ElementAt(index int64) (interface{}, error) {
	return GetElement(sa.Array, index)
}

// ElementFor puts element value into given element.
//
// You do not need to convert element. It will be typed to the interface. This
// is an unsafe operation. Element must be passed by reference.
//
// XXX: Index must be defined on how it works with multidimensional arrays.
func (sa *Array) ElementFor(index int64, element interface{}) error {
	return PutElementIn(sa.Array, index, &element)
}

// SetInterfaceID sets the IID for the COM array.
//
// This is only used when serving COM arrays to clients.
func (sa *Array) SetInterfaceID(interfaceID *com.GUID) error {
	return SetInterfaceID(sa.Array, &interfaceID)
}

// InterfaceID may return the IID, if the array type is a COM object.
func (sa *Array) InterfaceID() (*com.GUID, error) {
	return GetInterfaceID(sa.Array)
}

func (sa *Array) VariantType() (varType com.VariantType, err error) {
	vt, err := GetVariantType(sa.Array)
	varType = com.VariantType(vt)
	return
}

// Lock for modification.
func (sa *Array) Lock() error {
	return Lock(sa.Array)
}

// UnlockArray for reading.
func (sa *Array) Unlock() error {
	return Unlock(sa.Array)
}

// RecordInfo retrieves IRecordInfo for SafeArray.
//
// XXX: Must implement IRecordInfo interface for this to return.
func (sa *Array) RecordInfo() (interface{}, error) {
	return GetRecordInfo(sa.Array)
}

// SetRecordInfo sets IRecordInfo for SafeArray.
//
// XXX: Must implement IRecordInfo interface for this to return.
func (sa *Array) SetRecordInfo(info interface{}) error {
	return SetRecordInfo(sa.Array, info)
}

// PutInArray converts SafeArray data in to arbitrary type slice.
//
// This works on both single dimensional and multidimensional arrays. It will
// convert multidimensional to single dimensional arrays. This will not change
// in the future. A separate method exists for returning a multidimensional
// array.
func (sa *Array) PutInArray(slice interface{}) (err error) {
	if !IsSlice(slice) {
		err = errors.New("must be a slice.")
		return
	}

	dimensions, err := GetDimensions(sa.Array)
	if err != nil {
		return
	}

	length, err := sa.Length()
	if err != nil {
		return
	}

	kind := reflect.ValueOf(slice).Kind()

	if dimensions == 1 && kind != reflect.String {
		err = MarshalArray(sa.Array, length, &slice)
		return
	}

	t := reflect.TypeOf(slice)

	for i := int64(0); i < length; i++ {
		if kind != string {
			element := reflect.New(t).Interface()
			err = PutElementIn(sa.Array, i, &element)
			if err != nil {
				return
			}
			*slice = append(slice, element)
		} else {
			element, err := GetElementString(sa.Array, i)
			if err != nil {
				return
			}
			*slice = append(slice, element)
		}
	}
}

func (sa *Array) ToArray() (slice interface{}, err error) {
	vt, err := sa.VariantType()
	if err != nil {
		return
	}

	// Must not have VT_ARRAY and VT_BYREF flags set.
	// Must not be VT_EMPTY and VT_NULL.

	switch vt {
	case com.Float32VariantType:
		slice = make([]float32, sa.Length())
		err = sa.PutInArray(&slice)
		return
	case com.Float64VariantType:
		slice = make([]float64, sa.Length())
		err = sa.PutInArray(&slice)
		return
	case com.CurrencyVariantType:
		slice = make([]*com.Currency, sa.Length())
		err = sa.PutInArray(&slice)
		return
	case com.DateVariantType:
		err = errors.New("variant type is not implemented")
	case com.BinaryStringVariantType, com.ClassIDVariantType:
		slice = make([]string, sa.Length())
		err = sa.PutInArray(&slice)
		return
	case com.IDispatchVariantType:
		slice = make([]*idispatch.Dispatch, sa.Length())
		err = sa.PutInArray(&slice)
		return
	case com.ErrorVariantType:
		err = errors.New("variant type is not implemented")
	case com.BoolVariantType:
		slice = make([]uint16, sa.Length())
		err = sa.PutInArray(&slice)
		return
	case com.VariantVariantType:
		slice = make([]*com.Variant, sa.Length())
		err = sa.PutInArray(&slice)
		return
	case com.IUnknownVariantType:
		slice = make([]*iunknown.Unknown, sa.Length())
		err = sa.PutInArray(&slice)
		return
	case com.DecimalVariantType:
		slice = make([]*com.Decimal, sa.Length())
		err = sa.PutInArray(&slice)
		return
	case com.Integer8VariantType:
		slice = make([]int8, sa.Length())
		err = sa.PutInArray(&slice)
		return
	case com.UInteger8VariantType:
		slice = make([]uint8, sa.Length())
		err = sa.PutInArray(&slice)
		return
	case com.Integer16VariantType:
		slice = make([]int16, sa.Length())
		err = sa.PutInArray(&slice)
		return
	case com.UInteger16VariantType:
		slice = make([]uint16, sa.Length())
		err = sa.PutInArray(&slice)
		return
	case com.Integer32VariantType:
		slice = make([]int32, sa.Length())
		err = sa.PutInArray(&slice)
		return
	case com.UInteger32VariantType:
		slice = make([]uint32, sa.Length())
		err = sa.PutInArray(&slice)
		return
	case com.Integer64VariantType:
		slice = make([]int64, sa.Length())
		err = sa.PutInArray(&slice)
		return
	case com.UInteger64VariantType:
		slice = make([]uint64, sa.Length())
		err = sa.PutInArray(&slice)
		return
	case com.IntegerVariantType:
		// Warning: This must match the architecture of the application you wish
		// to access.
		slice = make([]int, sa.Length())
		err = sa.PutInArray(&slice)
		return
	case com.UIntegerVariantType:
		// Warning: This must match the architecture of the application you wish
		// to access.
		slice = make([]uint, sa.Length())
		err = sa.PutInArray(&slice)
		return
	case com.HResultVariantType:
		// Warning: This must match the architecture of the application you wish
		// to access.
		slice = make([]uintptr, sa.Length())
		err = sa.PutInArray(&slice)
		// TODO: Need to turn HResult into OleError.
		return
	case com.PointerVariantType:
		slice = make([]unsafe.Pointer, sa.Length())
		err = sa.PutInArray(&slice)
		return
	case com.SafeArrayVariantType:
		slice = make([]*COMArray, sa.Length())
		err = sa.PutInArray(&slice)
		// Need to turn into Array objects
		return
	case com.CArrayVariantType:
		// TODO: Complete
		err = errors.New("variant type is not implemented")
	case com.ANSIStringVariantType:
		// TODO: Complete
		err = errors.New("variant type is not implemented")
	case com.UnicodeStringVariantType:
		// TODO: Complete
		err = errors.New("variant type is not implemented")
	case com.RecordVariantType:
		// TODO: Complete
		err = errors.New("variant type is not implemented")
	case com.IntegerPointerVariantType, com.UIntegerPointerVariantType:
		slice = make([]uintptr, sa.Length())
		err = sa.PutInArray(&slice)
		return
	case com.FileTimeVariantType:
		slice = make([]*com.FileTime, sa.Length())
		err = sa.PutInArray(&slice)
		return
	case com.ClipboardFormatVariantType:
		// TODO: Complete
		err = errors.New("variant type is not implemented")
	default:
		err = errors.New("variant type is not supported")
	}

	return
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"runtime/pprof"
	"sort"
	"text/tabwriter"
)

const VERSION = `0.2.1`

var languages = []Language{
	Language{"Thrift", mExt(".thrift"), cComments},

	Language{"C", mExt(".c", ".h"), cComments},
	Language{"C++", mExt(".cc", ".cpp", ".cxx", ".hh", ".hpp", ".hxx"), cComments},
	Language{"Go", mExt(".go"), cComments},
	Language{"Scala", mExt(".scala"), cComments},
	Language{"Java", mExt(".java"), cComments},

	Language{"YACC", mExt(".y"), cComments},
	Language{"Lex", mExt(".l"), cComments},

	Language{"SQL", mExt(".sql"), sqlComments},

	Language{"Haskell", mExt(".hs", ".lhs"), hsComments},

	Language{"Perl", mExt(".pl", ".pm"), perlComments},
	Language{"PHP", mExt(".php"), cComments},

	Language{"Shell", mExt(".sh"), shComments},
	Language{"Bash", mExt(".bash"), shComments},

	Language{"Ruby", mExt(".rb"), shComments},
	Language{"Python", mExt(".py"), pyComments},
	Language{"Assembly", mExt(".asm", ".s"), semiComments},
	Language{"Lisp", mExt(".lsp", ".lisp"), semiComments},
	Language{"Scheme", mExt(".scm", ".scheme"), semiComments},

	Language{"Make", mName("makefile", "Makefile", "MAKEFILE"), shComments},
	Language{"CMake", mName("CMakeLists.txt"), shComments},
	Language{"Jam", mName("Jamfile", "Jamrules"), shComments},

	Language{"Markdown", mExt(".md"), noComments},

	Language{"HAML", mExt(".haml"), noComments},
	Language{"SASS", mExt(".sass"), cssComments},
	Language{"SCSS", mExt(".scss"), cssComments},

	Language{"HTML", mExt(".htm", ".html", ".xhtml"), xmlComments},
	Language{"XML", mExt(".xml"), xmlComments},
	Language{"CSS", mExt(".css"), cssComments},
	Language{"JavaScript", mExt(".js"), cComments},
}

type Commenter struct {
	LineComment  string
	StartComment string
	EndComment   string
	Nesting      bool
}

var (
	noComments   = Commenter{"\000", "\000", "\000", false}
	xmlComments  = Commenter{"\000", `<!--`, `-->`, false}
	cComments    = Commenter{`//`, `/*`, `*/`, false}
	cssComments  = Commenter{"\000", `/*`, `*/`, false}
	shComments   = Commenter{`#`, "\000", "\000", false}
	semiComments = Commenter{`;`, "\000", "\000", false}
	hsComments   = Commenter{`--`, `{-`, `-}`, true}
	sqlComments  = Commenter{`--`, "\000", "\000", false}
	pyComments   = Commenter{`#`, `"""`, `"""`, false}

	// TODO support POD and __END__
	perlComments = Commenter{`#`, "\000", "\000", false}
)

type Language struct {
	Namer
	Matcher
	Commenter
}

// TODO work properly with unicode
func (l Language) Update(c []byte, s *Stats) {
	s.FileCount++

	inComment := 0 // this is an int for nesting
	inLComment := false
	blank := true
	lc := []byte(l.LineComment)
	sc := []byte(l.StartComment)
	ec := []byte(l.EndComment)
	lp, sp, ep := 0, 0, 0

	for _, b := range c {
		if inComment == 0 && b == lc[lp] {
			lp++
			if lp == len(lc) {
				inLComment = true
				lp = 0
			}
		} else {
			lp = 0
		}
		if !inLComment && b == sc[sp] {
			sp++
			if sp == len(sc) {
				inComment++
				if inComment > 1 && !l.Nesting {
					inComment = 1
				}
				sp = 0
			}
		} else {
			sp = 0
		}
		if !inLComment && inComment > 0 && b == ec[ep] {
			ep++
			if ep == len(ec) {
				if inComment > 0 {
					inComment--
				}
				ep = 0
			}
		} else {
			ep = 0
		}

		if b != byte(' ') && b != byte('\t') && b != byte('\n') {
			blank = false
		}

		// BUG(srl): lines with comment don't count towards code
		// Note that lines with both code and comment count towards
		// each, but are not counted twice in the total.
		if b == byte('\n') {
			s.TotalLines++
			if inComment > 0 || inLComment {
				inLComment = false
				s.CommentLines++
			} else if blank {
				s.BlankLines++
			} else {
				s.CodeLines++
			}
			blank = true
			continue
		}
	}
}

type Namer string

func (l Namer) Name() string { return string(l) }

type Matcher func(string) bool

func (m Matcher) Match(fname string) bool { return m(fname) }

func mExt(exts ...string) Matcher {
	return func(fname string) bool {
		for _, ext := range exts {
			if ext == path.Ext(fname) {
				return true
			}
		}
		return false
	}
}

func mName(names ...string) Matcher {
	return func(fname string) bool {
		for _, name := range names {
			if name == path.Base(fname) {
				return true
			}
		}
		return false
	}
}

type Stats struct {
	FileCount    int
	TotalLines   int
	CodeLines    int
	BlankLines   int
	CommentLines int
}

var info = map[string]*Stats{}

func handleFileLang(fname string, l Language) {
	i, ok := info[l.Name()]
	if !ok {
		i = &Stats{}
		info[l.Name()] = i
	}
	c, err := ioutil.ReadFile(fname)
	if err != nil {
		fmt.Fprintf(os.Stderr, "  ! %s\n", fname)
		return
	}
	l.Update(c, i)
}

func handleFile(fname string) {
	for _, lang := range languages {
		if lang.Match(fname) {
			handleFileLang(fname, lang)
			return
		}
	}
	// TODO No recognized extension - check for hashbang
}

var files []string

func add(n string) {
	fi, err := os.Stat(n)
	if err != nil {
		goto invalid
	}
	if fi.IsDir() {
		fs, err := ioutil.ReadDir(n)
		if err != nil {
			goto invalid
		}
		for _, f := range fs {
			if f.Name()[0] != '.' {
				add(path.Join(n, f.Name()))
			}
		}
		return
	}
	if fi.Mode()&os.ModeType == 0 {
		files = append(files, n)
		return
	}

	println(fi.Mode())

invalid:
	fmt.Fprintf(os.Stderr, "  ! %s\n", n)
}

type LData []LResult

func (d LData) Len() int { return len(d) }

func (d LData) Less(i, j int) bool {
	if d[i].CodeLines == d[j].CodeLines {
		return d[i].Name > d[j].Name
	}
	return d[i].CodeLines > d[j].CodeLines
}

func (d LData) Swap(i, j int) {
	d[i], d[j] = d[j], d[i]
}

type LResult struct {
	Name         string
	FileCount    int
	CodeLines    int
	CommentLines int
	BlankLines   int
	TotalLines   int
}

func (r *LResult) Add(a LResult) {
	r.FileCount += a.FileCount
	r.CodeLines += a.CodeLines
	r.CommentLines += a.CommentLines
	r.BlankLines += a.BlankLines
	r.TotalLines += a.TotalLines
}

func printJSON() {
	bs, err := json.MarshalIndent(info, "", "  ")
	if err != nil {
		panic(err)
	}
	fmt.Println(string(bs))
}

func printInfo() {
	w := tabwriter.NewWriter(os.Stdout, 2, 8, 2, ' ', tabwriter.AlignRight)
	fmt.Fprintln(w, "Language\tFiles\tCode\tComment\tBlank\tTotal\t")
	d := LData([]LResult{})
	total := &LResult{}
	total.Name = "Total"
	for n, i := range info {
		r := LResult{n, i.FileCount, i.CodeLines, i.CommentLines, i.BlankLines, i.TotalLines}
		d = append(d, r)
		total.Add(r)
	}
	d = append(d, *total)
	sort.Sort(d)
	for _, i := range d {
		fmt.Fprintf(w, "%s\t%d\t%d\t%d\t%d\t%d\t\n", i.Name, i.FileCount, i.CodeLines, i.CommentLines, i.BlankLines, i.TotalLines)
	}

	w.Flush()
}

var (
	cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
	useJson    = flag.Bool("json", false, "JSON-format output")
	version    = flag.Bool("V", false, "display version info and exit")
)

func main() {
	flag.Parse()
	if *version {
		fmt.Printf("sloc %s\n", VERSION)
		return
	}
	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			fmt.Fprintf(os.Stderr, "error: %s\n", err.Error())
			return
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	args := flag.Args()
	if len(args) == 0 {
		args = append(args, `.`)
	}

	for _, n := range args {
		add(n)
	}

	for _, f := range files {
		handleFile(f)
	}

	if *useJson {
		printJSON()
	} else {
		printInfo()
	}
}
<commit_msg>Version 0.2.2<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"runtime/pprof"
	"sort"
	"text/tabwriter"
)

const VERSION = `0.2.2`

var languages = []Language{
	Language{"Thrift", mExt(".thrift"), cComments},

	Language{"C", mExt(".c", ".h"), cComments},
	Language{"C++", mExt(".cc", ".cpp", ".cxx", ".hh", ".hpp", ".hxx"), cComments},
	Language{"Go", mExt(".go"), cComments},
	Language{"Scala", mExt(".scala"), cComments},
	Language{"Java", mExt(".java"), cComments},

	Language{"YACC", mExt(".y"), cComments},
	Language{"Lex", mExt(".l"), cComments},

	Language{"SQL", mExt(".sql"), sqlComments},

	Language{"Haskell", mExt(".hs", ".lhs"), hsComments},

	Language{"Perl", mExt(".pl", ".pm"), perlComments},
	Language{"PHP", mExt(".php"), cComments},

	Language{"Shell", mExt(".sh"), shComments},
	Language{"Bash", mExt(".bash"), shComments},

	Language{"Ruby", mExt(".rb"), shComments},
	Language{"Python", mExt(".py"), pyComments},
	Language{"Assembly", mExt(".asm", ".s"), semiComments},
	Language{"Lisp", mExt(".lsp", ".lisp"), semiComments},
	Language{"Scheme", mExt(".scm", ".scheme"), semiComments},

	Language{"Make", mName("makefile", "Makefile", "MAKEFILE"), shComments},
	Language{"CMake", mName("CMakeLists.txt"), shComments},
	Language{"Jam", mName("Jamfile", "Jamrules"), shComments},

	Language{"Markdown", mExt(".md"), noComments},

	Language{"HAML", mExt(".haml"), noComments},
	Language{"SASS", mExt(".sass"), cssComments},
	Language{"SCSS", mExt(".scss"), cssComments},

	Language{"HTML", mExt(".htm", ".html", ".xhtml"), xmlComments},
	Language{"XML", mExt(".xml"), xmlComments},
	Language{"CSS", mExt(".css"), cssComments},
	Language{"JavaScript", mExt(".js"), cComments},
}

type Commenter struct {
	LineComment  string
	StartComment string
	EndComment   string
	Nesting      bool
}

var (
	noComments   = Commenter{"\000", "\000", "\000", false}
	xmlComments  = Commenter{"\000", `<!--`, `-->`, false}
	cComments    = Commenter{`//`, `/*`, `*/`, false}
	cssComments  = Commenter{"\000", `/*`, `*/`, false}
	shComments   = Commenter{`#`, "\000", "\000", false}
	semiComments = Commenter{`;`, "\000", "\000", false}
	hsComments   = Commenter{`--`, `{-`, `-}`, true}
	sqlComments  = Commenter{`--`, "\000", "\000", false}
	pyComments   = Commenter{`#`, `"""`, `"""`, false}

	// TODO support POD and __END__
	perlComments = Commenter{`#`, "\000", "\000", false}
)

type Language struct {
	Namer
	Matcher
	Commenter
}

// TODO work properly with unicode
func (l Language) Update(c []byte, s *Stats) {
	s.FileCount++

	inComment := 0 // this is an int for nesting
	inLComment := false
	blank := true
	lc := []byte(l.LineComment)
	sc := []byte(l.StartComment)
	ec := []byte(l.EndComment)
	lp, sp, ep := 0, 0, 0

	for _, b := range c {
		if inComment == 0 && b == lc[lp] {
			lp++
			if lp == len(lc) {
				inLComment = true
				lp = 0
			}
		} else {
			lp = 0
		}
		if !inLComment && b == sc[sp] {
			sp++
			if sp == len(sc) {
				inComment++
				if inComment > 1 && !l.Nesting {
					inComment = 1
				}
				sp = 0
			}
		} else {
			sp = 0
		}
		if !inLComment && inComment > 0 && b == ec[ep] {
			ep++
			if ep == len(ec) {
				if inComment > 0 {
					inComment--
				}
				ep = 0
			}
		} else {
			ep = 0
		}

		if b != byte(' ') && b != byte('\t') && b != byte('\n') {
			blank = false
		}

		// BUG(srl): lines with comment don't count towards code
		// Note that lines with both code and comment count towards
		// each, but are not counted twice in the total.
		if b == byte('\n') {
			s.TotalLines++
			if inComment > 0 || inLComment {
				inLComment = false
				s.CommentLines++
			} else if blank {
				s.BlankLines++
			} else {
				s.CodeLines++
			}
			blank = true
			continue
		}
	}
}

type Namer string

func (l Namer) Name() string { return string(l) }

type Matcher func(string) bool

func (m Matcher) Match(fname string) bool { return m(fname) }

func mExt(exts ...string) Matcher {
	return func(fname string) bool {
		for _, ext := range exts {
			if ext == path.Ext(fname) {
				return true
			}
		}
		return false
	}
}

func mName(names ...string) Matcher {
	return func(fname string) bool {
		for _, name := range names {
			if name == path.Base(fname) {
				return true
			}
		}
		return false
	}
}

type Stats struct {
	FileCount    int
	TotalLines   int
	CodeLines    int
	BlankLines   int
	CommentLines int
}

var info = map[string]*Stats{}

func handleFileLang(fname string, l Language) {
	i, ok := info[l.Name()]
	if !ok {
		i = &Stats{}
		info[l.Name()] = i
	}
	c, err := ioutil.ReadFile(fname)
	if err != nil {
		fmt.Fprintf(os.Stderr, "  ! %s\n", fname)
		return
	}
	l.Update(c, i)
}

func handleFile(fname string) {
	for _, lang := range languages {
		if lang.Match(fname) {
			handleFileLang(fname, lang)
			return
		}
	}
	// TODO No recognized extension - check for hashbang
}

var files []string

func add(n string) {
	fi, err := os.Stat(n)
	if err != nil {
		goto invalid
	}
	if fi.IsDir() {
		fs, err := ioutil.ReadDir(n)
		if err != nil {
			goto invalid
		}
		for _, f := range fs {
			if f.Name()[0] != '.' {
				add(path.Join(n, f.Name()))
			}
		}
		return
	}
	if fi.Mode()&os.ModeType == 0 {
		files = append(files, n)
		return
	}

	println(fi.Mode())

invalid:
	fmt.Fprintf(os.Stderr, "  ! %s\n", n)
}

type LData []LResult

func (d LData) Len() int { return len(d) }

func (d LData) Less(i, j int) bool {
	if d[i].CodeLines == d[j].CodeLines {
		return d[i].Name > d[j].Name
	}
	return d[i].CodeLines > d[j].CodeLines
}

func (d LData) Swap(i, j int) {
	d[i], d[j] = d[j], d[i]
}

type LResult struct {
	Name         string
	FileCount    int
	CodeLines    int
	CommentLines int
	BlankLines   int
	TotalLines   int
}

func (r *LResult) Add(a LResult) {
	r.FileCount += a.FileCount
	r.CodeLines += a.CodeLines
	r.CommentLines += a.CommentLines
	r.BlankLines += a.BlankLines
	r.TotalLines += a.TotalLines
}

func printJSON() {
	bs, err := json.MarshalIndent(info, "", "  ")
	if err != nil {
		panic(err)
	}
	fmt.Println(string(bs))
}

func printInfo() {
	w := tabwriter.NewWriter(os.Stdout, 2, 8, 2, ' ', tabwriter.AlignRight)
	fmt.Fprintln(w, "Language\tFiles\tCode\tComment\tBlank\tTotal\t")
	d := LData([]LResult{})
	total := &LResult{}
	total.Name = "Total"
	for n, i := range info {
		r := LResult{n, i.FileCount, i.CodeLines, i.CommentLines, i.BlankLines, i.TotalLines}
		d = append(d, r)
		total.Add(r)
	}
	d = append(d, *total)
	sort.Sort(d)
	for _, i := range d {
		fmt.Fprintf(w, "%s\t%d\t%d\t%d\t%d\t%d\t\n", i.Name, i.FileCount, i.CodeLines, i.CommentLines, i.BlankLines, i.TotalLines)
	}

	w.Flush()
}

var (
	cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
	useJson    = flag.Bool("json", false, "JSON-format output")
	version    = flag.Bool("V", false, "display version info and exit")
)

func main() {
	flag.Parse()
	if *version {
		fmt.Printf("sloc %s\n", VERSION)
		return
	}
	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			fmt.Fprintf(os.Stderr, "error: %s\n", err.Error())
			return
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	args := flag.Args()
	if len(args) == 0 {
		args = append(args, `.`)
	}

	for _, n := range args {
		add(n)
	}

	for _, f := range files {
		handleFile(f)
	}

	if *useJson {
		printJSON()
	} else {
		printInfo()
	}
}
<|endoftext|>


<commit_before>// Package rtnl provides a convenient API on top of the rtnetlink library.
package rtnl

import (
	"github.com/jsimonetti/rtnetlink"
	"github.com/mdlayher/netlink"
)

// Conn represents the underlying netlink connection
type Conn struct {
	Conn *rtnetlink.Conn // a route netlink connection
}

// Dial the netlink socket. Establishes a new connection. The typical initialisation is:
// 	conn, err := rtnl.Dial(nil)
//	if err != nil {
//		log.Fatal("can't establish netlink connection: ", err)
//	}
//	defer conn.Close()
//	// use conn for your calls
//
func Dial(cfg *netlink.Config) (*Conn, error) {
	conn, err := rtnetlink.Dial(cfg)
	if err != nil {
		return nil, err
	}
	return &Conn{Conn: conn}, nil
}

// Close the connection.
func (c *Conn) Close() {
	c.Conn.Close()
}
<commit_msg>rtnl: do not drop error on Close() but leave to caller<commit_after>// Package rtnl provides a convenient API on top of the rtnetlink library.
package rtnl

import (
	"github.com/jsimonetti/rtnetlink"
	"github.com/mdlayher/netlink"
)

// Conn represents the underlying netlink connection
type Conn struct {
	Conn *rtnetlink.Conn // a route netlink connection
}

// Dial the netlink socket. Establishes a new connection. The typical initialisation is:
// 	conn, err := rtnl.Dial(nil)
//	if err != nil {
//		log.Fatal("can't establish netlink connection: ", err)
//	}
//	defer conn.Close()
//	// use conn for your calls
//
func Dial(cfg *netlink.Config) (*Conn, error) {
	conn, err := rtnetlink.Dial(cfg)
	if err != nil {
		return nil, err
	}
	return &Conn{Conn: conn}, nil
}

// Close the connection.
func (c *Conn) Close() error {
	return c.Conn.Close()
}
<|endoftext|>


<commit_before><commit_msg>removes tachymeter AddCount<commit_after><|endoftext|>


<commit_before>package solr

import (
	"fmt"
	"math"
	"net/url"
)

type M map[string]interface{}

type Document map[string]interface{}

// Has check if a key exist in document
func (d Document) Has(k string) bool {
	_, ok := d[k]
	return ok
}

// Get returns value of a key
func (d Document) Get(k string) interface{} {
	v, _ := d[k]
	return v
}

// Set add a key/value to document
func (d Document) Set(k string, v interface{}) {
	d[k] = v
}

type SolrResponse struct {
	Status   int
	Response map[string]interface{}
}

type SolrUpdateResponse struct {
	Success bool
	Result  map[string]interface{}
}

type Collection struct {
	Docs     []Document
	Start    int
	NumFound int
}

// Parsed result for SearchHandler response, ie /select
type SolrResult struct {
	Status         int         // status quick access to status
	Results        *Collection // results parsed documents, basically response object
	ResponseHeader map[string]interface{}
	FacetCounts    map[string]interface{}
	Highlighting   map[string]interface{}
	Error          map[string]interface{}
	Grouped        map[string]interface{} // grouped for grouping result if grouping Results will be empty
	Stats          map[string]interface{}
	MoreLikeThis   map[string]interface{} // MoreLikeThis using Search (select) Component
}

// Parsed result for MoreLikeThisHandler response, ie /mlt
type SolrMltResult struct {
	Status         int         // status quick access to status
	Results        *Collection // results parsed documents, basically response object
	Match          *Collection // Documents for match section
	ResponseHeader map[string]interface{}
	Error          map[string]interface{}
}

type SolrInterface struct {
	conn *Connection
}

// Return a new instance of SolrInterface
func NewSolrInterface(solrUrl, core string) (*SolrInterface, error) {
	c, err := NewConnection(solrUrl, core)
	if err != nil {
		return nil, err
	}
	return &SolrInterface{conn: c}, nil
}

// Set to new core, this is just wrapper to Connection.SetCore which mean
// it will affect all places that use this Connection instance
func (si *SolrInterface) SetCore(core string) {
	si.conn.SetCore(core)
}

// SetBasicAuth sets the request's Authorization header to use HTTP Basic Authentication with the provided username and password.
// See http://golang.org/pkg/net/http/#Request.SetBasicAuth
func (si *SolrInterface) SetBasicAuth(username, password string) {
	si.conn.SetBasicAuth(username, password)
}

// Return a new instace of Search, q is optional and one can set it later
func (si *SolrInterface) Search(q *Query) *Search {
	return NewSearch(si.conn, q)
}

// makeAddChunks splits the documents into chunks. If chunk_size is less than one it will be default to 100
func makeAddChunks(docs []Document, chunk_size int) []map[string]interface{} {
	if chunk_size < 1 {
		chunk_size = 100
	}
	docs_len := len(docs)
	num_chunk := int(math.Ceil(float64(docs_len) / float64(chunk_size)))
	doc_counter := 0
	chunks := make([]map[string]interface{}, num_chunk)
	for i := 0; i < num_chunk; i++ {
		add := make([]Document, 0, chunk_size)
		for j := 0; j < chunk_size; j++ {
			if doc_counter >= docs_len {
				break
			}
			add = append(add, docs[doc_counter])
			doc_counter++
		}
		chunks[i] = M{"add": add}
	}
	return chunks
}

// Add will insert documents in batch of chunk_size. success is false as long as one chunk failed.
// The result in SolrUpdateResponse is summery of response from all chunks
// with key chunk_%d
func (si *SolrInterface) Add(docs []Document, chunk_size int, params *url.Values) (*SolrUpdateResponse, error) {
	result := &SolrUpdateResponse{Success: true}
	responses := M{}
	chunks := makeAddChunks(docs, chunk_size)

	for i := 0; i < len(chunks); i++ {
		res, err := si.Update(chunks[i], params)
		if err != nil {
			return nil, err
		}
		result.Success = result.Success && res.Success
		responses[fmt.Sprintf("chunk_%d", i+1)] = M{
			"result":  res.Result,
			"success": res.Success,
			"total":   len(chunks[i]["add"].([]Document))}
	}
	result.Result = responses
	return result, nil
}

// Delete take data of type map and optional params which can use to specify addition parameters such as commit=true .
// Only one delete statement is supported, ie data can be { "id":"ID" } .
// If you want to delete more docs use { "query":"QUERY" } .
// Extra params can specify in params or in data such as { "query":"QUERY", "commitWithin":"500" }
func (si *SolrInterface) Delete(data map[string]interface{}, params *url.Values) (*SolrUpdateResponse, error) {
	message := M{"delete": data}
	return si.Update(message, params)
}

// DeleteAll will remove all documents and commit
func (si *SolrInterface) DeleteAll() (*SolrUpdateResponse, error) {
	params := &url.Values{}
	params.Add("commit", "true")
	return si.Delete(M{"query": "*:*"}, params)
}

// Update take data of type map and optional params which can use to specify addition parameters such as commit=true
func (si *SolrInterface) Update(data map[string]interface{}, params *url.Values) (*SolrUpdateResponse, error) {
	if si.conn == nil {
		return nil, fmt.Errorf("No connection found for making request to solr")
	}
	return si.conn.Update(data, params)
}

// Commit the changes since the last commit
func (si *SolrInterface) Commit() (*SolrUpdateResponse, error) {
	params := &url.Values{}
	params.Add("commit", "true")
	return si.Update(M{}, params)
}

func (si *SolrInterface) Optimize(params *url.Values) (*SolrUpdateResponse, error) {
	if params == nil {
		params = &url.Values{}
	}
	params.Set("optimize", "true")
	return si.Update(M{}, params)
}

// Rollback rollbacks all add/deletes made to the index since the last commit.
// This should use with caution.
// See https://wiki.apache.org/solr/UpdateXmlMessages#A.22rollback.22
func (si *SolrInterface) Rollback() (*SolrUpdateResponse, error) {
	return si.Update(M{"rollback": M{}}, nil)
}

// Return new instance of CoreAdmin with provided solrUrl and basic auth
func (si *SolrInterface) CoreAdmin() (*CoreAdmin, error) {
	ca, err := NewCoreAdmin(si.conn.url.String())
	if err != nil {
		return nil, err
	}
	ca.SetBasicAuth(si.conn.username, si.conn.password)
	return ca, nil
}

// Return new instance of Schema with provided solrUrl and basic auth
func (si *SolrInterface) Schema() (*Schema, error) {
	s, err := NewSchema(si.conn.url.String(), si.conn.core)
	if err != nil {
		return nil, err
	}
	s.SetBasicAuth(si.conn.username, si.conn.password)
	return s, nil
}

// Return 'status' and QTime from solr, if everything is fine status should have value 'OK'
// QTime will have value -1 if can not determine
func (si *SolrInterface) Ping() (status string, qtime int, err error) {
	r, err := HTTPGet(fmt.Sprintf("%s/%s/admin/ping?wt=json", si.conn.url.String(), si.conn.core), nil, si.conn.username, si.conn.password)
	if err != nil {
		return "", -1, err
	}

	resp, err := bytes2json(&r)
	if err != nil {
		return "", -1, err
	}
	status, ok := resp["status"].(string)
	if ok == false {
		return "", -1, fmt.Errorf("Unexpected response returned")
	}
	if QTime, ok := resp["responseHeader"].(map[string]interface{})["QTime"].(float64); ok {
		qtime = int(QTime)
	} else {
		qtime = -1
	}
	return status, qtime, nil
}
<commit_msg>Adding some more docstring<commit_after>package solr

import (
	"fmt"
	"math"
	"net/url"
)

// Shortcut for map[string]interface{}
// Use where applicable
type M map[string]interface{}

type Document map[string]interface{}

// Has check if a key exist in document
func (d Document) Has(k string) bool {
	_, ok := d[k]
	return ok
}

// Get returns value of a key
func (d Document) Get(k string) interface{} {
	v, _ := d[k]
	return v
}

// Set add a key/value to document
func (d Document) Set(k string, v interface{}) {
	d[k] = v
}

type SolrResponse struct {
	Status   int
	Response map[string]interface{}
}

type SolrUpdateResponse struct {
	Success bool
	Result  map[string]interface{}
}

// Holding the search result
type Collection struct {
	Docs     []Document
	Start    int
	NumFound int
}

// Parsed result for SearchHandler response, ie /select
type SolrResult struct {
	Status         int         // status quick access to status
	Results        *Collection // results parsed documents, basically response object
	ResponseHeader map[string]interface{}
	FacetCounts    map[string]interface{}
	Highlighting   map[string]interface{}
	Error          map[string]interface{}
	Grouped        map[string]interface{} // grouped for grouping result if grouping Results will be empty
	Stats          map[string]interface{}
	MoreLikeThis   map[string]interface{} // MoreLikeThis using Search (select) Component
}

// Parsed result for MoreLikeThisHandler response, ie /mlt
type SolrMltResult struct {
	Status         int         // status quick access to status
	Results        *Collection // results parsed documents, basically response object
	Match          *Collection // Documents for match section
	ResponseHeader map[string]interface{}
	Error          map[string]interface{}
}

type SolrInterface struct {
	conn *Connection
}

// Return a new instance of SolrInterface
func NewSolrInterface(solrUrl, core string) (*SolrInterface, error) {
	c, err := NewConnection(solrUrl, core)
	if err != nil {
		return nil, err
	}
	return &SolrInterface{conn: c}, nil
}

// Set to new core, this is just wrapper to Connection.SetCore which mean
// it will affect all places that use this Connection instance
func (si *SolrInterface) SetCore(core string) {
	si.conn.SetCore(core)
}

// SetBasicAuth sets the request's Authorization header to use HTTP Basic Authentication with the provided username and password.
// See http://golang.org/pkg/net/http/#Request.SetBasicAuth
func (si *SolrInterface) SetBasicAuth(username, password string) {
	si.conn.SetBasicAuth(username, password)
}

// Return a new instace of Search, q is optional and one can set it later
func (si *SolrInterface) Search(q *Query) *Search {
	return NewSearch(si.conn, q)
}

// makeAddChunks splits the documents into chunks. If chunk_size is less than one it will be default to 100
func makeAddChunks(docs []Document, chunk_size int) []map[string]interface{} {
	if chunk_size < 1 {
		chunk_size = 100
	}
	docs_len := len(docs)
	num_chunk := int(math.Ceil(float64(docs_len) / float64(chunk_size)))
	doc_counter := 0
	chunks := make([]map[string]interface{}, num_chunk)
	for i := 0; i < num_chunk; i++ {
		add := make([]Document, 0, chunk_size)
		for j := 0; j < chunk_size; j++ {
			if doc_counter >= docs_len {
				break
			}
			add = append(add, docs[doc_counter])
			doc_counter++
		}
		chunks[i] = M{"add": add}
	}
	return chunks
}

// Add will insert documents in batch of chunk_size. success is false as long as one chunk failed.
// The result in SolrUpdateResponse is summery of response from all chunks
// with key chunk_%d
func (si *SolrInterface) Add(docs []Document, chunk_size int, params *url.Values) (*SolrUpdateResponse, error) {
	result := &SolrUpdateResponse{Success: true}
	responses := M{}
	chunks := makeAddChunks(docs, chunk_size)

	for i := 0; i < len(chunks); i++ {
		res, err := si.Update(chunks[i], params)
		if err != nil {
			return nil, err
		}
		result.Success = result.Success && res.Success
		responses[fmt.Sprintf("chunk_%d", i+1)] = M{
			"result":  res.Result,
			"success": res.Success,
			"total":   len(chunks[i]["add"].([]Document))}
	}
	result.Result = responses
	return result, nil
}

// Delete take data of type map and optional params which can use to specify addition parameters such as commit=true .
// Only one delete statement is supported, ie data can be { "id":"ID" } .
// If you want to delete more docs use { "query":"QUERY" } .
// Extra params can specify in params or in data such as { "query":"QUERY", "commitWithin":"500" }
func (si *SolrInterface) Delete(data map[string]interface{}, params *url.Values) (*SolrUpdateResponse, error) {
	message := M{"delete": data}
	return si.Update(message, params)
}

// DeleteAll will remove all documents and commit
func (si *SolrInterface) DeleteAll() (*SolrUpdateResponse, error) {
	params := &url.Values{}
	params.Add("commit", "true")
	return si.Delete(M{"query": "*:*"}, params)
}

// Update take data of type map and optional params which can use to specify addition parameters such as commit=true
func (si *SolrInterface) Update(data map[string]interface{}, params *url.Values) (*SolrUpdateResponse, error) {
	if si.conn == nil {
		return nil, fmt.Errorf("No connection found for making request to solr")
	}
	return si.conn.Update(data, params)
}

// Commit the changes since the last commit
func (si *SolrInterface) Commit() (*SolrUpdateResponse, error) {
	params := &url.Values{}
	params.Add("commit", "true")
	return si.Update(M{}, params)
}

func (si *SolrInterface) Optimize(params *url.Values) (*SolrUpdateResponse, error) {
	if params == nil {
		params = &url.Values{}
	}
	params.Set("optimize", "true")
	return si.Update(M{}, params)
}

// Rollback rollbacks all add/deletes made to the index since the last commit.
// This should use with caution.
// See https://wiki.apache.org/solr/UpdateXmlMessages#A.22rollback.22
func (si *SolrInterface) Rollback() (*SolrUpdateResponse, error) {
	return si.Update(M{"rollback": M{}}, nil)
}

// Return new instance of CoreAdmin with provided solrUrl and basic auth
func (si *SolrInterface) CoreAdmin() (*CoreAdmin, error) {
	ca, err := NewCoreAdmin(si.conn.url.String())
	if err != nil {
		return nil, err
	}
	ca.SetBasicAuth(si.conn.username, si.conn.password)
	return ca, nil
}

// Return new instance of Schema with provided solrUrl and basic auth
func (si *SolrInterface) Schema() (*Schema, error) {
	s, err := NewSchema(si.conn.url.String(), si.conn.core)
	if err != nil {
		return nil, err
	}
	s.SetBasicAuth(si.conn.username, si.conn.password)
	return s, nil
}

// Return 'status' and QTime from solr, if everything is fine status should have value 'OK'
// QTime will have value -1 if can not determine
func (si *SolrInterface) Ping() (status string, qtime int, err error) {
	r, err := HTTPGet(fmt.Sprintf("%s/%s/admin/ping?wt=json", si.conn.url.String(), si.conn.core), nil, si.conn.username, si.conn.password)
	if err != nil {
		return "", -1, err
	}

	resp, err := bytes2json(&r)
	if err != nil {
		return "", -1, err
	}
	status, ok := resp["status"].(string)
	if ok == false {
		return "", -1, fmt.Errorf("Unexpected response returned")
	}
	if QTime, ok := resp["responseHeader"].(map[string]interface{})["QTime"].(float64); ok {
		qtime = int(QTime)
	} else {
		qtime = -1
	}
	return status, qtime, nil
}
<|endoftext|>


<commit_before>// Copyright 2011 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package ogletest

import (
	"bytes"
	"flag"
	"fmt"
	"path"
	"reflect"
	"regexp"
	"runtime"
	"sync"
	"testing"
	"time"
)

var testFilter = flag.String("ogletest.run", "", "Regexp for matching tests to run.")

// runTestsOnce protects RunTests from executing multiple times.
var runTestsOnce sync.Once

func isAssertThatError(x interface{}) bool {
	_, ok := x.(*assertThatError)
	return ok
}

// runTest runs a single test, returning a slice of failure records for that test.
func runTest(suite interface{}, method reflect.Method) (failures []*failureRecord) {
	suiteValue := reflect.ValueOf(suite)
	suiteType := suiteValue.Type()

	// Set up a clean slate for this test. Make sure to reset it after everything
	// below is finished, so we don't accidentally use it elsewhere.
	currentlyRunningTest = newTestInfo()
	defer func() {
		currentlyRunningTest = nil
	}()

	// Create a receiver.
	var suiteInstance reflect.Value = reflect.New(suiteType.Elem())
	var suiteInstanceAsInterface interface{} = suiteInstance.Interface()

	// Run the SetUp method, paying attention to whether it panics.
	setUpPanicked := false
	if i, ok := suiteInstanceAsInterface.(SetUpInterface); ok {
		setUpPanicked = runWithProtection(func() { i.SetUp(currentlyRunningTest) })
	}

	// Run the test method itself, but only if the SetUp method didn't panic.
	// (This includes AssertThat errors.)
	if !setUpPanicked {
		runWithProtection(
			func() {
				runMethodIfExists(suiteInstance, method.Name)
			},
		)
	}

	// Run the TearDown method, if any.
	if i, ok := suiteInstanceAsInterface.(TearDownInterface); ok {
		runWithProtection(func() { i.TearDown() })
	}

	// Tell the mock controller for the tests to report any errors it's sitting
	// on.
	currentlyRunningTest.MockController.Finish()

	return currentlyRunningTest.failureRecords
}

// RunTests runs the test suites registered with ogletest, communicating
// failures to the supplied testing.T object. This is the bridge between
// ogletest and the testing package (and gotest); you should ensure that it's
// called at least once by creating a gotest-compatible test function and
// calling it there.
//
// For example:
//
//     import (
//       "github.com/jacobsa/ogletest"
//       "testing"
//     )
//
//     func TestOgletest(t *testing.T) {
//       ogletest.RunTests(t)
//     }
//
func RunTests(t *testing.T) {
	runTestsOnce.Do(func() { runTestsInternal(t) })
}

// runTestsInternal does the real work of RunTests, which simply wraps it in a
// sync.Once.
func runTestsInternal(t *testing.T) {
	// Process each registered suite.
	for _, suite := range testSuites {
		val := reflect.ValueOf(suite)
		typ := val.Type()
		suiteName := typ.Elem().Name()

		// Grab methods for the suite, filtering them to just the ones that we
		// don't need to skip.
		testMethods := filterMethods(suiteName, getMethodsInSourceOrder(typ))

		// Is there anything left to do?
		if len(testMethods) == 0 {
			continue
		}

		fmt.Printf("[----------] Running tests from %s\n", suiteName)

		// Run the SetUpTestSuite method, if any.
		if i, ok := suite.(SetUpTestSuiteInterface); ok {
			i.SetUpTestSuite()
		}

		// Run each method.
		for _, method := range testMethods {
			// Print a banner for the start of this test.
			fmt.Printf("[ RUN      ] %s.%s\n", suiteName, method.Name)

			// Run the test.
			startTime := time.Now()
			failures := runTest(suite, method)
			runDuration := time.Since(startTime)

			// Print any failures, and mark the test as having failed if there are any.
			for _, record := range failures {
				t.Fail()
				userErrorSection := ""
				if record.UserError != "" {
					userErrorSection = record.UserError + "\n"
				}

				fmt.Printf(
					"%s:%d:\n%s\n%s\n",
					record.FileName,
					record.LineNumber,
					record.GeneratedError,
					userErrorSection)
			}

			// Print a banner for the end of the test.
			bannerMessage := "[       OK ]"
			if len(failures) != 0 {
				bannerMessage = "[  FAILED  ]"
			}

			// Print a summary of the time taken, if long enough.
			var timeMessage string
			if runDuration >= 25*time.Millisecond {
				timeMessage = fmt.Sprintf(" (%s)", runDuration.String())
			}

			fmt.Printf(
				"%s %s.%s%s\n",
				bannerMessage,
				suiteName,
				method.Name,
				timeMessage)
		}

		// Run the TearDownTestSuite method, if any.
		if i, ok := suite.(TearDownTestSuiteInterface); ok {
			i.TearDownTestSuite()
		}

		fmt.Printf("[----------] Finished with tests from %s\n", suiteName)
	}
}

// Return true iff the supplied program counter appears to lie within panic().
func isPanic(pc uintptr) bool {
	f := runtime.FuncForPC(pc)
	if f == nil {
		return false
	}

	return f.Name() == "runtime.gopanic" || f.Name() == "runtime.sigpanic"
}

// Find the deepest stack frame containing something that appears to be a
// panic. Return the 'skip' value that a caller to this function would need
// to supply to runtime.Caller for that frame, or a negative number if not found.
func findPanic() int {
	localSkip := -1
	for i := 0; ; i++ {
		// Stop if we've passed the base of the stack.
		pc, _, _, ok := runtime.Caller(i)
		if !ok {
			break
		}

		// Is this a panic?
		if isPanic(pc) {
			localSkip = i
		}
	}

	return localSkip - 1
}

// Attempt to find the file base name and line number for the ultimate source
// of a panic, on the panicking stack. Return a human-readable sentinel if
// unsuccessful.
func findPanicFileLine() (string, int) {
	panicSkip := findPanic()
	if panicSkip < 0 {
		return "(unknown)", 0
	}

	// Find the trigger of the panic.
	_, file, line, ok := runtime.Caller(panicSkip + 1)
	if !ok {
		return "(unknown)", 0
	}

	return path.Base(file), line
}

// Run the supplied function, catching panics (including AssertThat errors) and
// reporting them to the currently-running test as appropriate. Return true iff
// the function panicked.
func runWithProtection(f func()) (panicked bool) {
	defer func() {
		// If the test didn't panic, we're done.
		r := recover()
		if r == nil {
			return
		}

		panicked = true

		// We modify the currently running test below.
		currentlyRunningTest.mutex.Lock()
		defer currentlyRunningTest.mutex.Unlock()

		// If the function panicked (and the panic was not due to an AssertThat
		// failure), add a failure for the panic.
		if !isAssertThatError(r) {
			var panicRecord failureRecord
			panicRecord.FileName, panicRecord.LineNumber = findPanicFileLine()
			panicRecord.GeneratedError = fmt.Sprintf(
				"panic: %v\n\n%s", r, formatPanicStack())

			currentlyRunningTest.failureRecords = append(
				currentlyRunningTest.failureRecords,
				&panicRecord)
		}
	}()

	f()
	return
}

func runMethodIfExists(v reflect.Value, name string, args ...interface{}) {
	method := v.MethodByName(name)
	if method.Kind() == reflect.Invalid {
		return
	}

	if method.Type().NumIn() != len(args) {
		panic(fmt.Sprintf(
			"%s: expected %d args, actually %d.",
			name,
			len(args),
			method.Type().NumIn()))
	}

	// Create a slice of reflect.Values to pass to the method. Simultaneously
	// check types.
	argVals := make([]reflect.Value, len(args))
	for i, arg := range args {
		argVal := reflect.ValueOf(arg)

		if argVal.Type() != method.Type().In(i) {
			panic(fmt.Sprintf(
				"%s: expected arg %d to have type %v.",
				name,
				i,
				argVal.Type()))
		}

		argVals[i] = argVal
	}

	method.Call(argVals)
}

func formatPanicStack() string {
	buf := new(bytes.Buffer)

	// Find the panic. If successful, we'll skip to below it. Otherwise, we'll
	// format everything.
	var initialSkip int
	if panicSkip := findPanic(); panicSkip >= 0 {
		initialSkip = panicSkip + 1
	}

	for i := initialSkip; ; i++ {
		pc, file, line, ok := runtime.Caller(i)
		if !ok {
			break
		}

		// Choose a function name to display.
		funcName := "(unknown)"
		if f := runtime.FuncForPC(pc); f != nil {
			funcName = f.Name()
		}

		// Stop if we've gotten as far as the test runner code.
		if funcName == "github.com/jacobsa/ogletest.runMethodIfExists" ||
			funcName == "github.com/jacobsa/ogletest.runWithProtection" {
			break
		}

		// Add an entry for this frame.
		fmt.Fprintf(buf, "%s\n\t%s:%d\n", funcName, file, line)
	}

	return buf.String()
}

func filterMethods(suiteName string, in []reflect.Method) (out []reflect.Method) {
	for _, m := range in {
		// Skip set up, tear down, and unexported methods.
		if isSpecialMethod(m.Name) || !isExportedMethod(m.Name) {
			continue
		}

		// Has the user told us to skip this method?
		fullName := fmt.Sprintf("%s.%s", suiteName, m.Name)
		matched, err := regexp.MatchString(*testFilter, fullName)
		if err != nil {
			panic("Invalid value for --ogletest.run: " + err.Error())
		}

		if !matched {
			continue
		}

		out = append(out, m)
	}

	return
}

func isSpecialMethod(name string) bool {
	return (name == "SetUpTestSuite") ||
		(name == "TearDownTestSuite") ||
		(name == "SetUp") ||
		(name == "TearDown")
}

func isExportedMethod(name string) bool {
	return len(name) > 0 && name[0] >= 'A' && name[0] <= 'Z'
}
<commit_msg>Simplified test method running code.<commit_after>// Copyright 2011 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package ogletest

import (
	"bytes"
	"flag"
	"fmt"
	"path"
	"reflect"
	"regexp"
	"runtime"
	"sync"
	"testing"
	"time"
)

var testFilter = flag.String("ogletest.run", "", "Regexp for matching tests to run.")

// runTestsOnce protects RunTests from executing multiple times.
var runTestsOnce sync.Once

func isAssertThatError(x interface{}) bool {
	_, ok := x.(*assertThatError)
	return ok
}

// runTest runs a single test, returning a slice of failure records for that test.
func runTest(suite interface{}, method reflect.Method) (failures []*failureRecord) {
	suiteValue := reflect.ValueOf(suite)
	suiteType := suiteValue.Type()

	// Set up a clean slate for this test. Make sure to reset it after everything
	// below is finished, so we don't accidentally use it elsewhere.
	currentlyRunningTest = newTestInfo()
	defer func() {
		currentlyRunningTest = nil
	}()

	// Create a receiver.
	var suiteInstance reflect.Value = reflect.New(suiteType.Elem())
	var suiteInstanceAsInterface interface{} = suiteInstance.Interface()

	// Run the SetUp method, paying attention to whether it panics.
	setUpPanicked := false
	if i, ok := suiteInstanceAsInterface.(SetUpInterface); ok {
		setUpPanicked = runWithProtection(func() { i.SetUp(currentlyRunningTest) })
	}

	// Run the test method itself, but only if the SetUp method didn't panic.
	// (This includes AssertThat errors.)
	if !setUpPanicked {
		runWithProtection(func() { runTestMethod(suiteInstance, method) })
	}

	// Run the TearDown method, if any.
	if i, ok := suiteInstanceAsInterface.(TearDownInterface); ok {
		runWithProtection(func() { i.TearDown() })
	}

	// Tell the mock controller for the tests to report any errors it's sitting
	// on.
	currentlyRunningTest.MockController.Finish()

	return currentlyRunningTest.failureRecords
}

// RunTests runs the test suites registered with ogletest, communicating
// failures to the supplied testing.T object. This is the bridge between
// ogletest and the testing package (and gotest); you should ensure that it's
// called at least once by creating a gotest-compatible test function and
// calling it there.
//
// For example:
//
//     import (
//       "github.com/jacobsa/ogletest"
//       "testing"
//     )
//
//     func TestOgletest(t *testing.T) {
//       ogletest.RunTests(t)
//     }
//
func RunTests(t *testing.T) {
	runTestsOnce.Do(func() { runTestsInternal(t) })
}

// runTestsInternal does the real work of RunTests, which simply wraps it in a
// sync.Once.
func runTestsInternal(t *testing.T) {
	// Process each registered suite.
	for _, suite := range testSuites {
		val := reflect.ValueOf(suite)
		typ := val.Type()
		suiteName := typ.Elem().Name()

		// Grab methods for the suite, filtering them to just the ones that we
		// don't need to skip.
		testMethods := filterMethods(suiteName, getMethodsInSourceOrder(typ))

		// Is there anything left to do?
		if len(testMethods) == 0 {
			continue
		}

		fmt.Printf("[----------] Running tests from %s\n", suiteName)

		// Run the SetUpTestSuite method, if any.
		if i, ok := suite.(SetUpTestSuiteInterface); ok {
			i.SetUpTestSuite()
		}

		// Run each method.
		for _, method := range testMethods {
			// Print a banner for the start of this test.
			fmt.Printf("[ RUN      ] %s.%s\n", suiteName, method.Name)

			// Run the test.
			startTime := time.Now()
			failures := runTest(suite, method)
			runDuration := time.Since(startTime)

			// Print any failures, and mark the test as having failed if there are any.
			for _, record := range failures {
				t.Fail()
				userErrorSection := ""
				if record.UserError != "" {
					userErrorSection = record.UserError + "\n"
				}

				fmt.Printf(
					"%s:%d:\n%s\n%s\n",
					record.FileName,
					record.LineNumber,
					record.GeneratedError,
					userErrorSection)
			}

			// Print a banner for the end of the test.
			bannerMessage := "[       OK ]"
			if len(failures) != 0 {
				bannerMessage = "[  FAILED  ]"
			}

			// Print a summary of the time taken, if long enough.
			var timeMessage string
			if runDuration >= 25*time.Millisecond {
				timeMessage = fmt.Sprintf(" (%s)", runDuration.String())
			}

			fmt.Printf(
				"%s %s.%s%s\n",
				bannerMessage,
				suiteName,
				method.Name,
				timeMessage)
		}

		// Run the TearDownTestSuite method, if any.
		if i, ok := suite.(TearDownTestSuiteInterface); ok {
			i.TearDownTestSuite()
		}

		fmt.Printf("[----------] Finished with tests from %s\n", suiteName)
	}
}

// Return true iff the supplied program counter appears to lie within panic().
func isPanic(pc uintptr) bool {
	f := runtime.FuncForPC(pc)
	if f == nil {
		return false
	}

	return f.Name() == "runtime.gopanic" || f.Name() == "runtime.sigpanic"
}

// Find the deepest stack frame containing something that appears to be a
// panic. Return the 'skip' value that a caller to this function would need
// to supply to runtime.Caller for that frame, or a negative number if not found.
func findPanic() int {
	localSkip := -1
	for i := 0; ; i++ {
		// Stop if we've passed the base of the stack.
		pc, _, _, ok := runtime.Caller(i)
		if !ok {
			break
		}

		// Is this a panic?
		if isPanic(pc) {
			localSkip = i
		}
	}

	return localSkip - 1
}

// Attempt to find the file base name and line number for the ultimate source
// of a panic, on the panicking stack. Return a human-readable sentinel if
// unsuccessful.
func findPanicFileLine() (string, int) {
	panicSkip := findPanic()
	if panicSkip < 0 {
		return "(unknown)", 0
	}

	// Find the trigger of the panic.
	_, file, line, ok := runtime.Caller(panicSkip + 1)
	if !ok {
		return "(unknown)", 0
	}

	return path.Base(file), line
}

// Run the supplied function, catching panics (including AssertThat errors) and
// reporting them to the currently-running test as appropriate. Return true iff
// the function panicked.
func runWithProtection(f func()) (panicked bool) {
	defer func() {
		// If the test didn't panic, we're done.
		r := recover()
		if r == nil {
			return
		}

		panicked = true

		// We modify the currently running test below.
		currentlyRunningTest.mutex.Lock()
		defer currentlyRunningTest.mutex.Unlock()

		// If the function panicked (and the panic was not due to an AssertThat
		// failure), add a failure for the panic.
		if !isAssertThatError(r) {
			var panicRecord failureRecord
			panicRecord.FileName, panicRecord.LineNumber = findPanicFileLine()
			panicRecord.GeneratedError = fmt.Sprintf(
				"panic: %v\n\n%s", r, formatPanicStack())

			currentlyRunningTest.failureRecords = append(
				currentlyRunningTest.failureRecords,
				&panicRecord)
		}
	}()

	f()
	return
}

func runTestMethod(suite reflect.Value, method reflect.Method) {
	if method.Func.Type().NumIn() != 1 {
		panic(fmt.Sprintf(
			"%s: expected 1 args, actually %d.",
			method.Name,
			method.Func.Type().NumIn()))
	}

	method.Func.Call([]reflect.Value{suite})
}

func formatPanicStack() string {
	buf := new(bytes.Buffer)

	// Find the panic. If successful, we'll skip to below it. Otherwise, we'll
	// format everything.
	var initialSkip int
	if panicSkip := findPanic(); panicSkip >= 0 {
		initialSkip = panicSkip + 1
	}

	for i := initialSkip; ; i++ {
		pc, file, line, ok := runtime.Caller(i)
		if !ok {
			break
		}

		// Choose a function name to display.
		funcName := "(unknown)"
		if f := runtime.FuncForPC(pc); f != nil {
			funcName = f.Name()
		}

		// Stop if we've gotten as far as the test runner code.
		if funcName == "github.com/jacobsa/ogletest.runTestMethod" ||
			funcName == "github.com/jacobsa/ogletest.runWithProtection" {
			break
		}

		// Add an entry for this frame.
		fmt.Fprintf(buf, "%s\n\t%s:%d\n", funcName, file, line)
	}

	return buf.String()
}

func filterMethods(suiteName string, in []reflect.Method) (out []reflect.Method) {
	for _, m := range in {
		// Skip set up, tear down, and unexported methods.
		if isSpecialMethod(m.Name) || !isExportedMethod(m.Name) {
			continue
		}

		// Has the user told us to skip this method?
		fullName := fmt.Sprintf("%s.%s", suiteName, m.Name)
		matched, err := regexp.MatchString(*testFilter, fullName)
		if err != nil {
			panic("Invalid value for --ogletest.run: " + err.Error())
		}

		if !matched {
			continue
		}

		out = append(out, m)
	}

	return
}

func isSpecialMethod(name string) bool {
	return (name == "SetUpTestSuite") ||
		(name == "TearDownTestSuite") ||
		(name == "SetUp") ||
		(name == "TearDown")
}

func isExportedMethod(name string) bool {
	return len(name) > 0 && name[0] >= 'A' && name[0] <= 'Z'
}
<|endoftext|>


<commit_before>package sdl

// #cgo pkg-config: sdl2
// #cgo LDFLAGS: -lSDL2_image
//
// #include "SDL.h"
import "C"

import (
	"fmt"
	"unsafe"
)

//
// The only way to keep this file sane is with vim folds. `:help fold` for more info
//

// START EventType {{{1

// TODO(adam): Suffix with Event instead of Ev?

// EventType represents the type of an application event.
type EventType uint32

// IsUserEvent reports whether t is a custom application event.
func (t EventType) IsUserEvent() bool {
	return t >= UserEvent && t <= LastEvent
}

// Special event numbers
const (
	FirstEvent EventType = C.SDL_FIRSTEVENT

	// Events UserEvent through LastEvent are for your use, and should be allocated
	// with RegisterEvents.
	UserEvent EventType = C.SDL_USEREVENT
	LastEvent EventType = C.SDL_LASTEVENT
)

// Application events
const (
	QuitEv EventType = C.SDL_QUIT

	// These application events have special meaning on iOS, see README-ios.txt for details
	AppTerminatingEv         EventType = C.SDL_APP_TERMINATING
	AppLowMemoryEv           EventType = C.SDL_APP_LOWMEMORY
	AppWillEnterBackgroundEv EventType = C.SDL_APP_WILLENTERBACKGROUND
	AppDidEnterBackgroundEv  EventType = C.SDL_APP_DIDENTERBACKGROUND
	AppWillEnterForegroundEv EventType = C.SDL_APP_WILLENTERFOREGROUND
	AppDidEnterForegroundEv  EventType = C.SDL_APP_DIDENTERFOREGROUND
)

// Window events
const (
	WindowEv EventType = C.SDL_WINDOWEVENT
	SysWmEv  EventType = C.SDL_SYSWMEVENT
)

// Keyboard events
const (
	KeyDownEv     EventType = C.SDL_KEYDOWN
	KeyUpEv       EventType = C.SDL_KEYUP
	TextEditingEv EventType = C.SDL_TEXTEDITING
	TextInputEv   EventType = C.SDL_TEXTINPUT
)

// Mouse events
const (
	MouseMotionEv     EventType = C.SDL_MOUSEMOTION
	MouseButtonDownEv EventType = C.SDL_MOUSEBUTTONDOWN
	MouseButtonUpEv   EventType = C.SDL_MOUSEBUTTONUP
	MouseWheelEv      EventType = C.SDL_MOUSEWHEEL
)

// Joystick events
const (
	JoyAxisMotionEv    EventType = C.SDL_JOYAXISMOTION
	JoyBallMotionEv    EventType = C.SDL_JOYBALLMOTION
	JoyHatMotionEv     EventType = C.SDL_JOYHATMOTION
	JoyButtonDownEv    EventType = C.SDL_JOYBUTTONDOWN
	JoyButtonUpEv      EventType = C.SDL_JOYBUTTONUP
	JoyDeviceAddedEv   EventType = C.SDL_JOYDEVICEADDED
	JoyDeviceRemovedEv EventType = C.SDL_JOYDEVICEREMOVED
)

// Game controller events
const (
	ControllerAxisMotionEv     EventType = C.SDL_CONTROLLERAXISMOTION
	ControllerButtonDownEv     EventType = C.SDL_CONTROLLERBUTTONDOWN
	ControllerButtonUpEv       EventType = C.SDL_CONTROLLERBUTTONUP
	ControllerDeviceAddedEv    EventType = C.SDL_CONTROLLERDEVICEADDED
	ControllerDeviceRemovedEv  EventType = C.SDL_CONTROLLERDEVICEREMOVED
	ControllerDeviceRemappedEv EventType = C.SDL_CONTROLLERDEVICEREMAPPED
)

// Touch events
const (
	FingerDownEv   EventType = C.SDL_FINGERDOWN
	FingerUpEv     EventType = C.SDL_FINGERUP
	FingerMotionEv EventType = C.SDL_FINGERMOTION
)

// Gesture events
const (
	DollarGestureEv EventType = C.SDL_DOLLARGESTURE
	DollarRecordEv  EventType = C.SDL_DOLLARRECORD
	MultiGestureEv  EventType = C.SDL_MULTIGESTURE
)

// Clipboard events
const (
	ClipboardUpdateEv EventType = C.SDL_CLIPBOARDUPDATE
)

// Drag and drop events
const (
	DropFileEv EventType = C.SDL_DROPFILE
)

// END EventType }}}1

// Event is implemented by all SDL events.
type Event interface {
	// Type returns the event's type.
	Type() EventType

	// Timestamp returns the number of milliseconds since the SDL library initialization.
	Timestamp() uint32
}

// PollEvent returns the next available event, or nil if there is no event pending.
func PollEvent() Event {
	var cEvent C.SDL_Event
	if C.SDL_PollEvent(&cEvent) == 0 {
		return nil
	}
	return convertEvent(unsafe.Pointer(&cEvent))
}

// HasEvent returns whether there is a pending event available.
func HasEvent() bool {
	return C.SDL_PollEvent(nil) != 0
}

func convertEvent(cEvent unsafe.Pointer) Event {
	common := (*C.SDL_CommonEvent)(cEvent)
	switch EventType(common._type) {
	case QuitEv:
		// Quit events don't hold any data beyond the common events.
		return commonEvent{common}
	case KeyDownEv, KeyUpEv:
		return KeyboardEvent{(*C.SDL_KeyboardEvent)(cEvent)}
	default:
		fmt.Println("Unhandled event with int:", int(common._type))
		return commonEvent{common}
	}
}

// {{{1 Event Structs

// {{{2 CommonEvent

// commonEvent holds fields common to all events.  It is not exported because it
// doesn't provide anything useful outside of the Event interface.
type commonEvent struct {
	ev *C.SDL_CommonEvent
}

func (e commonEvent) Type() EventType {
	return EventType(e.ev._type)
}

func (e commonEvent) Timestamp() uint32 {
	return uint32(e.ev.timestamp)
}

// }}}2 CommonEvent

// {{{2 WindowEvent
// TODO make this implement Event
type WindowEvent struct {
	ev C.SDL_WindowEvent
}

// }}}2 WindowEvent

// {{{2 KeyboardEvent
type KeyboardEvent struct {
	e *C.SDL_KeyboardEvent
}

func (e KeyboardEvent) Timestamp() uint32 {
	return uint32(e.e.timestamp)
}

func (e KeyboardEvent) Type() EventType {
	return EventType(e.e._type)
}

func (e KeyboardEvent) WindowID() uint32 {
	return uint32(e.e.windowID)
}

func (e KeyboardEvent) State() uint8 {
	return uint8(e.e.state)
}

func (e KeyboardEvent) Repeat() uint8 {
	return uint8(e.e.repeat)
}

// TODO this
/*
func (e KeyboardEvent) Keysym() Keysym {
}
*/
// }}}2 KeyboardEvent

// {{{2 TextEditingEvent
// TODO make this implement Event
type TextEditingEvent struct {
	ev C.SDL_TextEditingEvent
}

// }}}2 TextEditingEvent

// {{{2 TextInputEvent
// TODO make this implement Event
type TextInputEvent struct {
	ev C.SDL_TextInputEvent
}

// }}}2 TextInputEvent

// {{{2 MouseMotionEvent
// TODO make this implement Event
type MouseMotionEvent struct {
	ev C.SDL_MouseMotionEvent
}

// }}}2 MouseMotionEvent

// {{{2 MouseButtonEvent
// TODO make this implement Event
type MouseButtonEvent struct {
	ev C.SDL_MouseButtonEvent
}

// }}}2 MouseButtonEvent

// {{{2 MouseWheelEvent
// TODO make this implement Event
type MouseWheelEvent struct {
	ev C.SDL_MouseWheelEvent
}

// }}}2 MouseWheelEvent

// {{{2 JoyAxisEvent
// TODO make this implement Event
type JoyAxisEvent struct {
	ev C.SDL_JoyAxisEvent
}

// }}}2 JoyAxisEvent

// {{{2 JoyBallEvent
// TODO make this implement Event
type JoyBallEvent struct {
	ev C.SDL_JoyBallEvent
}

// }}}2 JoyBallEvent

// {{{2 JoyHatEvent
// TODO make this implement Event
type JoyHatEvent struct {
	ev C.SDL_JoyHatEvent
}

// }}}2 JoyHatEvent

// {{{2 JoyButtonEvent
// TODO make this implement Event
type JoyButtonEvent struct {
	ev C.SDL_JoyButtonEvent
}

// }}}2 JoyButtonEvent

// {{{2 JoyDeviceEvent
// TODO make this implement Event
type JoyDeviceEvent struct {
	ev C.SDL_JoyDeviceEvent
}

// }}}2 JoyDeviceEvent

// {{{2 ControllerAxisEvent
// TODO make this implement Event
type ControllerAxisEvent struct {
	ev C.SDL_ControllerAxisEvent
}

// }}}2 ControllerAxisEvent

// {{{2 ControllerButtonEvent
// TODO make this implement Event
type ControllerButtonEvent struct {
	ev C.SDL_ControllerButtonEvent
}

// }}}2 ControllerButtonEvent

// {{{2 ControllerDeviceEvent
// TODO make this implement Event
type ControllerDeviceEvent struct {
	ev C.SDL_ControllerDeviceEvent
}

// }}}2 ControllerDeviceEvent

// {{{2 UserEvent
// TODO make this implement Event
type UserEvent struct {
	ev C.SDL_UserEvent
}

// }}}2 UserEvent

// {{{2 SysWMEvent
// TODO make this implement Event
type SysWMEvent struct {
	ev C.SDL_SysWMEvent
}

// }}}2 SysWMEvent

// {{{2 TouchFingerEvent
// TODO make this implement Event
type TouchFingerEvent struct {
	ev C.SDL_TouchFingerEvent
}

// }}}2 TouchFingerEvent

// {{{2 MultiGestureEvent
// TODO make this implement Event
type MultiGestureEvent struct {
	ev C.SDL_MultiGestureEvent
}

// }}}2 MultiGestureEvent

// {{{2 DollarGestureEvent
// TODO make this implement Event
type DollarGestureEvent struct {
	ev C.SDL_DollarGestureEvent
}

// }}}2 DollarGestureEvent

// {{{2 DropEvent
// TODO make this implement Event
type DropEvent struct {
	ev C.SDL_DropEvent
}

// }}}2 DropEvent

// }}}1 Event Structs
<commit_msg>Rename all event types with EventType suffix<commit_after>package sdl

// #cgo pkg-config: sdl2
// #cgo LDFLAGS: -lSDL2_image
//
// #include "SDL.h"
import "C"

import (
	"fmt"
	"unsafe"
)

//
// The only way to keep this file sane is with vim folds. `:help fold` for more info
//

// START EventType {{{1

// EventType represents the type of an application event.
type EventType uint32

// IsUserEvent reports whether t is a custom application event.
func (t EventType) IsUserEvent() bool {
	return t >= UserEventType && t <= LastEventType
}

// Special event numbers
const (
	FirstEventType EventType = C.SDL_FIRSTEVENT

	// Events UserEvent through LastEvent are for your use, and should be allocated
	// with RegisterEvents.
	UserEventType EventType = C.SDL_USEREVENT
	LastEventType EventType = C.SDL_LASTEVENT
)

// Application events
const (
	QuitEventType EventType = C.SDL_QUIT

	// These application events have special meaning on iOS, see README-ios.txt for details
	AppTerminatingEventType         EventType = C.SDL_APP_TERMINATING
	AppLowMemoryEventType           EventType = C.SDL_APP_LOWMEMORY
	AppWillEnterBackgroundEventType EventType = C.SDL_APP_WILLENTERBACKGROUND
	AppDidEnterBackgroundEventType  EventType = C.SDL_APP_DIDENTERBACKGROUND
	AppWillEnterForegroundEventType EventType = C.SDL_APP_WILLENTERFOREGROUND
	AppDidEnterForegroundEventType  EventType = C.SDL_APP_DIDENTERFOREGROUND
)

// Window events
const (
	WindowEventType EventType = C.SDL_WINDOWEVENT
	SysWMEventType  EventType = C.SDL_SYSWMEVENT
)

// Keyboard events
const (
	KeyDownEventType     EventType = C.SDL_KEYDOWN
	KeyUpEventType       EventType = C.SDL_KEYUP
	TextEditingEventType EventType = C.SDL_TEXTEDITING
	TextInputEventType   EventType = C.SDL_TEXTINPUT
)

// Mouse events
const (
	MouseMotionEventType     EventType = C.SDL_MOUSEMOTION
	MouseButtonDownEventType EventType = C.SDL_MOUSEBUTTONDOWN
	MouseButtonUpEventType   EventType = C.SDL_MOUSEBUTTONUP
	MouseWheelEventType      EventType = C.SDL_MOUSEWHEEL
)

// Joystick events
const (
	JoyAxisMotionEventType    EventType = C.SDL_JOYAXISMOTION
	JoyBallMotionEventType    EventType = C.SDL_JOYBALLMOTION
	JoyHatMotionEventType     EventType = C.SDL_JOYHATMOTION
	JoyButtonDownEventType    EventType = C.SDL_JOYBUTTONDOWN
	JoyButtonUpEventType      EventType = C.SDL_JOYBUTTONUP
	JoyDeviceAddedEventType   EventType = C.SDL_JOYDEVICEADDED
	JoyDeviceRemovedEventType EventType = C.SDL_JOYDEVICEREMOVED
)

// Game controller events
const (
	ControllerAxisMotionEventType     EventType = C.SDL_CONTROLLERAXISMOTION
	ControllerButtonDownEventType     EventType = C.SDL_CONTROLLERBUTTONDOWN
	ControllerButtonUpEventType       EventType = C.SDL_CONTROLLERBUTTONUP
	ControllerDeviceAddedEventType    EventType = C.SDL_CONTROLLERDEVICEADDED
	ControllerDeviceRemovedEventType  EventType = C.SDL_CONTROLLERDEVICEREMOVED
	ControllerDeviceRemappedEventType EventType = C.SDL_CONTROLLERDEVICEREMAPPED
)

// Touch events
const (
	FingerDownEventType   EventType = C.SDL_FINGERDOWN
	FingerUpEventType     EventType = C.SDL_FINGERUP
	FingerMotionEventType EventType = C.SDL_FINGERMOTION
)

// Gesture events
const (
	DollarGestureEventType EventType = C.SDL_DOLLARGESTURE
	DollarRecordEventType  EventType = C.SDL_DOLLARRECORD
	MultiGestureEventType  EventType = C.SDL_MULTIGESTURE
)

// Clipboard events
const (
	ClipboardUpdateEventType EventType = C.SDL_CLIPBOARDUPDATE
)

// Drag and drop events
const (
	DropFileEventType EventType = C.SDL_DROPFILE
)

// END EventType }}}1

// Event is implemented by all SDL events.
type Event interface {
	// Type returns the event's type.
	Type() EventType

	// Timestamp returns the number of milliseconds since the SDL library initialization.
	Timestamp() uint32
}

// PollEvent returns the next available event, or nil if there is no event pending.
func PollEvent() Event {
	var cEvent C.SDL_Event
	if C.SDL_PollEvent(&cEvent) == 0 {
		return nil
	}
	return convertEvent(unsafe.Pointer(&cEvent))
}

// HasEvent returns whether there is a pending event available.
func HasEvent() bool {
	return C.SDL_PollEvent(nil) != 0
}

func convertEvent(cEvent unsafe.Pointer) Event {
	common := (*C.SDL_CommonEvent)(cEvent)
	switch EventType(common._type) {
	case QuitEventType:
		// Quit events don't hold any data beyond the common events.
		return commonEvent{common}
	case KeyDownEventType, KeyUpEventType:
		return KeyboardEvent{(*C.SDL_KeyboardEvent)(cEvent)}
	default:
		fmt.Println("Unhandled event with int:", int(common._type))
		return commonEvent{common}
	}
}

// {{{1 Event Structs

// {{{2 CommonEvent

// commonEvent holds fields common to all events.  It is not exported because it
// doesn't provide anything useful outside of the Event interface.
type commonEvent struct {
	ev *C.SDL_CommonEvent
}

func (e commonEvent) Type() EventType {
	return EventType(e.ev._type)
}

func (e commonEvent) Timestamp() uint32 {
	return uint32(e.ev.timestamp)
}

// }}}2 CommonEvent

// {{{2 WindowEvent
// TODO make this implement Event
type WindowEvent struct {
	ev C.SDL_WindowEvent
}

// }}}2 WindowEvent

// {{{2 KeyboardEvent
type KeyboardEvent struct {
	e *C.SDL_KeyboardEvent
}

func (e KeyboardEvent) Timestamp() uint32 {
	return uint32(e.e.timestamp)
}

func (e KeyboardEvent) Type() EventType {
	return EventType(e.e._type)
}

func (e KeyboardEvent) WindowID() uint32 {
	return uint32(e.e.windowID)
}

func (e KeyboardEvent) State() uint8 {
	return uint8(e.e.state)
}

func (e KeyboardEvent) Repeat() uint8 {
	return uint8(e.e.repeat)
}

// TODO this
/*
func (e KeyboardEvent) Keysym() Keysym {
}
*/
// }}}2 KeyboardEvent

// {{{2 TextEditingEvent
// TODO make this implement Event
type TextEditingEvent struct {
	ev C.SDL_TextEditingEvent
}

// }}}2 TextEditingEvent

// {{{2 TextInputEvent
// TODO make this implement Event
type TextInputEvent struct {
	ev C.SDL_TextInputEvent
}

// }}}2 TextInputEvent

// {{{2 MouseMotionEvent
// TODO make this implement Event
type MouseMotionEvent struct {
	ev C.SDL_MouseMotionEvent
}

// }}}2 MouseMotionEvent

// {{{2 MouseButtonEvent
// TODO make this implement Event
type MouseButtonEvent struct {
	ev C.SDL_MouseButtonEvent
}

// }}}2 MouseButtonEvent

// {{{2 MouseWheelEvent
// TODO make this implement Event
type MouseWheelEvent struct {
	ev C.SDL_MouseWheelEvent
}

// }}}2 MouseWheelEvent

// {{{2 JoyAxisEvent
// TODO make this implement Event
type JoyAxisEvent struct {
	ev C.SDL_JoyAxisEvent
}

// }}}2 JoyAxisEvent

// {{{2 JoyBallEvent
// TODO make this implement Event
type JoyBallEvent struct {
	ev C.SDL_JoyBallEvent
}

// }}}2 JoyBallEvent

// {{{2 JoyHatEvent
// TODO make this implement Event
type JoyHatEvent struct {
	ev C.SDL_JoyHatEvent
}

// }}}2 JoyHatEvent

// {{{2 JoyButtonEvent
// TODO make this implement Event
type JoyButtonEvent struct {
	ev C.SDL_JoyButtonEvent
}

// }}}2 JoyButtonEvent

// {{{2 JoyDeviceEvent
// TODO make this implement Event
type JoyDeviceEvent struct {
	ev C.SDL_JoyDeviceEvent
}

// }}}2 JoyDeviceEvent

// {{{2 ControllerAxisEvent
// TODO make this implement Event
type ControllerAxisEvent struct {
	ev C.SDL_ControllerAxisEvent
}

// }}}2 ControllerAxisEvent

// {{{2 ControllerButtonEvent
// TODO make this implement Event
type ControllerButtonEvent struct {
	ev C.SDL_ControllerButtonEvent
}

// }}}2 ControllerButtonEvent

// {{{2 ControllerDeviceEvent
// TODO make this implement Event
type ControllerDeviceEvent struct {
	ev C.SDL_ControllerDeviceEvent
}

// }}}2 ControllerDeviceEvent

// {{{2 UserEvent
// TODO make this implement Event
type UserEvent struct {
	ev C.SDL_UserEvent
}

// }}}2 UserEvent

// {{{2 SysWMEvent
// TODO make this implement Event
type SysWMEvent struct {
	ev C.SDL_SysWMEvent
}

// }}}2 SysWMEvent

// {{{2 TouchFingerEvent
// TODO make this implement Event
type TouchFingerEvent struct {
	ev C.SDL_TouchFingerEvent
}

// }}}2 TouchFingerEvent

// {{{2 MultiGestureEvent
// TODO make this implement Event
type MultiGestureEvent struct {
	ev C.SDL_MultiGestureEvent
}

// }}}2 MultiGestureEvent

// {{{2 DollarGestureEvent
// TODO make this implement Event
type DollarGestureEvent struct {
	ev C.SDL_DollarGestureEvent
}

// }}}2 DollarGestureEvent

// {{{2 DropEvent
// TODO make this implement Event
type DropEvent struct {
	ev C.SDL_DropEvent
}

// }}}2 DropEvent

// }}}1 Event Structs
<|endoftext|>