<commit_before>/*
 * Minio Client (C) 2014, 2015 Minio, Inc.
 *
 * 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 main

import (
	"io"
	"io/ioutil"
	"runtime"
	"strings"
	"sync/atomic"
	"time"

	"github.com/minio/mc/pkg/console"
	"github.com/minio/pb"
)

type pbBarCmd int

const (
	pbBarCmdExtend pbBarCmd = iota
	pbBarCmdProgress
	pbBarCmdFinish
	pbBarCmdPutError
	pbBarCmdGetError
	pbBarCmdSetCaption
)

type fakeReader struct {
	size int64
}

func (r *fakeReader) Read(p []byte) (n int, err error) {
	return int(r.size), io.EOF
}

func putFakeTarget(reader io.Reader) {
	io.Copy(ioutil.Discard, reader)
}

type proxyReader struct {
	io.Reader
	bar *barSend
}

func (r *proxyReader) Read(p []byte) (n int, err error) {
	n, err = r.Reader.Read(p)
	r.bar.progress(int64(n))
	return
}

func (b *barSend) NewProxyReader(r io.Reader) *proxyReader {
	return &proxyReader{r, b}
}

type barMsg struct {
	Cmd pbBarCmd
	Arg interface{}
}

type barSend struct {
	cmdCh    chan<- barMsg
	finishCh <-chan bool
}

func (b barSend) Extend(total int64) {
	b.cmdCh <- barMsg{Cmd: pbBarCmdExtend, Arg: total}
}

func (b barSend) progress(progress int64) {
	b.cmdCh <- barMsg{Cmd: pbBarCmdProgress, Arg: progress}
}

func (b barSend) ErrorPut(size int64) {
	b.cmdCh <- barMsg{Cmd: pbBarCmdPutError, Arg: size}
}

func (b barSend) ErrorGet(size int64) {
	b.cmdCh <- barMsg{Cmd: pbBarCmdGetError, Arg: size}
}

func (b *barSend) SetCaption(c string) {
	b.cmdCh <- barMsg{Cmd: pbBarCmdSetCaption, Arg: c}
}

func (b barSend) Finish() {
	defer close(b.cmdCh)
	b.cmdCh <- barMsg{Cmd: pbBarCmdFinish}
	<-b.finishCh
	console.Println()
}

func cursorAnimate() <-chan rune {
	cursorCh := make(chan rune)
	var cursors string
	if runtime.GOOS == "windows" {
		cursors = "|/-\\"
	} else {
		cursors = "➩➪➫➬➭➮➯➱"
	}
	go func() {
		for {
			for _, cursor := range cursors {
				cursorCh <- cursor
			}
		}
	}()
	return cursorCh
}

func fixateBarCaption(c string, s string, width int) string {
	switch {
	case len(c) > width:
		// Trim caption to fit within the screen
		trimSize := len(c) - width + 3
		if trimSize < len(c) {
			c = "..." + c[trimSize:]
		}
	case len(c) < width:
		c = c + strings.Repeat(" ", width-len(c))
	}
	return s + " " + c
}

func getFixedWidth(width, percent int) int {
	return width * percent / 100
}

// newCpBar - instantiate a pbBar.
func newCpBar() barSend {
	cmdCh := make(chan barMsg)
	finishCh := make(chan bool)
	go func(cmdCh <-chan barMsg, finishCh chan<- bool) {
		var started bool
		var totalBytesRead int64 // total amounts of bytes read
		bar := pb.New64(0)
		bar.SetUnits(pb.U_BYTES)
		bar.SetRefreshRate(time.Millisecond * 125)
		bar.NotPrint = true
		bar.ShowSpeed = true
		bar.Callback = func(s string) {
			console.Bar("\r" + s)
		}
		cursorCh := cursorAnimate()
		// Feels like wget
		bar.Format("[=> ]")
		for msg := range cmdCh {
			switch msg.Cmd {
			case pbBarCmdSetCaption:
				bar.Prefix(fixateBarCaption(msg.Arg.(string), string(<-cursorCh), getFixedWidth(bar.GetWidth(), 18)))
			case pbBarCmdExtend:
				atomic.AddInt64(&bar.Total, msg.Arg.(int64))
			case pbBarCmdProgress:
				if bar.Total > 0 && !started {
					started = true
					bar.Start()
				}
				if msg.Arg.(int64) > 0 {
					totalBytesRead += msg.Arg.(int64)
					bar.Add64(msg.Arg.(int64))
				}
			case pbBarCmdPutError:
				if totalBytesRead > msg.Arg.(int64) {
					bar.Set64(totalBytesRead - msg.Arg.(int64))
				}
			case pbBarCmdGetError:
				if msg.Arg.(int64) > 0 {
					bar.Add64(msg.Arg.(int64))
				}
			case pbBarCmdFinish:
				if started {
					bar.Finish()
				}
				finishCh <- true
				return
			}
		}
	}(cmdCh, finishCh)
	return barSend{cmdCh, finishCh}
}
<commit_msg>Add unicode block character for progress bar on linux and darwin<commit_after>/*
 * Minio Client (C) 2014, 2015 Minio, Inc.
 *
 * 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 main

import (
	"io"
	"io/ioutil"
	"runtime"
	"strings"
	"sync/atomic"
	"time"

	"github.com/minio/mc/pkg/console"
	"github.com/minio/pb"
)

type pbBarCmd int

const (
	pbBarCmdExtend pbBarCmd = iota
	pbBarCmdProgress
	pbBarCmdFinish
	pbBarCmdPutError
	pbBarCmdGetError
	pbBarCmdSetCaption
)

type fakeReader struct {
	size int64
}

func (r *fakeReader) Read(p []byte) (n int, err error) {
	return int(r.size), io.EOF
}

func putFakeTarget(reader io.Reader) {
	io.Copy(ioutil.Discard, reader)
}

type proxyReader struct {
	io.Reader
	bar *barSend
}

func (r *proxyReader) Read(p []byte) (n int, err error) {
	n, err = r.Reader.Read(p)
	r.bar.progress(int64(n))
	return
}

func (b *barSend) NewProxyReader(r io.Reader) *proxyReader {
	return &proxyReader{r, b}
}

type barMsg struct {
	Cmd pbBarCmd
	Arg interface{}
}

type barSend struct {
	cmdCh    chan<- barMsg
	finishCh <-chan bool
}

func (b barSend) Extend(total int64) {
	b.cmdCh <- barMsg{Cmd: pbBarCmdExtend, Arg: total}
}

func (b barSend) progress(progress int64) {
	b.cmdCh <- barMsg{Cmd: pbBarCmdProgress, Arg: progress}
}

func (b barSend) ErrorPut(size int64) {
	b.cmdCh <- barMsg{Cmd: pbBarCmdPutError, Arg: size}
}

func (b barSend) ErrorGet(size int64) {
	b.cmdCh <- barMsg{Cmd: pbBarCmdGetError, Arg: size}
}

func (b *barSend) SetCaption(c string) {
	b.cmdCh <- barMsg{Cmd: pbBarCmdSetCaption, Arg: c}
}

func (b barSend) Finish() {
	defer close(b.cmdCh)
	b.cmdCh <- barMsg{Cmd: pbBarCmdFinish}
	<-b.finishCh
	console.Println()
}

func cursorAnimate() <-chan rune {
	cursorCh := make(chan rune)
	var cursors string
	if runtime.GOOS == "windows" {
		cursors = "|/-\\"
	} else {
		cursors = "➩➪➫➬➭➮➯➱"
	}
	go func() {
		for {
			for _, cursor := range cursors {
				cursorCh <- cursor
			}
		}
	}()
	return cursorCh
}

func fixateBarCaption(c string, s string, width int) string {
	switch {
	case len(c) > width:
		// Trim caption to fit within the screen
		trimSize := len(c) - width + 3
		if trimSize < len(c) {
			c = "..." + c[trimSize:]
		}
	case len(c) < width:
		c = c + strings.Repeat(" ", width-len(c))
	}
	return s + " " + c
}

func getFixedWidth(width, percent int) int {
	return width * percent / 100
}

// newCpBar - instantiate a pbBar.
func newCpBar() barSend {
	cmdCh := make(chan barMsg)
	finishCh := make(chan bool)
	go func(cmdCh <-chan barMsg, finishCh chan<- bool) {
		var started bool
		var totalBytesRead int64 // total amounts of bytes read
		bar := pb.New64(0)
		bar.SetUnits(pb.U_BYTES)
		bar.SetRefreshRate(time.Millisecond * 125)
		bar.NotPrint = true
		bar.ShowSpeed = true
		bar.Callback = func(s string) {
			console.Bar("\r" + s)
		}
		cursorCh := cursorAnimate()
		if runtime.GOOS == "windows" {
			bar.Format("[=> ]")
		} else {
			bar.Format("[▆ ]")
		}
		for msg := range cmdCh {
			switch msg.Cmd {
			case pbBarCmdSetCaption:
				bar.Prefix(fixateBarCaption(msg.Arg.(string), string(<-cursorCh), getFixedWidth(bar.GetWidth(), 18)))
			case pbBarCmdExtend:
				atomic.AddInt64(&bar.Total, msg.Arg.(int64))
			case pbBarCmdProgress:
				if bar.Total > 0 && !started {
					started = true
					bar.Start()
				}
				if msg.Arg.(int64) > 0 {
					totalBytesRead += msg.Arg.(int64)
					bar.Add64(msg.Arg.(int64))
				}
			case pbBarCmdPutError:
				if totalBytesRead > msg.Arg.(int64) {
					bar.Set64(totalBytesRead - msg.Arg.(int64))
				}
			case pbBarCmdGetError:
				if msg.Arg.(int64) > 0 {
					bar.Add64(msg.Arg.(int64))
				}
			case pbBarCmdFinish:
				if started {
					bar.Finish()
				}
				finishCh <- true
				return
			}
		}
	}(cmdCh, finishCh)
	return barSend{cmdCh, finishCh}
}
<|endoftext|>


<commit_before>// Copyright 2009 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.

// This file implements the Mapping data structure.

package main

import (
	"fmt"
	"io"
	"path"
	"path/filepath"
	"sort"
	"strings"
)

// A Mapping object maps relative paths (e.g. from URLs)
// to absolute paths (of the file system) and vice versa.
//
// A Mapping object consists of a list of individual mappings
// of the form: prefix -> path which are interpreted as follows:
// A relative path of the form prefix/tail is to be mapped to
// the absolute path/tail, if that absolute path exists in the file
// system. Given a Mapping object, a relative path is mapped to an
// absolute path by trying each of the individual mappings in order,
// until a valid mapping is found. For instance, for the mapping:
//
//	user   -> /home/user
//	public -> /home/user/public
//	public -> /home/build/public
//
// the relative paths below are mapped to absolute paths as follows:
//
//	user/foo                -> /home/user/foo
//	public/net/rpc/file1.go -> /home/user/public/net/rpc/file1.go
//
// If there is no /home/user/public/net/rpc/file2.go, the next public
// mapping entry is used to map the relative path to:
//
//	public/net/rpc/file2.go -> /home/build/public/net/rpc/file2.go
//
// (assuming that file exists).
//
// Each individual mapping also has a RWValue associated with it that
// may be used to store mapping-specific information. See the Iterate
// method.
//
type Mapping struct {
	list     []mapping
	prefixes []string // lazily computed from list
}

type mapping struct {
	prefix, path string
	value        *RWValue
}

// Init initializes the Mapping from a list of paths.
// Empty paths are ignored; relative paths are assumed to be relative to
// the current working directory and converted to absolute paths.
// For each path of the form:
//
//	dirname/localname
//
// a mapping
//
//	localname -> path
//
// is added to the Mapping object, in the order of occurrence.
// For instance, under Unix, the argument:
//
//	/home/user:/home/build/public
//
// leads to the following mapping:
//
//	user   -> /home/user
//	public -> /home/build/public
//
func (m *Mapping) Init(paths []string) {
	pathlist := canonicalizePaths(paths, nil)
	list := make([]mapping, len(pathlist))

	// create mapping list
	for i, path := range pathlist {
		_, prefix := filepath.Split(path)
		list[i] = mapping{prefix, path, new(RWValue)}
	}

	m.list = list
}

// IsEmpty returns true if there are no mappings specified.
func (m *Mapping) IsEmpty() bool { return len(m.list) == 0 }

// PrefixList returns a list of all prefixes, with duplicates removed.
// For instance, for the mapping:
//
//	user   -> /home/user
//	public -> /home/user/public
//	public -> /home/build/public
//
// the prefix list is:
//
//	user, public
//
func (m *Mapping) PrefixList() []string {
	// compute the list lazily
	if m.prefixes == nil {
		list := make([]string, len(m.list))

		// populate list
		for i, e := range m.list {
			list[i] = e.prefix
		}

		// sort the list and remove duplicate entries
		sort.Strings(list)
		i := 0
		prev := ""
		for _, path := range list {
			if path != prev {
				list[i] = path
				i++
				prev = path
			}
		}

		m.prefixes = list[0:i]
	}

	return m.prefixes
}

// Fprint prints the mapping.
func (m *Mapping) Fprint(w io.Writer) {
	for _, e := range m.list {
		fmt.Fprintf(w, "\t%s -> %s\n", e.prefix, e.path)
	}
}

// splitFirst splits a path at the first path separator and returns
// the path's head (the top-most directory specified by the path) and
// its tail (the rest of the path). If there is no path separator,
// splitFirst returns path as head, and the the empty string as tail.
// Specifically, splitFirst("foo") == splitFirst("foo/").
//
func splitFirst(path string) (head, tail string) {
	if i := strings.Index(path, string(filepath.Separator)); i > 0 {
		// 0 < i < len(path)
		return path[0:i], path[i+1:]
	}
	return path, ""
}

// ToAbsolute maps a slash-separated relative path to an absolute filesystem
// path using the Mapping specified by the receiver. If the path cannot
// be mapped, the empty string is returned.
//
func (m *Mapping) ToAbsolute(spath string) string {
	fpath := filepath.FromSlash(spath)
	prefix, tail := splitFirst(fpath)
	for _, e := range m.list {
		if e.prefix == prefix {
			// found potential mapping
			abspath := filepath.Join(e.path, tail)
			if _, err := fs.Stat(abspath); err == nil {
				return abspath
			}
		}
	}
	return "" // no match
}

// ToRelative maps an absolute filesystem path to a relative slash-separated
// path using the Mapping specified by the receiver. If the path cannot
// be mapped, the empty string is returned.
//
func (m *Mapping) ToRelative(fpath string) string {
	for _, e := range m.list {
		if strings.HasPrefix(fpath, e.path) {
			spath := filepath.ToSlash(fpath)
			// /absolute/prefix/foo -> prefix/foo
			return path.Join(e.prefix, spath[len(e.path):]) // Join will remove a trailing '/'
		}
	}
	return "" // no match
}

// Iterate calls f for each path and RWValue in the mapping (in uspecified order)
// until f returns false.
//
func (m *Mapping) Iterate(f func(path string, value *RWValue) bool) {
	for _, e := range m.list {
		if !f(e.path, e.value) {
			return
		}
	}
}
<commit_msg>godoc: fix absolute->relative mapping<commit_after>// Copyright 2009 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.

// This file implements the Mapping data structure.

package main

import (
	"fmt"
	"io"
	"path"
	"path/filepath"
	"sort"
	"strings"
)

// A Mapping object maps relative paths (e.g. from URLs)
// to absolute paths (of the file system) and vice versa.
//
// A Mapping object consists of a list of individual mappings
// of the form: prefix -> path which are interpreted as follows:
// A relative path of the form prefix/tail is to be mapped to
// the absolute path/tail, if that absolute path exists in the file
// system. Given a Mapping object, a relative path is mapped to an
// absolute path by trying each of the individual mappings in order,
// until a valid mapping is found. For instance, for the mapping:
//
//	user   -> /home/user
//	public -> /home/user/public
//	public -> /home/build/public
//
// the relative paths below are mapped to absolute paths as follows:
//
//	user/foo                -> /home/user/foo
//	public/net/rpc/file1.go -> /home/user/public/net/rpc/file1.go
//
// If there is no /home/user/public/net/rpc/file2.go, the next public
// mapping entry is used to map the relative path to:
//
//	public/net/rpc/file2.go -> /home/build/public/net/rpc/file2.go
//
// (assuming that file exists).
//
// Each individual mapping also has a RWValue associated with it that
// may be used to store mapping-specific information. See the Iterate
// method.
//
type Mapping struct {
	list     []mapping
	prefixes []string // lazily computed from list
}

type mapping struct {
	prefix, path string
	value        *RWValue
}

// Init initializes the Mapping from a list of paths.
// Empty paths are ignored; relative paths are assumed to be relative to
// the current working directory and converted to absolute paths.
// For each path of the form:
//
//	dirname/localname
//
// a mapping
//
//	localname -> path
//
// is added to the Mapping object, in the order of occurrence.
// For instance, under Unix, the argument:
//
//	/home/user:/home/build/public
//
// leads to the following mapping:
//
//	user   -> /home/user
//	public -> /home/build/public
//
func (m *Mapping) Init(paths []string) {
	pathlist := canonicalizePaths(paths, nil)
	list := make([]mapping, len(pathlist))

	// create mapping list
	for i, path := range pathlist {
		_, prefix := filepath.Split(path)
		list[i] = mapping{prefix, path, new(RWValue)}
	}

	m.list = list
}

// IsEmpty returns true if there are no mappings specified.
func (m *Mapping) IsEmpty() bool { return len(m.list) == 0 }

// PrefixList returns a list of all prefixes, with duplicates removed.
// For instance, for the mapping:
//
//	user   -> /home/user
//	public -> /home/user/public
//	public -> /home/build/public
//
// the prefix list is:
//
//	user, public
//
func (m *Mapping) PrefixList() []string {
	// compute the list lazily
	if m.prefixes == nil {
		list := make([]string, len(m.list))

		// populate list
		for i, e := range m.list {
			list[i] = e.prefix
		}

		// sort the list and remove duplicate entries
		sort.Strings(list)
		i := 0
		prev := ""
		for _, path := range list {
			if path != prev {
				list[i] = path
				i++
				prev = path
			}
		}

		m.prefixes = list[0:i]
	}

	return m.prefixes
}

// Fprint prints the mapping.
func (m *Mapping) Fprint(w io.Writer) {
	for _, e := range m.list {
		fmt.Fprintf(w, "\t%s -> %s\n", e.prefix, e.path)
	}
}

// splitFirst splits a path at the first path separator and returns
// the path's head (the top-most directory specified by the path) and
// its tail (the rest of the path). If there is no path separator,
// splitFirst returns path as head, and the the empty string as tail.
// Specifically, splitFirst("foo") == splitFirst("foo/").
//
func splitFirst(path string) (head, tail string) {
	if i := strings.Index(path, string(filepath.Separator)); i > 0 {
		// 0 < i < len(path)
		return path[0:i], path[i+1:]
	}
	return path, ""
}

// ToAbsolute maps a slash-separated relative path to an absolute filesystem
// path using the Mapping specified by the receiver. If the path cannot
// be mapped, the empty string is returned.
//
func (m *Mapping) ToAbsolute(spath string) string {
	fpath := filepath.FromSlash(spath)
	prefix, tail := splitFirst(fpath)
	for _, e := range m.list {
		if e.prefix == prefix {
			// found potential mapping
			abspath := filepath.Join(e.path, tail)
			if _, err := fs.Stat(abspath); err == nil {
				return abspath
			}
		}
	}
	return "" // no match
}

// ToRelative maps an absolute filesystem path to a relative slash-separated
// path using the Mapping specified by the receiver. If the path cannot
// be mapped, the empty string is returned.
//
func (m *Mapping) ToRelative(fpath string) string {
	for _, e := range m.list {
		// if fpath has prefix e.path, the next character must be a separator (was issue 3096)
		if strings.HasPrefix(fpath, e.path) && fpath[len(e.path)] == filepath.Separator {
			spath := filepath.ToSlash(fpath)
			// /absolute/prefix/foo -> prefix/foo
			return path.Join(e.prefix, spath[len(e.path):]) // Join will remove a trailing '/'
		}
	}
	return "" // no match
}

// Iterate calls f for each path and RWValue in the mapping (in uspecified order)
// until f returns false.
//
func (m *Mapping) Iterate(f func(path string, value *RWValue) bool) {
	for _, e := range m.list {
		if !f(e.path, e.value) {
			return
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2019 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 dragonfly freebsd linux netbsd openbsd

package main

import (
	"internal/testenv"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"testing"
)

var asmSource = `
	.section .text1,"ax"
s1:
	.byte 0
	.section .text2,"ax"
s2:
	.byte 0
`

var goSource = `
package main
func main() {}
`

// The linker used to crash if an ELF input file had multiple text sections
// with the same name.
func TestSectionsWithSameName(t *testing.T) {
	testenv.MustHaveGoBuild(t)
	testenv.MustHaveCGO(t)
	t.Parallel()

	objcopy, err := exec.LookPath("objcopy")
	if err != nil {
		t.Skipf("can't find objcopy: %v", err)
	}

	dir, err := ioutil.TempDir("", "go-link-TestSectionsWithSameName")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(dir)

	gopath := filepath.Join(dir, "GOPATH")
	env := append(os.Environ(), "GOPATH="+gopath)

	if err := ioutil.WriteFile(filepath.Join(dir, "go.mod"), []byte("module elf_test\n"), 0666); err != nil {
		t.Fatal(err)
	}

	asmFile := filepath.Join(dir, "x.s")
	if err := ioutil.WriteFile(asmFile, []byte(asmSource), 0444); err != nil {
		t.Fatal(err)
	}

	goTool := testenv.GoToolPath(t)
	cmd := exec.Command(goTool, "env", "CC")
	cmd.Env = env
	ccb, err := cmd.Output()
	if err != nil {
		t.Fatal(err)
	}
	cc := strings.TrimSpace(string(ccb))

	cmd = exec.Command(goTool, "env", "GOGCCFLAGS")
	cmd.Env = env
	cflagsb, err := cmd.Output()
	if err != nil {
		t.Fatal(err)
	}
	cflags := strings.Fields(string(cflagsb))

	asmObj := filepath.Join(dir, "x.o")
	t.Logf("%s %v -c -o %s %s", cc, cflags, asmObj, asmFile)
	if out, err := exec.Command(cc, append(cflags, "-c", "-o", asmObj, asmFile)...).CombinedOutput(); err != nil {
		t.Logf("%s", out)
		t.Fatal(err)
	}

	asm2Obj := filepath.Join(dir, "x2.syso")
	t.Logf("%s --rename-section .text2=.text1 %s %s", objcopy, asmObj, asm2Obj)
	if out, err := exec.Command(objcopy, "--rename-section", ".text2=.text1", asmObj, asm2Obj).CombinedOutput(); err != nil {
		t.Logf("%s", out)
		t.Fatal(err)
	}

	for _, s := range []string{asmFile, asmObj} {
		if err := os.Remove(s); err != nil {
			t.Fatal(err)
		}
	}

	goFile := filepath.Join(dir, "main.go")
	if err := ioutil.WriteFile(goFile, []byte(goSource), 0444); err != nil {
		t.Fatal(err)
	}

	cmd = exec.Command(goTool, "build")
	cmd.Dir = dir
	cmd.Env = env
	t.Logf("%s build", goTool)
	if out, err := cmd.CombinedOutput(); err != nil {
		t.Logf("%s", out)
		t.Fatal(err)
	}
}
<commit_msg>cmd/link: add new linker testpoint for "ld -r" host object<commit_after>// Copyright 2019 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 dragonfly freebsd linux netbsd openbsd

package main

import (
	"fmt"
	"internal/testenv"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"testing"
)

func getCCAndCCFLAGS(t *testing.T, env []string) (string, []string) {
	goTool := testenv.GoToolPath(t)
	cmd := exec.Command(goTool, "env", "CC")
	cmd.Env = env
	ccb, err := cmd.Output()
	if err != nil {
		t.Fatal(err)
	}
	cc := strings.TrimSpace(string(ccb))

	cmd = exec.Command(goTool, "env", "GOGCCFLAGS")
	cmd.Env = env
	cflagsb, err := cmd.Output()
	if err != nil {
		t.Fatal(err)
	}
	cflags := strings.Fields(string(cflagsb))

	return cc, cflags
}

var asmSource = `
	.section .text1,"ax"
s1:
	.byte 0
	.section .text2,"ax"
s2:
	.byte 0
`

var goSource = `
package main
func main() {}
`

// The linker used to crash if an ELF input file had multiple text sections
// with the same name.
func TestSectionsWithSameName(t *testing.T) {
	testenv.MustHaveGoBuild(t)
	testenv.MustHaveCGO(t)
	t.Parallel()

	objcopy, err := exec.LookPath("objcopy")
	if err != nil {
		t.Skipf("can't find objcopy: %v", err)
	}

	dir, err := ioutil.TempDir("", "go-link-TestSectionsWithSameName")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(dir)

	gopath := filepath.Join(dir, "GOPATH")
	env := append(os.Environ(), "GOPATH="+gopath)

	if err := ioutil.WriteFile(filepath.Join(dir, "go.mod"), []byte("module elf_test\n"), 0666); err != nil {
		t.Fatal(err)
	}

	asmFile := filepath.Join(dir, "x.s")
	if err := ioutil.WriteFile(asmFile, []byte(asmSource), 0444); err != nil {
		t.Fatal(err)
	}

	goTool := testenv.GoToolPath(t)
	cc, cflags := getCCAndCCFLAGS(t, env)

	asmObj := filepath.Join(dir, "x.o")
	t.Logf("%s %v -c -o %s %s", cc, cflags, asmObj, asmFile)
	if out, err := exec.Command(cc, append(cflags, "-c", "-o", asmObj, asmFile)...).CombinedOutput(); err != nil {
		t.Logf("%s", out)
		t.Fatal(err)
	}

	asm2Obj := filepath.Join(dir, "x2.syso")
	t.Logf("%s --rename-section .text2=.text1 %s %s", objcopy, asmObj, asm2Obj)
	if out, err := exec.Command(objcopy, "--rename-section", ".text2=.text1", asmObj, asm2Obj).CombinedOutput(); err != nil {
		t.Logf("%s", out)
		t.Fatal(err)
	}

	for _, s := range []string{asmFile, asmObj} {
		if err := os.Remove(s); err != nil {
			t.Fatal(err)
		}
	}

	goFile := filepath.Join(dir, "main.go")
	if err := ioutil.WriteFile(goFile, []byte(goSource), 0444); err != nil {
		t.Fatal(err)
	}

	cmd := exec.Command(goTool, "build")
	cmd.Dir = dir
	cmd.Env = env
	t.Logf("%s build", goTool)
	if out, err := cmd.CombinedOutput(); err != nil {
		t.Logf("%s", out)
		t.Fatal(err)
	}
}

var cSources35779 = []string{`
static int blah() { return 42; }
int Cfunc1() { return blah(); }
`, `
static int blah() { return 42; }
int Cfunc2() { return blah(); }
`,
}

// TestMinusRSymsWithSameName tests a corner case in the new
// loader. Prior to the fix this failed with the error 'loadelf:
// $WORK/b001/_pkg_.a(ldr.syso): duplicate symbol reference: blah in
// both main(.text) and main(.text)'
func TestMinusRSymsWithSameName(t *testing.T) {
	testenv.MustHaveGoBuild(t)
	testenv.MustHaveCGO(t)
	t.Parallel()

	dir, err := ioutil.TempDir("", "go-link-TestMinusRSymsWithSameName")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(dir)

	gopath := filepath.Join(dir, "GOPATH")
	env := append(os.Environ(), "GOPATH="+gopath)

	if err := ioutil.WriteFile(filepath.Join(dir, "go.mod"), []byte("module elf_test\n"), 0666); err != nil {
		t.Fatal(err)
	}

	goTool := testenv.GoToolPath(t)
	cc, cflags := getCCAndCCFLAGS(t, env)

	objs := []string{}
	csrcs := []string{}
	for i, content := range cSources35779 {
		csrcFile := filepath.Join(dir, fmt.Sprintf("x%d.c", i))
		csrcs = append(csrcs, csrcFile)
		if err := ioutil.WriteFile(csrcFile, []byte(content), 0444); err != nil {
			t.Fatal(err)
		}

		obj := filepath.Join(dir, fmt.Sprintf("x%d.o", i))
		objs = append(objs, obj)
		t.Logf("%s %v -c -o %s %s", cc, cflags, obj, csrcFile)
		if out, err := exec.Command(cc, append(cflags, "-c", "-o", obj, csrcFile)...).CombinedOutput(); err != nil {
			t.Logf("%s", out)
			t.Fatal(err)
		}
	}

	sysoObj := filepath.Join(dir, "ldr.syso")
	t.Logf("%s %v -nostdlib -r -o %s %v", cc, cflags, sysoObj, objs)
	if out, err := exec.Command(cc, append(cflags, "-nostdlib", "-r", "-o", sysoObj, objs[0], objs[1])...).CombinedOutput(); err != nil {
		t.Logf("%s", out)
		t.Fatal(err)
	}

	cruft := [][]string{objs, csrcs}
	for _, sl := range cruft {
		for _, s := range sl {
			if err := os.Remove(s); err != nil {
				t.Fatal(err)
			}
		}
	}

	goFile := filepath.Join(dir, "main.go")
	if err := ioutil.WriteFile(goFile, []byte(goSource), 0444); err != nil {
		t.Fatal(err)
	}

	t.Logf("%s build", goTool)
	cmd := exec.Command(goTool, "build")
	cmd.Dir = dir
	cmd.Env = env
	t.Logf("%s build", goTool)
	if out, err := cmd.CombinedOutput(); err != nil {
		t.Logf("%s", out)
		t.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"log"
	"strings"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/ses"
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceAwsSesNotification() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsSesNotificationSet,
		Read:   resourceAwsSesNotificationRead,
		Update: resourceAwsSesNotificationSet,
		Delete: resourceAwsSesNotificationDelete,

		Schema: map[string]*schema.Schema{
			"topic_arn": {
				Type:         schema.TypeString,
				Optional:     true,
				ValidateFunc: validateArn,
			},

			"notification_type": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
				ValidateFunc: validation.StringInSlice([]string{
					ses.NotificationTypeBounce,
					ses.NotificationTypeComplaint,
					ses.NotificationTypeDelivery,
				}, false),
			},

			"identity": {
				Type:         schema.TypeString,
				Required:     true,
				ForceNew:     true,
				ValidateFunc: validation.NoZeroValues,
			},
		},
	}
}

func resourceAwsSesNotificationSet(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).sesConn
	topic := d.Get("topic_arn").(string)
	notification := d.Get("notification_type").(string)
	identity := d.Get("identity").(string)

	setOpts := &ses.SetIdentityNotificationTopicInput{
		Identity:         aws.String(identity),
		NotificationType: aws.String(notification),
		SnsTopic:         aws.String(topic),
	}

	d.SetId(fmt.Sprintf("%s|%s", identity, notification))

	log.Printf("[DEBUG] Setting SES Identity Notification: %#v", setOpts)

	if _, err := conn.SetIdentityNotificationTopic(setOpts); err != nil {
		return fmt.Errorf("Error setting SES Identity Notification: %s", err)
	}

	return resourceAwsSesNotificationRead(d, meta)
}

func resourceAwsSesNotificationRead(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).sesConn

	identity, notificationType, err := decodeSesIdentityNotificationId(d.Id())
	if err != nil {
		return err
	}

	getOpts := &ses.GetIdentityNotificationAttributesInput{
		Identities: []*string{aws.String(identity)},
	}

	log.Printf("[DEBUG] Reading SES Identity Notification Attributes: %#v", getOpts)

	response, err := conn.GetIdentityNotificationAttributes(getOpts)

	if err != nil {
		return fmt.Errorf("Error reading SES Identity Notification: %s", err)
	}

	notificationAttributes := response.NotificationAttributes[identity]
	switch notificationType {
	case ses.NotificationTypeBounce:
		d.Set("topic_arn", notificationAttributes.BounceTopic)
	case ses.NotificationTypeComplaint:
		d.Set("topic_arn", notificationAttributes.ComplaintTopic)
	case ses.NotificationTypeDelivery:
		d.Set("topic_arn", notificationAttributes.DeliveryTopic)
	}

	return nil
}

func resourceAwsSesNotificationDelete(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).sesConn

	identity, notificationType, err := decodeSesIdentityNotificationId(d.Id())
	if err != nil {
		return err
	}

	setOpts := &ses.SetIdentityNotificationTopicInput{
		Identity:         aws.String(identity),
		NotificationType: aws.String(notificationType),
		SnsTopic:         nil,
	}

	log.Printf("[DEBUG] Deleting SES Identity Notification: %#v", setOpts)

	if _, err := conn.SetIdentityNotificationTopic(setOpts); err != nil {
		return fmt.Errorf("Error deleting SES Identity Notification: %s", err)
	}

	return resourceAwsSesNotificationRead(d, meta)
}

func decodeSesIdentityNotificationId(id string) (string, string, error) {
	parts := strings.Split(id, "|")
	if len(parts) != 2 {
		return "", "", fmt.Errorf("Unexpected format of ID (%q), expected IDENTITY|TYPE", id)
	}
	return parts[0], parts[1], nil
}
<commit_msg>#931 Import validation<commit_after>package aws

import (
	"fmt"
	"log"
	"strings"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/ses"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/hashicorp/terraform/helper/validation"
)

func resourceAwsSesNotification() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsSesNotificationSet,
		Read:   resourceAwsSesNotificationRead,
		Update: resourceAwsSesNotificationSet,
		Delete: resourceAwsSesNotificationDelete,

		Schema: map[string]*schema.Schema{
			"topic_arn": {
				Type:         schema.TypeString,
				Optional:     true,
				ValidateFunc: validateArn,
			},

			"notification_type": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
				ValidateFunc: validation.StringInSlice([]string{
					ses.NotificationTypeBounce,
					ses.NotificationTypeComplaint,
					ses.NotificationTypeDelivery,
				}, false),
			},

			"identity": {
				Type:         schema.TypeString,
				Required:     true,
				ForceNew:     true,
				ValidateFunc: validation.NoZeroValues,
			},
		},
	}
}

func resourceAwsSesNotificationSet(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).sesConn
	topic := d.Get("topic_arn").(string)
	notification := d.Get("notification_type").(string)
	identity := d.Get("identity").(string)

	setOpts := &ses.SetIdentityNotificationTopicInput{
		Identity:         aws.String(identity),
		NotificationType: aws.String(notification),
		SnsTopic:         aws.String(topic),
	}

	d.SetId(fmt.Sprintf("%s|%s", identity, notification))

	log.Printf("[DEBUG] Setting SES Identity Notification: %#v", setOpts)

	if _, err := conn.SetIdentityNotificationTopic(setOpts); err != nil {
		return fmt.Errorf("Error setting SES Identity Notification: %s", err)
	}

	return resourceAwsSesNotificationRead(d, meta)
}

func resourceAwsSesNotificationRead(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).sesConn

	identity, notificationType, err := decodeSesIdentityNotificationId(d.Id())
	if err != nil {
		return err
	}

	getOpts := &ses.GetIdentityNotificationAttributesInput{
		Identities: []*string{aws.String(identity)},
	}

	log.Printf("[DEBUG] Reading SES Identity Notification Attributes: %#v", getOpts)

	response, err := conn.GetIdentityNotificationAttributes(getOpts)

	if err != nil {
		return fmt.Errorf("Error reading SES Identity Notification: %s", err)
	}

	notificationAttributes := response.NotificationAttributes[identity]
	switch notificationType {
	case ses.NotificationTypeBounce:
		d.Set("topic_arn", notificationAttributes.BounceTopic)
	case ses.NotificationTypeComplaint:
		d.Set("topic_arn", notificationAttributes.ComplaintTopic)
	case ses.NotificationTypeDelivery:
		d.Set("topic_arn", notificationAttributes.DeliveryTopic)
	}

	return nil
}

func resourceAwsSesNotificationDelete(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).sesConn

	identity, notificationType, err := decodeSesIdentityNotificationId(d.Id())
	if err != nil {
		return err
	}

	setOpts := &ses.SetIdentityNotificationTopicInput{
		Identity:         aws.String(identity),
		NotificationType: aws.String(notificationType),
		SnsTopic:         nil,
	}

	log.Printf("[DEBUG] Deleting SES Identity Notification: %#v", setOpts)

	if _, err := conn.SetIdentityNotificationTopic(setOpts); err != nil {
		return fmt.Errorf("Error deleting SES Identity Notification: %s", err)
	}

	return resourceAwsSesNotificationRead(d, meta)
}

func decodeSesIdentityNotificationId(id string) (string, string, error) {
	parts := strings.Split(id, "|")
	if len(parts) != 2 {
		return "", "", fmt.Errorf("Unexpected format of ID (%q), expected IDENTITY|TYPE", id)
	}
	return parts[0], parts[1], nil
}
<|endoftext|>


<commit_before>package reddit

import (
	"bytes"
	"fmt"
	"net/http"
)

// tokenURL is the url of reddit's oauth2 authorization service.
const tokenURL = "https://www.reddit.com/api/v1/access_token"

// clientConfig holds all the information needed to define Client behavior, such
// as who the client will identify as externally and where to authorize.
type clientConfig struct {
	// Agent is the user agent set in all requests made by the Client.
	agent string

	// If all fields in App are set, this client will attempt to identify as
	// a registered Reddit app using the credentials.
	app App
}

// client executes http Requests and invisibly handles OAuth2 authorization.
type client interface {
	Do(*http.Request) ([]byte, error)
}

type baseClient struct {
	cli *http.Client
}

func (b *baseClient) Do(req *http.Request) ([]byte, error) {
	resp, err := b.cli.Do(req)
	if err != nil {
		return nil, err
	}

	switch resp.StatusCode {
	case http.StatusOK:
	case http.StatusForbidden:
		return nil, PermissionDeniedErr
	case http.StatusServiceUnavailable:
		return nil, BusyErr
	case http.StatusTooManyRequests:
		return nil, RateLimitErr
	case http.StatusBadGateway:
		return nil, GatewayErr
	case http.StatusGatewayTimeout:
		return nil, GatewayTimeoutErr
	default:
		return nil, fmt.Errorf("bad response code: %d", resp.StatusCode)
	}

	var buf bytes.Buffer
	if _, err := buf.ReadFrom(resp.Body); err != nil {
		return nil, err
	}

	return buf.Bytes(), nil
}

// newClient returns a new client using the given user to make requests.
func newClient(c clientConfig) (client, error) {
	if c.app.tokenURL == "" {
		c.app.tokenURL = tokenURL
	}

	if c.app.configured() {
		return newAppClient(c)
	}

	return &baseClient{clientWithAgent(c.agent)}, nil
}
<commit_msg>Fixing a memory leak problem in the HTTP client<commit_after>package reddit

import (
	"bytes"
	"fmt"
	"net/http"
)

// tokenURL is the url of reddit's oauth2 authorization service.
const tokenURL = "https://www.reddit.com/api/v1/access_token"

// clientConfig holds all the information needed to define Client behavior, such
// as who the client will identify as externally and where to authorize.
type clientConfig struct {
	// Agent is the user agent set in all requests made by the Client.
	agent string

	// If all fields in App are set, this client will attempt to identify as
	// a registered Reddit app using the credentials.
	app App
}

// client executes http Requests and invisibly handles OAuth2 authorization.
type client interface {
	Do(*http.Request) ([]byte, error)
}

type baseClient struct {
	cli *http.Client
}

func (b *baseClient) Do(req *http.Request) ([]byte, error) {
	resp, err := b.cli.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	switch resp.StatusCode {
	case http.StatusOK:
	case http.StatusForbidden:
		return nil, PermissionDeniedErr
	case http.StatusServiceUnavailable:
		return nil, BusyErr
	case http.StatusTooManyRequests:
		return nil, RateLimitErr
	case http.StatusBadGateway:
		return nil, GatewayErr
	case http.StatusGatewayTimeout:
		return nil, GatewayTimeoutErr
	default:
		return nil, fmt.Errorf("bad response code: %d", resp.StatusCode)
	}

	var buf bytes.Buffer
	if _, err := buf.ReadFrom(resp.Body); err != nil {
		return nil, err
	}

	return buf.Bytes(), nil
}

// newClient returns a new client using the given user to make requests.
func newClient(c clientConfig) (client, error) {
	if c.app.tokenURL == "" {
		c.app.tokenURL = tokenURL
	}

	if c.app.configured() {
		return newAppClient(c)
	}

	return &baseClient{clientWithAgent(c.agent)}, nil
}
<|endoftext|>


<commit_before>package qq

import (
	"bytes"
	"fmt"
	"go/ast"
	"go/parser"
	"go/printer"
	"go/token"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"sync"
	"time"
)

type color string

const (
	// Control what's printed in the header line.
	// See https://golang.org/pkg/log/#pkg-constants for an explanation of how
	// these flags work.
	Ldate = 1 << iota
	Ltime
	Lmicroseconds
	Llongfile
	Lshortfile
	LUTC
	Lfuncname
	LstdFlags = Ltime | Lshortfile | Lfuncname

	// ANSI color escape codes
	bold     color = "\033[1m"
	yellow   color = "\033[33m"
	cyan     color = "\033[36m"
	endColor color = "\033[0m" // "reset everything"

	noName = ""
)

// A Logger writes pretty log messages to a file. Loggers write to files only,
// not io.Writers. The upside of this restriction is you don't have to open
// and close log files yourself. Loggers do that for you. Loggers are safe for
// concurrent use.
type Logger struct {
	mu       sync.Mutex  // protects all the other fields
	path     string      // full path to log file
	flag     int         // determines what's printed in header line
	start    time.Time   // time of first write in the current log group
	timer    *time.Timer // when it gets to 0, start a new log group
	lastFile string      // last file to call Log(). determines when to print header
	lastFunc string      // last function to call Log()
}

// New creates a Logger that writes to the file at the given path.
func New(path string, flag int) *Logger {
	t := time.NewTimer(0)
	t.Stop()

	return &Logger{
		path:  path,
		flag:  flag,
		timer: t,
	}
}

// Log pretty-prints the given arguments to the file associated with the Logger.
func (l *Logger) Log(a ...interface{}) {
	l.mu.Lock()
	defer l.mu.Unlock()

	// will print line break if more than 2s since last write (groups logs
	// together)
	timerExpired := !l.timer.Reset(2 * time.Second)
	if timerExpired {
		l.start = time.Now()
	}

	// get info about func calling qq.Log()
	var callDepth int
	if l == std {
		callDepth = 2 // user is calling qq.Log()
	} else {
		callDepth = 1 // user is calling myCustomQQLogger.Log()
	}
	pc, filename, line, ok := runtime.Caller(callDepth)
	if !ok {
		l.Output(a...) // no fancy printing :(
		return
	}

	// print header if necessary, e.g. [14:00:36 main.go main.main]
	funcName := runtime.FuncForPC(pc).Name()
	if timerExpired || funcName != l.lastFunc || filename != l.lastFile {
		l.lastFunc = funcName
		l.lastFile = filename
		header := l.formatHeader(time.Now(), filename, funcName, line)
		l.printHeader(header)
	}

	// extract arg names from source text between parens in qq.Log()
	names, err := argNames(filename, line)
	if err != nil {
		l.Output(a...) // no fancy printing :(
		return
	}

	// colorize names and values. convert values to %#v strings
	a = formatArgs(names, a)
	l.Output(a...)
}

// Path retuns the full path to the file associated with the Logger.
func (l *Logger) Path() string {
	return l.path
}

// open returns a file descriptor for the file at l.path, creating it if it
// doesn't exist. It will panic if it can't open the file.
func (l *Logger) open() *os.File {
	f, err := os.OpenFile(l.path, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0600)
	if err != nil {
		panic(err)
	}
	return f
}

// Output writes to the log file associated with l. Each log message is
// prepended with a timestamp.
func (l *Logger) Output(a ...interface{}) {
	timestamp := fmt.Sprintf("%.3fs", time.Since(l.start).Seconds())
	timestamp = colorize(timestamp, yellow)
	a = append([]interface{}{timestamp}, a...)
	f := l.open()
	defer f.Close()
	fmt.Fprintln(f, a...)
}

// formatHeader creates the header based on which flags are set in the logger.
func (l *Logger) formatHeader(t time.Time, filename, funcName string, line int) string {
	if l.flag&LUTC != 0 {
		t = t.UTC()
	}

	const maxHeaders = 4 // [date time filename funcname]
	h := make([]string, 0, maxHeaders)
	if l.flag&Ldate != 0 {
		h = append(h, t.Format("2006/01/02"))
	}

	if l.flag&Lmicroseconds != 0 {
		h = append(h, t.Format("15:04:05.000000"))
	} else if l.flag&Ltime != 0 {
		h = append(h, t.Format("15:04:05"))
	}

	// if Llongfile and Lshortfile both present, Lshortfile wins
	if l.flag&Lshortfile != 0 {
		filename = filepath.Base(filename)
	}
	if l.flag&(Llongfile|Lshortfile) != 0 {
		h = append(h, fmt.Sprintf("%s:%d", filename, line))
	}

	if l.flag&Lfuncname != 0 {
		h = append(h, funcName)
	}

	return fmt.Sprintf("[%s]", strings.Join(h, " "))
}

// printHeader prints a header of the form [16:11:18 main.go main.main]. Headers
// make logs easier to read by reducing redundant information that is normally
// printed on each line.
func (l *Logger) printHeader(header string) {
	f := l.open()
	defer f.Close()
	fmt.Fprint(f, "\n", header, "\n")
}

// SetFlags sets the header flags for the logger.
func (l *Logger) SetFlags(flag int) {
	l.mu.Lock()
	defer l.mu.Unlock()
	l.flag = flag
}

// SetPath sets the destination log file for the logger.
func (l *Logger) SetPath(path string) {
	l.mu.Lock()
	defer l.mu.Unlock()
	l.path = path
}

// argNames finds the qq.Log() call at the given filename/line number and
// returns its arguments as a slice of strings. If the argument is a literal,
// argNames will return an empty string at the index position of that argument.
// For example, qq.Log(ip, port, 5432) would return []string{"ip", "port", ""}.
// argNames returns a non-nil error if the source text cannot be parsed.
func argNames(filename string, line int) ([]string, error) {
	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, filename, nil, 0)
	if err != nil {
		return nil, err
	}

	var names []string
	ast.Inspect(f, func(n ast.Node) bool {
		call, is := n.(*ast.CallExpr)
		if !is {
			return true // visit next node
		}

		// is a function call, but on wrong line
		if fset.Position(call.End()).Line != line {
			return true
		}

		// is a function call on correct line, but not a qq function
		if !qqCall(call) {
			return true
		}

		for _, arg := range call.Args {
			names = append(names, argName(arg))
		}
		return true
	})

	return names, nil
}

// qqCall returns true if the given function call expression is for a qq
// function, e.g. qq.Log().
func qqCall(n *ast.CallExpr) bool {
	sel, is := n.Fun.(*ast.SelectorExpr) // SelectorExpr example: a.B()
	if !is {
		return false
	}

	ident, is := sel.X.(*ast.Ident) // sel.X is the part that precedes the .
	if !is {
		return false
	}

	return ident.Name == "qq"
}

// argName returns the source text of the given argument if it's a variable or
// an expression. If the argument is something else, like a literal, argName
// returns an empty string.
func argName(arg ast.Expr) string {
	var name string
	switch a := arg.(type) {
	case *ast.Ident:
		if a.Obj.Kind == ast.Var {
			name = a.Obj.Name
		}
	case *ast.BinaryExpr,
		*ast.CallExpr,
		*ast.IndexExpr,
		*ast.KeyValueExpr,
		*ast.ParenExpr,
		*ast.SliceExpr,
		*ast.TypeAssertExpr,
		*ast.UnaryExpr:
		name = exprToString(arg)
	}
	return name
}

// exprToString returns the source text underlying the given ast.Expr.
func exprToString(arg ast.Expr) string {
	var buf bytes.Buffer
	fset := token.NewFileSet()
	printer.Fprint(&buf, fset, arg)
	return buf.String() // returns empty string if printer fails
}

// formatArgs turns a slice of arguments into pretty-printed strings. If the
// argument is a variable or an expression, it will be returned as a
// name=value string, e.g. "port=443", "3+2=5". Variable names, expressions, and
// values are colorized using ANSI escape codes.
func formatArgs(names []string, values []interface{}) []interface{} {
	formatted := make([]interface{}, len(values))
	for i := 0; i < len(values); i++ {
		val := fmt.Sprintf("%#v", values[i])
		val = colorize(val, cyan)

		if names[i] == noName {
			// arg is a literal
			formatted[i] = val
			continue
		}

		name := colorize(names[i], bold)
		formatted[i] = fmt.Sprintf("%s=%s", name, val)
	}
	return formatted
}

// colorize returns the given text encapsulated in ANSI escape codes that
// give the text color in the terminal.
func colorize(text string, c color) string {
	return string(c) + text + string(endColor)
}

// standard logger
var std = New(filepath.Join(os.TempDir(), "qq.log"), LstdFlags)

// Log writes a log message through the standard logger.
func Log(a ...interface{}) {
	std.Log(a...)
}

// Path returns the full path to the standard qq.log file.
func Path() string {
	return std.Path()
}

// SetFlags sets the header flags for the standard logger.
func SetFlags(flag int) {
	std.SetFlags(flag)
}

// SetPath sets the output destination for the standard logger. If the given path
// is invalid, the next Log() call will panic.
func SetPath(path string) {
	std.SetPath(path)
}
<commit_msg>break lines at 80 chars<commit_after>package qq

import (
	"bytes"
	"fmt"
	"go/ast"
	"go/parser"
	"go/printer"
	"go/token"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"sync"
	"time"
)

type color string

const (
	// Control what's printed in the header line.
	// See https://golang.org/pkg/log/#pkg-constants for an explanation of how
	// these flags work.
	Ldate = 1 << iota
	Ltime
	Lmicroseconds
	Llongfile
	Lshortfile
	LUTC
	Lfuncname
	LstdFlags = Ltime | Lshortfile | Lfuncname

	// ANSI color escape codes
	bold     color = "\033[1m"
	yellow   color = "\033[33m"
	cyan     color = "\033[36m"
	endColor color = "\033[0m" // "reset everything"

	noName         = ""
	timeStampWidth = 6
	maxLineWidth   = 80
)

// A Logger writes pretty log messages to a file. Loggers write to files only,
// not io.Writers. The upside of this restriction is you don't have to open
// and close log files yourself. Loggers do that for you. Loggers are safe for
// concurrent use.
type Logger struct {
	mu       sync.Mutex  // protects all the other fields
	path     string      // full path to log file
	flag     int         // determines what's printed in header line
	start    time.Time   // time of first write in the current log group
	timer    *time.Timer // when it gets to 0, start a new log group
	lastFile string      // last file to call Log(). determines when to print header
	lastFunc string      // last function to call Log()
}

// New creates a Logger that writes to the file at the given path.
func New(path string, flag int) *Logger {
	t := time.NewTimer(0)
	t.Stop()

	return &Logger{
		path:  path,
		flag:  flag,
		timer: t,
	}
}

// Log pretty-prints the given arguments to the file associated with the Logger.
func (l *Logger) Log(a ...interface{}) {
	l.mu.Lock()
	defer l.mu.Unlock()

	// will print line break if more than 2s since last write (groups logs
	// together)
	timerExpired := !l.timer.Reset(2 * time.Second)
	if timerExpired {
		l.start = time.Now()
	}

	// get info about func calling qq.Log()
	var callDepth int
	if l == std {
		callDepth = 2 // user is calling qq.Log()
	} else {
		callDepth = 1 // user is calling myCustomQQLogger.Log()
	}
	pc, filename, line, ok := runtime.Caller(callDepth)
	if !ok {
		l.Output(a...) // no fancy printing :(
		return
	}

	// print header if necessary, e.g. [14:00:36 main.go main.main]
	funcName := runtime.FuncForPC(pc).Name()
	if timerExpired || funcName != l.lastFunc || filename != l.lastFile {
		l.lastFunc = funcName
		l.lastFile = filename
		header := l.formatHeader(time.Now(), filename, funcName, line)
		l.printHeader(header)
	}

	// extract arg names from source text between parens in qq.Log()
	names, err := argNames(filename, line)
	if err != nil {
		l.Output(a...) // no fancy printing :(
		return
	}

	// colorize names and values. convert values to %#v strings
	a = formatArgs(names, a)
	l.Output(a...)
}

// Path retuns the full path to the file associated with the Logger.
func (l *Logger) Path() string {
	return l.path
}

// open returns a file descriptor for the file at l.path, creating it if it
// doesn't exist. It will panic if it can't open the file.
func (l *Logger) open() *os.File {
	f, err := os.OpenFile(l.path, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0600)
	if err != nil {
		panic(err)
	}
	return f
}

// Output writes to the log file associated with l. Each log message is
// prepended with a timestamp.
func (l *Logger) Output(a ...interface{}) {
	timestamp := fmt.Sprintf("%.3fs", time.Since(l.start).Seconds())
	timestamp = colorize(timestamp, yellow)
	a = append([]interface{}{timestamp}, a...)
	f := l.open()
	defer f.Close()
	fmt.Fprintln(f, a...)
}

// formatHeader creates the header based on which flags are set in the logger.
func (l *Logger) formatHeader(t time.Time, filename, funcName string, line int) string {
	if l.flag&LUTC != 0 {
		t = t.UTC()
	}

	const maxHeaders = 4 // [date time filename funcname]
	h := make([]string, 0, maxHeaders)
	if l.flag&Ldate != 0 {
		h = append(h, t.Format("2006/01/02"))
	}

	if l.flag&Lmicroseconds != 0 {
		h = append(h, t.Format("15:04:05.000000"))
	} else if l.flag&Ltime != 0 {
		h = append(h, t.Format("15:04:05"))
	}

	// if Llongfile and Lshortfile both present, Lshortfile wins
	if l.flag&Lshortfile != 0 {
		filename = filepath.Base(filename)
	}
	if l.flag&(Llongfile|Lshortfile) != 0 {
		h = append(h, fmt.Sprintf("%s:%d", filename, line))
	}

	if l.flag&Lfuncname != 0 {
		h = append(h, funcName)
	}

	return fmt.Sprintf("[%s]", strings.Join(h, " "))
}

// printHeader prints a header of the form [16:11:18 main.go main.main]. Headers
// make logs easier to read by reducing redundant information that is normally
// printed on each line.
func (l *Logger) printHeader(header string) {
	f := l.open()
	defer f.Close()
	fmt.Fprint(f, "\n", header, "\n")
}

// SetFlags sets the header flags for the logger.
func (l *Logger) SetFlags(flag int) {
	l.mu.Lock()
	defer l.mu.Unlock()
	l.flag = flag
}

// SetPath sets the destination log file for the logger.
func (l *Logger) SetPath(path string) {
	l.mu.Lock()
	defer l.mu.Unlock()
	l.path = path
}

// argNames finds the qq.Log() call at the given filename/line number and
// returns its arguments as a slice of strings. If the argument is a literal,
// argNames will return an empty string at the index position of that argument.
// For example, qq.Log(ip, port, 5432) would return []string{"ip", "port", ""}.
// argNames returns a non-nil error if the source text cannot be parsed.
func argNames(filename string, line int) ([]string, error) {
	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, filename, nil, 0)
	if err != nil {
		return nil, err
	}

	var names []string
	ast.Inspect(f, func(n ast.Node) bool {
		call, is := n.(*ast.CallExpr)
		if !is {
			return true // visit next node
		}

		// is a function call, but on wrong line
		if fset.Position(call.End()).Line != line {
			return true
		}

		// is a function call on correct line, but not a qq function
		if !qqCall(call) {
			return true
		}

		for _, arg := range call.Args {
			names = append(names, argName(arg))
		}
		return true
	})

	return names, nil
}

// qqCall returns true if the given function call expression is for a qq
// function, e.g. qq.Log().
func qqCall(n *ast.CallExpr) bool {
	sel, is := n.Fun.(*ast.SelectorExpr) // SelectorExpr example: a.B()
	if !is {
		return false
	}

	ident, is := sel.X.(*ast.Ident) // sel.X is the part that precedes the .
	if !is {
		return false
	}

	return ident.Name == "qq"
}

// argName returns the source text of the given argument if it's a variable or
// an expression. If the argument is something else, like a literal, argName
// returns an empty string.
func argName(arg ast.Expr) string {
	var name string
	switch a := arg.(type) {
	case *ast.Ident:
		if a.Obj.Kind == ast.Var {
			name = a.Obj.Name
		}
	case *ast.BinaryExpr,
		*ast.CallExpr,
		*ast.IndexExpr,
		*ast.KeyValueExpr,
		*ast.ParenExpr,
		*ast.SliceExpr,
		*ast.TypeAssertExpr,
		*ast.UnaryExpr:
		name = exprToString(arg)
	}
	return name
}

// exprToString returns the source text underlying the given ast.Expr.
func exprToString(arg ast.Expr) string {
	var buf bytes.Buffer
	fset := token.NewFileSet()
	printer.Fprint(&buf, fset, arg)
	return buf.String() // returns empty string if printer fails
}

// formatArgs turns argument names and values into pretty-printed strings. If
// the argument is a variable or an expression, it will be returned as a
// colorized name=value string, e.g. "port=443", "3+2=5". If the argument is a
// literal, only the colorized value will be returned. Variable names,
// expressions, and values are colorized using ANSI escape codes.
func formatArgs(names []string, values []interface{}) []interface{} {
	var formatted []interface{}
	lineWidth := timeStampWidth
	for i, v := range values {
		arg := formatArg(names[i], v)

		// break line at 80 chars
		argWidth := len(arg) + 1 // +1 for trailing space
		lineWidth += argWidth
		if lineWidth > maxLineWidth {
			formatted = append(formatted, "\n      ") // spaces to line up with timestamp
			lineWidth = argWidth
		}

		formatted = append(formatted, arg)
	}
	return formatted
}

// formatArg takes an argument name and value and returns a colorized string,
// with the value in %#v format.
func formatArg(name string, value interface{}) string {
	v := fmt.Sprintf("%#v", value)
	v = colorize(v, cyan)

	if name == noName {
		return v // arg is a literal
	}

	name = colorize(name, bold)
	return fmt.Sprintf("%s=%s", name, v)
}

// colorize returns the given text encapsulated in ANSI escape codes that
// give the text color in the terminal.
func colorize(text string, c color) string {
	return string(c) + text + string(endColor)
}

// standard logger
var std = New(filepath.Join(os.TempDir(), "qq.log"), LstdFlags)

// Log writes a log message through the standard logger.
func Log(a ...interface{}) {
	std.Log(a...)
}

// Path returns the full path to the standard qq.log file.
func Path() string {
	return std.Path()
}

// SetFlags sets the header flags for the standard logger.
func SetFlags(flag int) {
	std.SetFlags(flag)
}

// SetPath sets the output destination for the standard logger. If the given path
// is invalid, the next Log() call will panic.
func SetPath(path string) {
	std.SetPath(path)
}
<|endoftext|>


<commit_before>package sdl

/*
#include <SDL2/SDL_surface.h>
*/
import "C"
import "unsafe"
import "reflect"

const (
	SWSURFACE	= 0
	PREALLOC	= 0x00000001
	RLEACCEL	= 0x00000002
	DONTFREE	= 0x00000004
)

type Surface struct {
	Flags uint32
	Format *PixelFormat
	W int32
	H int32
	Pitch int
	pixels unsafe.Pointer // use Pixels() for access
	UserData unsafe.Pointer
	Locked int
	LockData unsafe.Pointer
	ClipRect Rect
	_map *[0]byte
	RefCount int
}

type blit C.SDL_blit

func (surface *Surface) MustLock() bool {
	return (surface.Flags & RLEACCEL) != 0
}

func CreateRGBSurface(flags uint32, width, height, depth int32,
		Rmask, Gmask, Bmask, Amask uint32) *Surface {
	_flags := (C.Uint32) (flags)
	_width := (C.int) (width)
	_height := (C.int) (height)
	_depth := (C.int) (depth)
	_Rmask := (C.Uint32) (Rmask)
	_Gmask := (C.Uint32) (Gmask)
	_Bmask := (C.Uint32) (Bmask)
	_Amask := (C.Uint32) (Amask)
	return (*Surface) (unsafe.Pointer(C.SDL_CreateRGBSurface(_flags, _width, _height,
				_depth, _Rmask, _Gmask, _Bmask, _Amask)))
}

func CreateRGBSurfaceFrom(pixels unsafe.Pointer, width, height, depth, pitch int32,
		Rmask, Gmask, Bmask, Amask uint32) *Surface {
	_width := (C.int) (width)
	_height := (C.int) (height)
	_depth := (C.int) (depth)
	_pitch := (C.int) (pitch)
	_Rmask := (C.Uint32) (Rmask)
	_Gmask := (C.Uint32) (Gmask)
	_Bmask := (C.Uint32) (Bmask)
	_Amask := (C.Uint32) (Amask)
	return (*Surface) (unsafe.Pointer(C.SDL_CreateRGBSurfaceFrom(pixels, _width, _height,
				_depth, _pitch, _Rmask, _Gmask, _Bmask, _Amask)))
}

func (surface *Surface) Free() {
	_surface := (*C.SDL_Surface) (unsafe.Pointer(surface))
	C.SDL_FreeSurface(_surface)
}

func (surface *Surface) SetPalette(palette *Palette) int {
	_surface := (*C.SDL_Surface) (unsafe.Pointer(surface))
	_palette := (*C.SDL_Palette) (unsafe.Pointer(palette))
	return (int) (C.SDL_SetSurfacePalette(_surface, _palette))
}

func (surface *Surface) Lock() {
	_surface := (*C.SDL_Surface) (unsafe.Pointer(surface))
	C.SDL_LockSurface(_surface)
}

func (surface *Surface) Unlock() {
	_surface := (*C.SDL_Surface) (unsafe.Pointer(surface))
	C.SDL_UnlockSurface(_surface)
}

func LoadBMP_RW(src *RWops, freesrc int) *Surface {
	_src := (*C.SDL_RWops) (unsafe.Pointer(src))
	_freesrc := (C.int) (freesrc)
	_surface := C.SDL_LoadBMP_RW(_src, _freesrc)
	return (*Surface) (unsafe.Pointer(_surface))
}

func LoadBMP(file string) *Surface {
	return (*Surface) (LoadBMP_RW(RWFromFile(file, "rb"), 1))
}

func (surface *Surface) SaveBMP_RW(dst *RWops, freedst int) int {
	_surface := (*C.SDL_Surface) (unsafe.Pointer(surface))
	_dst := (*C.SDL_RWops) (unsafe.Pointer(dst))
	_freedst := (C.int) (freedst)
	return (int) (C.SDL_SaveBMP_RW(_surface, _dst, _freedst))
}

func (surface *Surface) SaveBMP(file string) int {
	return (int) (surface.SaveBMP_RW(RWFromFile(file, "wb"), 1))
}

func (surface *Surface) SetRLE(flag int) int {
	_surface := (*C.SDL_Surface) (unsafe.Pointer(surface))
	_flag := (C.int) (flag)
	return (int) (C.SDL_SetSurfaceRLE(_surface, _flag))
}

func (surface *Surface) SetColorKey(flag int, key uint32) int {
	_surface := (*C.SDL_Surface) (unsafe.Pointer(surface))
	_flag := (C.int) (flag)
	_key := (C.Uint32) (key)
	return (int) (C.SDL_SetColorKey(_surface, _flag, _key))
}

func (surface *Surface) GetColorKey(key *uint32) int {
	_surface := (*C.SDL_Surface) (unsafe.Pointer(surface))
	_key := (*C.Uint32) (unsafe.Pointer(key))
	return (int) (C.SDL_GetColorKey(_surface, _key))
}

func (surface *Surface) SetColorMod(r, g, b uint8) int {
	_surface := (*C.SDL_Surface) (unsafe.Pointer(surface))
	_r := (C.Uint8) (r)
	_g := (C.Uint8) (g)
	_b := (C.Uint8) (b)
	return (int) (C.SDL_SetSurfaceColorMod(_surface, _r, _g, _b))
}

func (surface *Surface) GetColorMod(r, g, b *uint8) int {
	_surface := (*C.SDL_Surface) (unsafe.Pointer(surface))
	_r := (*C.Uint8) (unsafe.Pointer(r))
	_g := (*C.Uint8) (unsafe.Pointer(g))
	_b := (*C.Uint8) (unsafe.Pointer(b))
	return (int) (C.SDL_GetSurfaceColorMod(_surface, _r, _g, _b))
}

func (surface *Surface) SetAlphaMod(alpha uint8) int {
	_surface := (*C.SDL_Surface) (unsafe.Pointer(surface))
	_alpha := (C.Uint8) (alpha)
	return (int) (C.SDL_SetSurfaceAlphaMod(_surface, _alpha))
}

func (surface *Surface) GetAlphaMod(alpha *uint8) int {
	_surface := (*C.SDL_Surface) (unsafe.Pointer(surface))
	_alpha := (*C.Uint8) (unsafe.Pointer(alpha))
	return (int) (C.SDL_GetSurfaceAlphaMod(_surface, _alpha))
}

func (surface *Surface) SetBlendMode(blendMode BlendMode) int {
	_surface := (*C.SDL_Surface) (unsafe.Pointer(surface))
	_blendMode := (C.SDL_BlendMode) (blendMode)
	return (int) (C.SDL_SetSurfaceBlendMode(_surface, _blendMode))
}

func (surface *Surface) GetBlendMode(blendMode *BlendMode) int {
	_surface := (*C.SDL_Surface) (unsafe.Pointer(surface))
	_blendMode := (*C.SDL_BlendMode) (unsafe.Pointer(blendMode))
	return (int) (C.SDL_GetSurfaceBlendMode(_surface, _blendMode))
}

func (surface *Surface) SetClipRect(rect *Rect) bool {
	_surface := (*C.SDL_Surface) (unsafe.Pointer(surface))
	_rect := (*C.SDL_Rect) (unsafe.Pointer(rect))
	return C.SDL_SetClipRect(_surface, _rect) > 0
}

func (surface *Surface) GetClipRect(rect *Rect) {
	_surface := (*C.SDL_Surface) (unsafe.Pointer(surface))
	_rect := (*C.SDL_Rect) (unsafe.Pointer(rect))
	C.SDL_GetClipRect(_surface, _rect)
}

func (surface *Surface) Convert(fmt *PixelFormat, flags uint32) *Surface {
	_surface := (*C.SDL_Surface) (unsafe.Pointer(surface))
	_fmt := (*C.SDL_PixelFormat) (unsafe.Pointer(fmt))
	_flags := (C.Uint32) (flags)
	_surface = C.SDL_ConvertSurface(_surface, _fmt, _flags)
	return (*Surface) (unsafe.Pointer(_surface))
}

func (surface *Surface) ConvertFormat(pixel_format uint32, flags uint32) *Surface {
	_surface := (*C.SDL_Surface) (unsafe.Pointer(surface))
	_pixel_format := (C.Uint32) (pixel_format)
	_flags := (C.Uint32) (flags)
	return (*Surface) (unsafe.Pointer(C.SDL_ConvertSurfaceFormat(_surface, _pixel_format, _flags)))
}

func ConvertPixels(width, height int, src_format uint32, src unsafe.Pointer, src_pitch int,
		dst_format uint32, dst unsafe.Pointer, dst_pitch int) int {
	_width := (C.int) (width)
	_height := (C.int) (height)
	_src_format := (C.Uint32) (src_format)
	_src_pitch := (C.int) (src_pitch)
	_dst_format := (C.Uint32) (dst_format)
	_dst_pitch := (C.int) (dst_pitch)
	return (int) (C.SDL_ConvertPixels(_width, _height, _src_format, src, _src_pitch, _dst_format, dst, _dst_pitch))
}

func (surface *Surface) FillRect(rect *Rect, color uint32) int {
	_surface := (*C.SDL_Surface) (unsafe.Pointer(surface))
	_rect := (*C.SDL_Rect) (unsafe.Pointer(rect))
	_color := (C.Uint32) (color)
	return (int) (C.SDL_FillRect(_surface, _rect, _color))
}

func (surface *Surface) FillRects(rects *Rect, count int, color uint32) int {
	_surface := (*C.SDL_Surface) (unsafe.Pointer(surface))
	_rects := (*C.SDL_Rect) (unsafe.Pointer(rects))
	_count := (C.int) (count)
	_color := (C.Uint32) (color)
	return (int) (C.SDL_FillRects(_surface, _rects, _count, _color))
}

func (src *Surface) Blit(srcrect *Rect, dst *Surface, dstrect *Rect) int {
	_src := (*C.SDL_Surface) (unsafe.Pointer(src))
	_srcrect := (*C.SDL_Rect) (unsafe.Pointer(srcrect))
	_dst := (*C.SDL_Surface) (unsafe.Pointer(dst))
	_dstrect := (*C.SDL_Rect) (unsafe.Pointer(dstrect))
	return (int) (C.SDL_BlitSurface(_src, _srcrect, _dst, _dstrect))
}

func (src *Surface) BlitScaled(srcrect *Rect, dst *Surface, dstrect *Rect) int {
	_src := (*C.SDL_Surface) (unsafe.Pointer(src))
	_srcrect := (*C.SDL_Rect) (unsafe.Pointer(srcrect))
	_dst := (*C.SDL_Surface) (unsafe.Pointer(dst))
	_dstrect := (*C.SDL_Rect) (unsafe.Pointer(dstrect))
	return (int) (C.SDL_BlitScaled(_src, _srcrect, _dst, _dstrect))
}

func (src *Surface) UpperBlit(srcrect *Rect, dst *Surface, dstrect *Rect) int {
	_src := (*C.SDL_Surface) (unsafe.Pointer(src))
	_srcrect := (*C.SDL_Rect) (unsafe.Pointer(srcrect))
	_dst := (*C.SDL_Surface) (unsafe.Pointer(dst))
	_dstrect := (*C.SDL_Rect) (unsafe.Pointer(dstrect))
	return (int) (C.SDL_UpperBlit(_src, _srcrect, _dst, _dstrect))
}

func (src *Surface) LowerBlit(srcrect *Rect, dst *Surface, dstrect *Rect) int {
	_src := (*C.SDL_Surface) (unsafe.Pointer(src))
	_srcrect := (*C.SDL_Rect) (unsafe.Pointer(srcrect))
	_dst := (*C.SDL_Surface) (unsafe.Pointer(dst))
	_dstrect := (*C.SDL_Rect) (unsafe.Pointer(dstrect))
	return (int) (C.SDL_LowerBlit(_src, _srcrect, _dst, _dstrect))
}

func (src *Surface) SoftStretch(srcrect *Rect, dst *Surface, dstrect *Rect) int {
	_src := (*C.SDL_Surface) (unsafe.Pointer(src))
	_srcrect := (*C.SDL_Rect) (unsafe.Pointer(srcrect))
	_dst := (*C.SDL_Surface) (unsafe.Pointer(dst))
	_dstrect := (*C.SDL_Rect) (unsafe.Pointer(dstrect))
	return (int) (C.SDL_SoftStretch(_src, _srcrect, _dst, _dstrect))
}

func (src *Surface) UpperBlitScaled(srcrect *Rect, dst *Surface, dstrect *Rect) int {
	_src := (*C.SDL_Surface) (unsafe.Pointer(src))
	_srcrect := (*C.SDL_Rect) (unsafe.Pointer(srcrect))
	_dst := (*C.SDL_Surface) (unsafe.Pointer(dst))
	_dstrect := (*C.SDL_Rect) (unsafe.Pointer(dstrect))
	return (int) (C.SDL_UpperBlitScaled(_src, _srcrect, _dst, _dstrect))
}

func (src *Surface) LowerBlitScaled(srcrect *Rect, dst *Surface, dstrect *Rect) int {
	_src := (*C.SDL_Surface) (unsafe.Pointer(src))
	_srcrect := (*C.SDL_Rect) (unsafe.Pointer(srcrect))
	_dst := (*C.SDL_Surface) (unsafe.Pointer(dst))
	_dstrect := (*C.SDL_Rect) (unsafe.Pointer(dstrect))
	return (int) (C.SDL_LowerBlitScaled(_src, _srcrect, _dst, _dstrect))
}

func (surface *Surface) PixelNum() int {
	return int(surface.W * surface.H)
}

func (surface *Surface) PixelSize() int {
	return int(surface.Format.BytesPerPixel)
}

func (surface *Surface) Pixels() []byte {
	var b []byte
	length := int(surface.W * surface.H) * int(surface.Format.BytesPerPixel)
	sliceHeader := (*reflect.SliceHeader)(unsafe.Pointer(&b))
	sliceHeader.Cap = int(length)
	sliceHeader.Len = int(length)
	sliceHeader.Data = uintptr(surface.pixels)
	return b
}
<commit_msg>Added method to access surface pixel data<commit_after>package sdl

/*
#include <SDL2/SDL_surface.h>
*/
import "C"
import "unsafe"
import "reflect"

const (
	SWSURFACE	= 0
	PREALLOC	= 0x00000001
	RLEACCEL	= 0x00000002
	DONTFREE	= 0x00000004
)

type Surface struct {
	Flags uint32
	Format *PixelFormat
	W int32
	H int32
	Pitch int
	pixels unsafe.Pointer // use Pixels() for access
	UserData unsafe.Pointer
	Locked int
	LockData unsafe.Pointer
	ClipRect Rect
	_map *[0]byte
	RefCount int
}

type blit C.SDL_blit

func (surface *Surface) MustLock() bool {
	return (surface.Flags & RLEACCEL) != 0
}

func CreateRGBSurface(flags uint32, width, height, depth int32,
		Rmask, Gmask, Bmask, Amask uint32) *Surface {
	_flags := (C.Uint32) (flags)
	_width := (C.int) (width)
	_height := (C.int) (height)
	_depth := (C.int) (depth)
	_Rmask := (C.Uint32) (Rmask)
	_Gmask := (C.Uint32) (Gmask)
	_Bmask := (C.Uint32) (Bmask)
	_Amask := (C.Uint32) (Amask)
	return (*Surface) (unsafe.Pointer(C.SDL_CreateRGBSurface(_flags, _width, _height,
				_depth, _Rmask, _Gmask, _Bmask, _Amask)))
}

func CreateRGBSurfaceFrom(pixels unsafe.Pointer, width, height, depth, pitch int32,
		Rmask, Gmask, Bmask, Amask uint32) *Surface {
	_width := (C.int) (width)
	_height := (C.int) (height)
	_depth := (C.int) (depth)
	_pitch := (C.int) (pitch)
	_Rmask := (C.Uint32) (Rmask)
	_Gmask := (C.Uint32) (Gmask)
	_Bmask := (C.Uint32) (Bmask)
	_Amask := (C.Uint32) (Amask)
	return (*Surface) (unsafe.Pointer(C.SDL_CreateRGBSurfaceFrom(pixels, _width, _height,
				_depth, _pitch, _Rmask, _Gmask, _Bmask, _Amask)))
}

func (surface *Surface) Free() {
	_surface := (*C.SDL_Surface) (unsafe.Pointer(surface))
	C.SDL_FreeSurface(_surface)
}

func (surface *Surface) SetPalette(palette *Palette) int {
	_surface := (*C.SDL_Surface) (unsafe.Pointer(surface))
	_palette := (*C.SDL_Palette) (unsafe.Pointer(palette))
	return (int) (C.SDL_SetSurfacePalette(_surface, _palette))
}

func (surface *Surface) Lock() {
	_surface := (*C.SDL_Surface) (unsafe.Pointer(surface))
	C.SDL_LockSurface(_surface)
}

func (surface *Surface) Unlock() {
	_surface := (*C.SDL_Surface) (unsafe.Pointer(surface))
	C.SDL_UnlockSurface(_surface)
}

func LoadBMP_RW(src *RWops, freesrc int) *Surface {
	_src := (*C.SDL_RWops) (unsafe.Pointer(src))
	_freesrc := (C.int) (freesrc)
	_surface := C.SDL_LoadBMP_RW(_src, _freesrc)
	return (*Surface) (unsafe.Pointer(_surface))
}

func LoadBMP(file string) *Surface {
	return (*Surface) (LoadBMP_RW(RWFromFile(file, "rb"), 1))
}

func (surface *Surface) SaveBMP_RW(dst *RWops, freedst int) int {
	_surface := (*C.SDL_Surface) (unsafe.Pointer(surface))
	_dst := (*C.SDL_RWops) (unsafe.Pointer(dst))
	_freedst := (C.int) (freedst)
	return (int) (C.SDL_SaveBMP_RW(_surface, _dst, _freedst))
}

func (surface *Surface) SaveBMP(file string) int {
	return (int) (surface.SaveBMP_RW(RWFromFile(file, "wb"), 1))
}

func (surface *Surface) SetRLE(flag int) int {
	_surface := (*C.SDL_Surface) (unsafe.Pointer(surface))
	_flag := (C.int) (flag)
	return (int) (C.SDL_SetSurfaceRLE(_surface, _flag))
}

func (surface *Surface) SetColorKey(flag int, key uint32) int {
	_surface := (*C.SDL_Surface) (unsafe.Pointer(surface))
	_flag := (C.int) (flag)
	_key := (C.Uint32) (key)
	return (int) (C.SDL_SetColorKey(_surface, _flag, _key))
}

func (surface *Surface) GetColorKey(key *uint32) int {
	_surface := (*C.SDL_Surface) (unsafe.Pointer(surface))
	_key := (*C.Uint32) (unsafe.Pointer(key))
	return (int) (C.SDL_GetColorKey(_surface, _key))
}

func (surface *Surface) SetColorMod(r, g, b uint8) int {
	_surface := (*C.SDL_Surface) (unsafe.Pointer(surface))
	_r := (C.Uint8) (r)
	_g := (C.Uint8) (g)
	_b := (C.Uint8) (b)
	return (int) (C.SDL_SetSurfaceColorMod(_surface, _r, _g, _b))
}

func (surface *Surface) GetColorMod(r, g, b *uint8) int {
	_surface := (*C.SDL_Surface) (unsafe.Pointer(surface))
	_r := (*C.Uint8) (unsafe.Pointer(r))
	_g := (*C.Uint8) (unsafe.Pointer(g))
	_b := (*C.Uint8) (unsafe.Pointer(b))
	return (int) (C.SDL_GetSurfaceColorMod(_surface, _r, _g, _b))
}

func (surface *Surface) SetAlphaMod(alpha uint8) int {
	_surface := (*C.SDL_Surface) (unsafe.Pointer(surface))
	_alpha := (C.Uint8) (alpha)
	return (int) (C.SDL_SetSurfaceAlphaMod(_surface, _alpha))
}

func (surface *Surface) GetAlphaMod(alpha *uint8) int {
	_surface := (*C.SDL_Surface) (unsafe.Pointer(surface))
	_alpha := (*C.Uint8) (unsafe.Pointer(alpha))
	return (int) (C.SDL_GetSurfaceAlphaMod(_surface, _alpha))
}

func (surface *Surface) SetBlendMode(blendMode BlendMode) int {
	_surface := (*C.SDL_Surface) (unsafe.Pointer(surface))
	_blendMode := (C.SDL_BlendMode) (blendMode)
	return (int) (C.SDL_SetSurfaceBlendMode(_surface, _blendMode))
}

func (surface *Surface) GetBlendMode(blendMode *BlendMode) int {
	_surface := (*C.SDL_Surface) (unsafe.Pointer(surface))
	_blendMode := (*C.SDL_BlendMode) (unsafe.Pointer(blendMode))
	return (int) (C.SDL_GetSurfaceBlendMode(_surface, _blendMode))
}

func (surface *Surface) SetClipRect(rect *Rect) bool {
	_surface := (*C.SDL_Surface) (unsafe.Pointer(surface))
	_rect := (*C.SDL_Rect) (unsafe.Pointer(rect))
	return C.SDL_SetClipRect(_surface, _rect) > 0
}

func (surface *Surface) GetClipRect(rect *Rect) {
	_surface := (*C.SDL_Surface) (unsafe.Pointer(surface))
	_rect := (*C.SDL_Rect) (unsafe.Pointer(rect))
	C.SDL_GetClipRect(_surface, _rect)
}

func (surface *Surface) Convert(fmt *PixelFormat, flags uint32) *Surface {
	_surface := (*C.SDL_Surface) (unsafe.Pointer(surface))
	_fmt := (*C.SDL_PixelFormat) (unsafe.Pointer(fmt))
	_flags := (C.Uint32) (flags)
	_surface = C.SDL_ConvertSurface(_surface, _fmt, _flags)
	return (*Surface) (unsafe.Pointer(_surface))
}

func (surface *Surface) ConvertFormat(pixel_format uint32, flags uint32) *Surface {
	_surface := (*C.SDL_Surface) (unsafe.Pointer(surface))
	_pixel_format := (C.Uint32) (pixel_format)
	_flags := (C.Uint32) (flags)
	return (*Surface) (unsafe.Pointer(C.SDL_ConvertSurfaceFormat(_surface, _pixel_format, _flags)))
}

func ConvertPixels(width, height int, src_format uint32, src unsafe.Pointer, src_pitch int,
		dst_format uint32, dst unsafe.Pointer, dst_pitch int) int {
	_width := (C.int) (width)
	_height := (C.int) (height)
	_src_format := (C.Uint32) (src_format)
	_src_pitch := (C.int) (src_pitch)
	_dst_format := (C.Uint32) (dst_format)
	_dst_pitch := (C.int) (dst_pitch)
	return (int) (C.SDL_ConvertPixels(_width, _height, _src_format, src, _src_pitch, _dst_format, dst, _dst_pitch))
}

func (surface *Surface) FillRect(rect *Rect, color uint32) int {
	_surface := (*C.SDL_Surface) (unsafe.Pointer(surface))
	_rect := (*C.SDL_Rect) (unsafe.Pointer(rect))
	_color := (C.Uint32) (color)
	return (int) (C.SDL_FillRect(_surface, _rect, _color))
}

func (surface *Surface) FillRects(rects *Rect, count int, color uint32) int {
	_surface := (*C.SDL_Surface) (unsafe.Pointer(surface))
	_rects := (*C.SDL_Rect) (unsafe.Pointer(rects))
	_count := (C.int) (count)
	_color := (C.Uint32) (color)
	return (int) (C.SDL_FillRects(_surface, _rects, _count, _color))
}

func (src *Surface) Blit(srcrect *Rect, dst *Surface, dstrect *Rect) int {
	_src := (*C.SDL_Surface) (unsafe.Pointer(src))
	_srcrect := (*C.SDL_Rect) (unsafe.Pointer(srcrect))
	_dst := (*C.SDL_Surface) (unsafe.Pointer(dst))
	_dstrect := (*C.SDL_Rect) (unsafe.Pointer(dstrect))
	return (int) (C.SDL_BlitSurface(_src, _srcrect, _dst, _dstrect))
}

func (src *Surface) BlitScaled(srcrect *Rect, dst *Surface, dstrect *Rect) int {
	_src := (*C.SDL_Surface) (unsafe.Pointer(src))
	_srcrect := (*C.SDL_Rect) (unsafe.Pointer(srcrect))
	_dst := (*C.SDL_Surface) (unsafe.Pointer(dst))
	_dstrect := (*C.SDL_Rect) (unsafe.Pointer(dstrect))
	return (int) (C.SDL_BlitScaled(_src, _srcrect, _dst, _dstrect))
}

func (src *Surface) UpperBlit(srcrect *Rect, dst *Surface, dstrect *Rect) int {
	_src := (*C.SDL_Surface) (unsafe.Pointer(src))
	_srcrect := (*C.SDL_Rect) (unsafe.Pointer(srcrect))
	_dst := (*C.SDL_Surface) (unsafe.Pointer(dst))
	_dstrect := (*C.SDL_Rect) (unsafe.Pointer(dstrect))
	return (int) (C.SDL_UpperBlit(_src, _srcrect, _dst, _dstrect))
}

func (src *Surface) LowerBlit(srcrect *Rect, dst *Surface, dstrect *Rect) int {
	_src := (*C.SDL_Surface) (unsafe.Pointer(src))
	_srcrect := (*C.SDL_Rect) (unsafe.Pointer(srcrect))
	_dst := (*C.SDL_Surface) (unsafe.Pointer(dst))
	_dstrect := (*C.SDL_Rect) (unsafe.Pointer(dstrect))
	return (int) (C.SDL_LowerBlit(_src, _srcrect, _dst, _dstrect))
}

func (src *Surface) SoftStretch(srcrect *Rect, dst *Surface, dstrect *Rect) int {
	_src := (*C.SDL_Surface) (unsafe.Pointer(src))
	_srcrect := (*C.SDL_Rect) (unsafe.Pointer(srcrect))
	_dst := (*C.SDL_Surface) (unsafe.Pointer(dst))
	_dstrect := (*C.SDL_Rect) (unsafe.Pointer(dstrect))
	return (int) (C.SDL_SoftStretch(_src, _srcrect, _dst, _dstrect))
}

func (src *Surface) UpperBlitScaled(srcrect *Rect, dst *Surface, dstrect *Rect) int {
	_src := (*C.SDL_Surface) (unsafe.Pointer(src))
	_srcrect := (*C.SDL_Rect) (unsafe.Pointer(srcrect))
	_dst := (*C.SDL_Surface) (unsafe.Pointer(dst))
	_dstrect := (*C.SDL_Rect) (unsafe.Pointer(dstrect))
	return (int) (C.SDL_UpperBlitScaled(_src, _srcrect, _dst, _dstrect))
}

func (src *Surface) LowerBlitScaled(srcrect *Rect, dst *Surface, dstrect *Rect) int {
	_src := (*C.SDL_Surface) (unsafe.Pointer(src))
	_srcrect := (*C.SDL_Rect) (unsafe.Pointer(srcrect))
	_dst := (*C.SDL_Surface) (unsafe.Pointer(dst))
	_dstrect := (*C.SDL_Rect) (unsafe.Pointer(dstrect))
	return (int) (C.SDL_LowerBlitScaled(_src, _srcrect, _dst, _dstrect))
}

func (surface *Surface) PixelNum() int {
	return int(surface.W * surface.H)
}

func (surface *Surface) PixelSize() int {
	return int(surface.Format.BytesPerPixel)
}

func (surface *Surface) Pixels() []byte {
	var b []byte
	length := int(surface.W * surface.H) * int(surface.Format.BytesPerPixel)
	sliceHeader := (*reflect.SliceHeader)(unsafe.Pointer(&b))
	sliceHeader.Cap = int(length)
	sliceHeader.Len = int(length)
	sliceHeader.Data = uintptr(surface.pixels)
	return b
}

func (surface *Surface) Data() unsafe.Pointer {
	return surface.pixels
}
<|endoftext|>


<commit_before>package ttf

//#cgo windows LDFLAGS: -lSDL2 -lSDL2_ttf
//#cgo darwin LDFLAGS: -framework SDL2 -framework SDL2_ttf
//#cgo linux freebsd pkg-config: sdl2
//#cgo linux freebsd LDFLAGS: -lSDL2_ttf
//#include <stdlib.h>
//#if defined(__APPLE__)
//#include <SDL2_ttf/SDL_ttf.h>
//#else
//#include <SDL2/SDL_ttf.h>
//#endif
//void Do_TTF_SetError(const char *str) {
//    TTF_SetError(str);
//}
import "C"
import "github.com/veandco/go-sdl2/sdl"
import "unsafe"
import "errors"

//Font Hinting Types
const (
	HINTING_NORMAL = int(C.TTF_HINTING_NORMAL)
	HINTING_LIGHT  = int(C.TTF_HINTING_LIGHT)
	HINTING_MONO   = int(C.TTF_HINTING_MONO)
	HINTING_NONE   = int(C.TTF_HINTING_NONE)
)

//Font Style Types
const (
	STYLE_NORMAL        = 0
	STYLE_BOLD          = 0x01
	STYLE_ITALIC        = 0x02
	STYLE_UNDERLINE     = 0x04
	STYLE_STRIKETHROUGH = 0x08
)

type Font struct {
	f *C.TTF_Font
}

func Init() int {
	return int(C.TTF_Init())
}

func WasInit() bool {
	return int(C.TTF_WasInit()) != 0
}

func Quit() {
	C.TTF_Quit()
}

func GetError() error {
	e := C.TTF_GetError()
	if e == nil {
		return nil
	}
	return errors.New(C.GoString(e))
}

func SetError(err string) {
	_err := C.CString(err)
	defer C.free(unsafe.Pointer(_err))
	C.Do_TTF_SetError(_err)
}

func ByteSwappedUnicode(swap bool) {
	val := 0
	if swap {
		val = 1
	}
	C.TTF_ByteSwappedUNICODE(C.int(val))
}

func OpenFont(file string, size int) (*Font, error) {
	_file := C.CString(file)
	defer C.free(unsafe.Pointer(_file))
	_size := (C.int)(size)
	f := (*C.TTF_Font)(C.TTF_OpenFont(_file, _size))

	if f == nil {
		return nil, GetError()
	}
	return &Font{f}, nil
}

func OpenFontIndex(file string, size int, index int) (*Font, error) {
	_file := C.CString(file)
	defer C.free(unsafe.Pointer(_file))
	_size := (C.int)(size)
	_index := (C.long)(index)
	f := (*C.TTF_Font)(C.TTF_OpenFontIndex(_file, _size, _index))

	if f == nil {
		return nil, GetError()
	}
	return &Font{f}, nil
}

func (f *Font) RenderText_Solid(text string, color sdl.Color) *sdl.Surface {
	_text := C.CString(text)
	defer C.free(unsafe.Pointer(_text))
	_c := C.SDL_Color{C.Uint8(color.R), C.Uint8(color.G), C.Uint8(color.B), C.Uint8(color.A)}
	surface := (*sdl.Surface)(unsafe.Pointer(C.TTF_RenderText_Solid(f.f, _text, _c)))
	return surface
}

func (f *Font) RenderText_Shaded(text string, fg, bg sdl.Color) *sdl.Surface {
	_text := C.CString(text)
	defer C.free(unsafe.Pointer(_text))
	_fg := C.SDL_Color{C.Uint8(fg.R), C.Uint8(fg.G), C.Uint8(fg.B), C.Uint8(fg.A)}
	_bg := C.SDL_Color{C.Uint8(bg.R), C.Uint8(bg.G), C.Uint8(bg.B), C.Uint8(bg.A)}
	surface := (*sdl.Surface)(unsafe.Pointer(C.TTF_RenderText_Shaded(f.f, _text, _fg, _bg)))
	return surface
}

func (f *Font) RenderText_Blended(text string, color sdl.Color) *sdl.Surface {
	_text := C.CString(text)
	defer C.free(unsafe.Pointer(_text))
	_c := C.SDL_Color{C.Uint8(color.R), C.Uint8(color.G), C.Uint8(color.B), C.Uint8(color.A)}
	surface := (*sdl.Surface)(unsafe.Pointer(C.TTF_RenderText_Blended(f.f, _text, _c)))
	return surface
}

func (f *Font) Close() {
	C.TTF_CloseFont(f.f)
	f.f = nil
}

func (f *Font) Height() int   { return int(C.TTF_FontHeight(f.f)) }
func (f *Font) Ascent() int   { return int(C.TTF_FontAscent(f.f)) }
func (f *Font) Descent() int  { return int(C.TTF_FontDescent(f.f)) }
func (f *Font) LineSkip() int { return int(C.TTF_FontLineSkip(f.f)) }
func (f *Font) Faces() int    { return int(C.TTF_FontFaces(f.f)) }

func (f *Font) GetStyle() int {
	return int(C.TTF_GetFontStyle(f.f))
}

func (f *Font) SetStyle(style int) {
	C.TTF_SetFontStyle(f.f, C.int(style))
}

func (f *Font) GetHinting() int {
	return int(C.TTF_GetFontHinting(f.f))
}

func (f *Font) SetHinting(hinting int) {
	C.TTF_SetFontHinting(f.f, C.int(hinting))
}

func (f *Font) GetKerning() bool {
	return int(C.TTF_GetFontKerning(f.f)) == 1
}

func (f *Font) SetKerning(allowed bool) {
	val := 0
	if allowed {
		val = 1
	}
	C.TTF_SetFontKerning(f.f, C.int(val))
}

func (f *Font) GetOutline() int {
	return int(C.TTF_GetFontOutline(f.f))
}

func (f *Font) SetOutline(outline int) {
	C.TTF_SetFontOutline(f.f, C.int(outline))
}

func (f *Font) FaceIsFixedWidth() bool {
	return int(C.TTF_FontFaceIsFixedWidth(f.f)) != 0
}

func (f *Font) FaceFamilyName() string {
	_fname := C.TTF_FontFaceFamilyName(f.f)
	fname := C.GoString(_fname)
	C.free(unsafe.Pointer(_fname))
	return fname
}
<commit_msg>Fixed CFLAG and LDFLAG refs for OSX Macports install of SDL2_ttf<commit_after>package ttf

//#cgo darwin CFLAGS: -I/opt/local/include/
//#cgo windows LDFLAGS: -lSDL2 -lSDL2_ttf
//#cgo darwin LDFLAGS: -L/opt/local/lib/ -lSDL2 -lSDL2_ttf
//#cgo linux freebsd pkg-config: sdl2
//#cgo linux freebsd LDFLAGS: -lSDL2_ttf
//#include <stdlib.h>
//#include <SDL2/SDL_ttf.h>
//void Do_TTF_SetError(const char *str) {
//    TTF_SetError(str);
//}
import "C"
import "github.com/veandco/go-sdl2/sdl"
import "unsafe"
import "errors"

//Font Hinting Types
const (
	HINTING_NORMAL = int(C.TTF_HINTING_NORMAL)
	HINTING_LIGHT  = int(C.TTF_HINTING_LIGHT)
	HINTING_MONO   = int(C.TTF_HINTING_MONO)
	HINTING_NONE   = int(C.TTF_HINTING_NONE)
)

//Font Style Types
const (
	STYLE_NORMAL        = 0
	STYLE_BOLD          = 0x01
	STYLE_ITALIC        = 0x02
	STYLE_UNDERLINE     = 0x04
	STYLE_STRIKETHROUGH = 0x08
)

type Font struct {
	f *C.TTF_Font
}

func Init() int {
	return int(C.TTF_Init())
}

func WasInit() bool {
	return int(C.TTF_WasInit()) != 0
}

func Quit() {
	C.TTF_Quit()
}

func GetError() error {
	e := C.TTF_GetError()
	if e == nil {
		return nil
	}
	return errors.New(C.GoString(e))
}

func SetError(err string) {
	_err := C.CString(err)
	defer C.free(unsafe.Pointer(_err))
	C.Do_TTF_SetError(_err)
}

func ByteSwappedUnicode(swap bool) {
	val := 0
	if swap {
		val = 1
	}
	C.TTF_ByteSwappedUNICODE(C.int(val))
}

func OpenFont(file string, size int) (*Font, error) {
	_file := C.CString(file)
	defer C.free(unsafe.Pointer(_file))
	_size := (C.int)(size)
	f := (*C.TTF_Font)(C.TTF_OpenFont(_file, _size))

	if f == nil {
		return nil, GetError()
	}
	return &Font{f}, nil
}

func OpenFontIndex(file string, size int, index int) (*Font, error) {
	_file := C.CString(file)
	defer C.free(unsafe.Pointer(_file))
	_size := (C.int)(size)
	_index := (C.long)(index)
	f := (*C.TTF_Font)(C.TTF_OpenFontIndex(_file, _size, _index))

	if f == nil {
		return nil, GetError()
	}
	return &Font{f}, nil
}

func (f *Font) RenderText_Solid(text string, color sdl.Color) *sdl.Surface {
	_text := C.CString(text)
	defer C.free(unsafe.Pointer(_text))
	_c := C.SDL_Color{C.Uint8(color.R), C.Uint8(color.G), C.Uint8(color.B), C.Uint8(color.A)}
	surface := (*sdl.Surface)(unsafe.Pointer(C.TTF_RenderText_Solid(f.f, _text, _c)))
	return surface
}

func (f *Font) RenderText_Shaded(text string, fg, bg sdl.Color) *sdl.Surface {
	_text := C.CString(text)
	defer C.free(unsafe.Pointer(_text))
	_fg := C.SDL_Color{C.Uint8(fg.R), C.Uint8(fg.G), C.Uint8(fg.B), C.Uint8(fg.A)}
	_bg := C.SDL_Color{C.Uint8(bg.R), C.Uint8(bg.G), C.Uint8(bg.B), C.Uint8(bg.A)}
	surface := (*sdl.Surface)(unsafe.Pointer(C.TTF_RenderText_Shaded(f.f, _text, _fg, _bg)))
	return surface
}

func (f *Font) RenderText_Blended(text string, color sdl.Color) *sdl.Surface {
	_text := C.CString(text)
	defer C.free(unsafe.Pointer(_text))
	_c := C.SDL_Color{C.Uint8(color.R), C.Uint8(color.G), C.Uint8(color.B), C.Uint8(color.A)}
	surface := (*sdl.Surface)(unsafe.Pointer(C.TTF_RenderText_Blended(f.f, _text, _c)))
	return surface
}

func (f *Font) Close() {
	C.TTF_CloseFont(f.f)
	f.f = nil
}

func (f *Font) Height() int   { return int(C.TTF_FontHeight(f.f)) }
func (f *Font) Ascent() int   { return int(C.TTF_FontAscent(f.f)) }
func (f *Font) Descent() int  { return int(C.TTF_FontDescent(f.f)) }
func (f *Font) LineSkip() int { return int(C.TTF_FontLineSkip(f.f)) }
func (f *Font) Faces() int    { return int(C.TTF_FontFaces(f.f)) }

func (f *Font) GetStyle() int {
	return int(C.TTF_GetFontStyle(f.f))
}

func (f *Font) SetStyle(style int) {
	C.TTF_SetFontStyle(f.f, C.int(style))
}

func (f *Font) GetHinting() int {
	return int(C.TTF_GetFontHinting(f.f))
}

func (f *Font) SetHinting(hinting int) {
	C.TTF_SetFontHinting(f.f, C.int(hinting))
}

func (f *Font) GetKerning() bool {
	return int(C.TTF_GetFontKerning(f.f)) == 1
}

func (f *Font) SetKerning(allowed bool) {
	val := 0
	if allowed {
		val = 1
	}
	C.TTF_SetFontKerning(f.f, C.int(val))
}

func (f *Font) GetOutline() int {
	return int(C.TTF_GetFontOutline(f.f))
}

func (f *Font) SetOutline(outline int) {
	C.TTF_SetFontOutline(f.f, C.int(outline))
}

func (f *Font) FaceIsFixedWidth() bool {
	return int(C.TTF_FontFaceIsFixedWidth(f.f)) != 0
}

func (f *Font) FaceFamilyName() string {
	_fname := C.TTF_FontFaceFamilyName(f.f)
	fname := C.GoString(_fname)
	C.free(unsafe.Pointer(_fname))
	return fname
}
<|endoftext|>