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

package html

import (
	"exp/html/atom"
)

// A NodeType is the type of a Node.
type NodeType uint32

const (
	ErrorNode NodeType = iota
	TextNode
	DocumentNode
	ElementNode
	CommentNode
	DoctypeNode
	scopeMarkerNode
)

// Section 12.2.3.3 says "scope markers are inserted when entering applet
// elements, buttons, object elements, marquees, table cells, and table
// captions, and are used to prevent formatting from 'leaking'".
var scopeMarker = Node{Type: scopeMarkerNode}

// A Node consists of a NodeType and some Data (tag name for element nodes,
// content for text) and are part of a tree of Nodes. Element nodes may also
// have a Namespace and contain a slice of Attributes. Data is unescaped, so
// that it looks like "a<b" rather than "a<b". For element nodes, DataAtom
// is the atom for Data, or zero if Data is not a known tag name.
//
// An empty Namespace implies a "http://www.w3.org/1999/xhtml" namespace.
// Similarly, "math" is short for "http://www.w3.org/1998/Math/MathML", and
// "svg" is short for "http://www.w3.org/2000/svg".
type Node struct {
	Parent    *Node
	Child     []*Node
	Type      NodeType
	DataAtom  atom.Atom
	Data      string
	Namespace string
	Attr      []Attribute
}

// Add adds a node as a child of n.
// It will panic if the child's parent is not nil.
func (n *Node) Add(child *Node) {
	if child.Parent != nil {
		panic("html: Node.Add called for a child Node that already has a parent")
	}
	child.Parent = n
	n.Child = append(n.Child, child)
}

// Remove removes a node as a child of n.
// It will panic if the child's parent is not n.
func (n *Node) Remove(child *Node) {
	if child.Parent == n {
		child.Parent = nil
		for i, m := range n.Child {
			if m == child {
				copy(n.Child[i:], n.Child[i+1:])
				j := len(n.Child) - 1
				n.Child[j] = nil
				n.Child = n.Child[:j]
				return
			}
		}
	}
	panic("html: Node.Remove called for a non-child Node")
}

// reparentChildren reparents all of src's child nodes to dst.
func reparentChildren(dst, src *Node) {
	for _, n := range src.Child {
		if n.Parent != src {
			panic("html: nodes have an inconsistent parent/child relationship")
		}
		n.Parent = dst
	}
	dst.Child = append(dst.Child, src.Child...)
	src.Child = nil
}

// clone returns a new node with the same type, data and attributes.
// The clone has no parent and no children.
func (n *Node) clone() *Node {
	m := &Node{
		Type:     n.Type,
		DataAtom: n.DataAtom,
		Data:     n.Data,
		Attr:     make([]Attribute, len(n.Attr)),
	}
	copy(m.Attr, n.Attr)
	return m
}

// nodeStack is a stack of nodes.
type nodeStack []*Node

// pop pops the stack. It will panic if s is empty.
func (s *nodeStack) pop() *Node {
	i := len(*s)
	n := (*s)[i-1]
	*s = (*s)[:i-1]
	return n
}

// top returns the most recently pushed node, or nil if s is empty.
func (s *nodeStack) top() *Node {
	if i := len(*s); i > 0 {
		return (*s)[i-1]
	}
	return nil
}

// index returns the index of the top-most occurrence of n in the stack, or -1
// if n is not present.
func (s *nodeStack) index(n *Node) int {
	for i := len(*s) - 1; i >= 0; i-- {
		if (*s)[i] == n {
			return i
		}
	}
	return -1
}

// insert inserts a node at the given index.
func (s *nodeStack) insert(i int, n *Node) {
	(*s) = append(*s, nil)
	copy((*s)[i+1:], (*s)[i:])
	(*s)[i] = n
}

// remove removes a node from the stack. It is a no-op if n is not present.
func (s *nodeStack) remove(n *Node) {
	i := s.index(n)
	if i == -1 {
		return
	}
	copy((*s)[i:], (*s)[i+1:])
	j := len(*s) - 1
	(*s)[j] = nil
	*s = (*s)[:j]
}

// TODO(nigeltao): forTag no longer used. Should it be deleted?

// forTag returns the top-most element node with the given tag.
func (s *nodeStack) forTag(tag string) *Node {
	for i := len(*s) - 1; i >= 0; i-- {
		n := (*s)[i]
		if n.Type == ElementNode && n.Data == tag {
			return n
		}
	}
	return nil
}
<commit_msg>exp/html: remove unused forTag function.<commit_after>// Copyright 2011 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.

package html

import (
	"exp/html/atom"
)

// A NodeType is the type of a Node.
type NodeType uint32

const (
	ErrorNode NodeType = iota
	TextNode
	DocumentNode
	ElementNode
	CommentNode
	DoctypeNode
	scopeMarkerNode
)

// Section 12.2.3.3 says "scope markers are inserted when entering applet
// elements, buttons, object elements, marquees, table cells, and table
// captions, and are used to prevent formatting from 'leaking'".
var scopeMarker = Node{Type: scopeMarkerNode}

// A Node consists of a NodeType and some Data (tag name for element nodes,
// content for text) and are part of a tree of Nodes. Element nodes may also
// have a Namespace and contain a slice of Attributes. Data is unescaped, so
// that it looks like "a<b" rather than "a<b". For element nodes, DataAtom
// is the atom for Data, or zero if Data is not a known tag name.
//
// An empty Namespace implies a "http://www.w3.org/1999/xhtml" namespace.
// Similarly, "math" is short for "http://www.w3.org/1998/Math/MathML", and
// "svg" is short for "http://www.w3.org/2000/svg".
type Node struct {
	Parent    *Node
	Child     []*Node
	Type      NodeType
	DataAtom  atom.Atom
	Data      string
	Namespace string
	Attr      []Attribute
}

// Add adds a node as a child of n.
// It will panic if the child's parent is not nil.
func (n *Node) Add(child *Node) {
	if child.Parent != nil {
		panic("html: Node.Add called for a child Node that already has a parent")
	}
	child.Parent = n
	n.Child = append(n.Child, child)
}

// Remove removes a node as a child of n.
// It will panic if the child's parent is not n.
func (n *Node) Remove(child *Node) {
	if child.Parent == n {
		child.Parent = nil
		for i, m := range n.Child {
			if m == child {
				copy(n.Child[i:], n.Child[i+1:])
				j := len(n.Child) - 1
				n.Child[j] = nil
				n.Child = n.Child[:j]
				return
			}
		}
	}
	panic("html: Node.Remove called for a non-child Node")
}

// reparentChildren reparents all of src's child nodes to dst.
func reparentChildren(dst, src *Node) {
	for _, n := range src.Child {
		if n.Parent != src {
			panic("html: nodes have an inconsistent parent/child relationship")
		}
		n.Parent = dst
	}
	dst.Child = append(dst.Child, src.Child...)
	src.Child = nil
}

// clone returns a new node with the same type, data and attributes.
// The clone has no parent and no children.
func (n *Node) clone() *Node {
	m := &Node{
		Type:     n.Type,
		DataAtom: n.DataAtom,
		Data:     n.Data,
		Attr:     make([]Attribute, len(n.Attr)),
	}
	copy(m.Attr, n.Attr)
	return m
}

// nodeStack is a stack of nodes.
type nodeStack []*Node

// pop pops the stack. It will panic if s is empty.
func (s *nodeStack) pop() *Node {
	i := len(*s)
	n := (*s)[i-1]
	*s = (*s)[:i-1]
	return n
}

// top returns the most recently pushed node, or nil if s is empty.
func (s *nodeStack) top() *Node {
	if i := len(*s); i > 0 {
		return (*s)[i-1]
	}
	return nil
}

// index returns the index of the top-most occurrence of n in the stack, or -1
// if n is not present.
func (s *nodeStack) index(n *Node) int {
	for i := len(*s) - 1; i >= 0; i-- {
		if (*s)[i] == n {
			return i
		}
	}
	return -1
}

// insert inserts a node at the given index.
func (s *nodeStack) insert(i int, n *Node) {
	(*s) = append(*s, nil)
	copy((*s)[i+1:], (*s)[i:])
	(*s)[i] = n
}

// remove removes a node from the stack. It is a no-op if n is not present.
func (s *nodeStack) remove(n *Node) {
	i := s.index(n)
	if i == -1 {
		return
	}
	copy((*s)[i:], (*s)[i+1:])
	j := len(*s) - 1
	(*s)[j] = nil
	*s = (*s)[:j]
}
<|endoftext|>


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

package build

import (
	"errors"
	"fmt"
	"log"
	"os"
	"path/filepath"
	"runtime"
)

// Path is a validated list of Trees derived from $GOROOT and $GOPATH at init.
var Path []*Tree

// Tree describes a Go source tree, either $GOROOT or one from $GOPATH.
type Tree struct {
	Path   string
	Goroot bool
}

func newTree(p string) (*Tree, error) {
	if !filepath.IsAbs(p) {
		return nil, errors.New("must be absolute")
	}
	ep, err := filepath.EvalSymlinks(p)
	if err != nil {
		return nil, err
	}
	return &Tree{Path: ep}, nil
}

// SrcDir returns the tree's package source directory.
func (t *Tree) SrcDir() string {
	if t.Goroot {
		return filepath.Join(t.Path, "src", "pkg")
	}
	return filepath.Join(t.Path, "src")
}

// PkgDir returns the tree's package object directory.
func (t *Tree) PkgDir() string {
	goos, goarch := runtime.GOOS, runtime.GOARCH
	if e := os.Getenv("GOOS"); e != "" {
		goos = e
	}
	if e := os.Getenv("GOARCH"); e != "" {
		goarch = e
	}
	return filepath.Join(t.Path, "pkg", goos+"_"+goarch)
}

// BinDir returns the tree's binary executable directory.
func (t *Tree) BinDir() string {
	if t.Goroot {
		if gobin := os.Getenv("GOBIN"); gobin != "" {
			return filepath.Clean(gobin)
		}
	}
	return filepath.Join(t.Path, "bin")
}

// HasSrc returns whether the given package's
// source can be found inside this Tree.
func (t *Tree) HasSrc(pkg string) bool {
	fi, err := os.Stat(filepath.Join(t.SrcDir(), pkg))
	if err != nil {
		return false
	}
	return fi.IsDir()
}

// HasPkg returns whether the given package's
// object file can be found inside this Tree.
func (t *Tree) HasPkg(pkg string) bool {
	fi, err := os.Stat(filepath.Join(t.PkgDir(), pkg+".a"))
	if err != nil {
		return false
	}
	return !fi.IsDir()
	// TODO(adg): check object version is consistent
}

var (
	ErrNotFound     = errors.New("package could not be found locally")
	ErrTreeNotFound = errors.New("no valid GOROOT or GOPATH could be found")
)

// FindTree takes an import or filesystem path and returns the
// tree where the package source should be and the package import path.
func FindTree(path string) (tree *Tree, pkg string, err error) {
	if isLocalPath(path) {
		if path, err = filepath.Abs(path); err != nil {
			return
		}
		if path, err = filepath.EvalSymlinks(path); err != nil {
			return
		}
		for _, t := range Path {
			tpath := t.SrcDir() + string(filepath.Separator)
			if !filepath.HasPrefix(path, tpath) {
				continue
			}
			tree = t
			pkg = path[len(tpath):]
			return
		}
		err = fmt.Errorf("path %q not inside a GOPATH", path)
		return
	}
	tree = defaultTree
	pkg = path
	for _, t := range Path {
		if t.HasSrc(pkg) {
			tree = t
			return
		}
	}
	if tree == nil {
		err = ErrTreeNotFound
	} else {
		err = ErrNotFound
	}
	return
}

// isLocalPath returns whether the given path is local (/foo ./foo ../foo . ..)
// Windows paths that starts with drive letter (c:\foo c:foo) are considered local.
func isLocalPath(s string) bool {
	const sep = string(filepath.Separator)
	return s == "." || s == ".." ||
		filepath.HasPrefix(s, sep) ||
		filepath.HasPrefix(s, "."+sep) || filepath.HasPrefix(s, ".."+sep) ||
		filepath.VolumeName(s) != ""
}

var (
	// argument lists used by the build's gc and ld methods
	gcImportArgs []string
	ldImportArgs []string

	// default tree for remote packages
	defaultTree *Tree
)

// set up Path: parse and validate GOROOT and GOPATH variables
func init() {
	root := runtime.GOROOT()
	t, err := newTree(root)
	if err != nil {
		log.Printf("invalid GOROOT %q: %v", root, err)
	} else {
		t.Goroot = true
		Path = []*Tree{t}
	}

Loop:
	for _, p := range filepath.SplitList(os.Getenv("GOPATH")) {
		if p == "" {
			continue
		}
		t, err := newTree(p)
		if err != nil {
			log.Printf("invalid GOPATH %q: %v", p, err)
			continue
		}

		// Check for dupes.
		// TODO(alexbrainman): make this correct under windows (case insensitive).
		for _, t2 := range Path {
			if t2.Path != t.Path {
				continue
			}
			if t2.Goroot {
				log.Printf("GOPATH is the same as GOROOT: %q", t.Path)
			} else {
				log.Printf("duplicate GOPATH entry: %q", t.Path)
			}
			continue Loop
		}

		Path = append(Path, t)
		gcImportArgs = append(gcImportArgs, "-I", t.PkgDir())
		ldImportArgs = append(ldImportArgs, "-L", t.PkgDir())

		// select first GOPATH entry as default
		if defaultTree == nil {
			defaultTree = t
		}
	}

	// use GOROOT if no valid GOPATH specified
	if defaultTree == nil && len(Path) > 0 {
		defaultTree = Path[0]
	}
}
<commit_msg>go/build: no back slash in FindTree returned pkg name<commit_after>// Copyright 2011 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.

package build

import (
	"errors"
	"fmt"
	"log"
	"os"
	"path/filepath"
	"runtime"
)

// Path is a validated list of Trees derived from $GOROOT and $GOPATH at init.
var Path []*Tree

// Tree describes a Go source tree, either $GOROOT or one from $GOPATH.
type Tree struct {
	Path   string
	Goroot bool
}

func newTree(p string) (*Tree, error) {
	if !filepath.IsAbs(p) {
		return nil, errors.New("must be absolute")
	}
	ep, err := filepath.EvalSymlinks(p)
	if err != nil {
		return nil, err
	}
	return &Tree{Path: ep}, nil
}

// SrcDir returns the tree's package source directory.
func (t *Tree) SrcDir() string {
	if t.Goroot {
		return filepath.Join(t.Path, "src", "pkg")
	}
	return filepath.Join(t.Path, "src")
}

// PkgDir returns the tree's package object directory.
func (t *Tree) PkgDir() string {
	goos, goarch := runtime.GOOS, runtime.GOARCH
	if e := os.Getenv("GOOS"); e != "" {
		goos = e
	}
	if e := os.Getenv("GOARCH"); e != "" {
		goarch = e
	}
	return filepath.Join(t.Path, "pkg", goos+"_"+goarch)
}

// BinDir returns the tree's binary executable directory.
func (t *Tree) BinDir() string {
	if t.Goroot {
		if gobin := os.Getenv("GOBIN"); gobin != "" {
			return filepath.Clean(gobin)
		}
	}
	return filepath.Join(t.Path, "bin")
}

// HasSrc returns whether the given package's
// source can be found inside this Tree.
func (t *Tree) HasSrc(pkg string) bool {
	fi, err := os.Stat(filepath.Join(t.SrcDir(), pkg))
	if err != nil {
		return false
	}
	return fi.IsDir()
}

// HasPkg returns whether the given package's
// object file can be found inside this Tree.
func (t *Tree) HasPkg(pkg string) bool {
	fi, err := os.Stat(filepath.Join(t.PkgDir(), pkg+".a"))
	if err != nil {
		return false
	}
	return !fi.IsDir()
	// TODO(adg): check object version is consistent
}

var (
	ErrNotFound     = errors.New("package could not be found locally")
	ErrTreeNotFound = errors.New("no valid GOROOT or GOPATH could be found")
)

// FindTree takes an import or filesystem path and returns the
// tree where the package source should be and the package import path.
func FindTree(path string) (tree *Tree, pkg string, err error) {
	if isLocalPath(path) {
		if path, err = filepath.Abs(path); err != nil {
			return
		}
		if path, err = filepath.EvalSymlinks(path); err != nil {
			return
		}
		for _, t := range Path {
			tpath := t.SrcDir() + string(filepath.Separator)
			if !filepath.HasPrefix(path, tpath) {
				continue
			}
			tree = t
			pkg = filepath.ToSlash(path[len(tpath):])
			return
		}
		err = fmt.Errorf("path %q not inside a GOPATH", path)
		return
	}
	tree = defaultTree
	pkg = filepath.ToSlash(path)
	for _, t := range Path {
		if t.HasSrc(pkg) {
			tree = t
			return
		}
	}
	if tree == nil {
		err = ErrTreeNotFound
	} else {
		err = ErrNotFound
	}
	return
}

// isLocalPath returns whether the given path is local (/foo ./foo ../foo . ..)
// Windows paths that starts with drive letter (c:\foo c:foo) are considered local.
func isLocalPath(s string) bool {
	const sep = string(filepath.Separator)
	return s == "." || s == ".." ||
		filepath.HasPrefix(s, sep) ||
		filepath.HasPrefix(s, "."+sep) || filepath.HasPrefix(s, ".."+sep) ||
		filepath.VolumeName(s) != ""
}

var (
	// argument lists used by the build's gc and ld methods
	gcImportArgs []string
	ldImportArgs []string

	// default tree for remote packages
	defaultTree *Tree
)

// set up Path: parse and validate GOROOT and GOPATH variables
func init() {
	root := runtime.GOROOT()
	t, err := newTree(root)
	if err != nil {
		log.Printf("invalid GOROOT %q: %v", root, err)
	} else {
		t.Goroot = true
		Path = []*Tree{t}
	}

Loop:
	for _, p := range filepath.SplitList(os.Getenv("GOPATH")) {
		if p == "" {
			continue
		}
		t, err := newTree(p)
		if err != nil {
			log.Printf("invalid GOPATH %q: %v", p, err)
			continue
		}

		// Check for dupes.
		// TODO(alexbrainman): make this correct under windows (case insensitive).
		for _, t2 := range Path {
			if t2.Path != t.Path {
				continue
			}
			if t2.Goroot {
				log.Printf("GOPATH is the same as GOROOT: %q", t.Path)
			} else {
				log.Printf("duplicate GOPATH entry: %q", t.Path)
			}
			continue Loop
		}

		Path = append(Path, t)
		gcImportArgs = append(gcImportArgs, "-I", t.PkgDir())
		ldImportArgs = append(ldImportArgs, "-L", t.PkgDir())

		// select first GOPATH entry as default
		if defaultTree == nil {
			defaultTree = t
		}
	}

	// use GOROOT if no valid GOPATH specified
	if defaultTree == nil && len(Path) > 0 {
		defaultTree = Path[0]
	}
}
<|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.

package os

import (
	"errors"
	"runtime"
	"syscall"
	"time"
)

// The only signal values guaranteed to be present on all systems
// are Interrupt (send the process an interrupt) and Kill (force
// the process to exit).
var (
	Interrupt Signal = syscall.Note("interrupt")
	Kill      Signal = syscall.Note("kill")
)

func startProcess(name string, argv []string, attr *ProcAttr) (p *Process, err error) {
	sysattr := &syscall.ProcAttr{
		Dir: attr.Dir,
		Env: attr.Env,
		Sys: attr.Sys,
	}

	for _, f := range attr.Files {
		sysattr.Files = append(sysattr.Files, f.Fd())
	}

	pid, h, e := syscall.StartProcess(name, argv, sysattr)
	if e != nil {
		return nil, &PathError{"fork/exec", name, e}
	}

	return newProcess(pid, h), nil
}

func (p *Process) writeProcFile(file string, data string) error {
	f, e := OpenFile("/proc/"+itoa(p.Pid)+"/"+file, O_WRONLY, 0)
	if e != nil {
		return e
	}
	defer f.Close()
	_, e = f.Write([]byte(data))
	return e
}

func (p *Process) signal(sig Signal) error {
	if p.done() {
		return errors.New("os: process already finished")
	}
	if sig == Kill {
		// Special-case the kill signal since it doesn't use /proc/$pid/note.
		return p.Kill()
	}
	if e := p.writeProcFile("note", sig.String()); e != nil {
		return NewSyscallError("signal", e)
	}
	return nil
}

func (p *Process) kill() error {
	if e := p.writeProcFile("ctl", "kill"); e != nil {
		return NewSyscallError("kill", e)
	}
	return nil
}

func (p *Process) wait() (ps *ProcessState, err error) {
	var waitmsg syscall.Waitmsg

	if p.Pid == -1 {
		return nil, ErrInvalid
	}
	err = syscall.WaitProcess(p.Pid, &waitmsg)
	if err != nil {
		return nil, NewSyscallError("wait", err)
	}

	p.setDone()
	ps = &ProcessState{
		pid:    waitmsg.Pid,
		status: &waitmsg,
	}
	return ps, nil
}

func (p *Process) release() error {
	// NOOP for Plan 9.
	p.Pid = -1
	// no need for a finalizer anymore
	runtime.SetFinalizer(p, nil)
	return nil
}

func findProcess(pid int) (p *Process, err error) {
	// NOOP for Plan 9.
	return newProcess(pid, 0), nil
}

// ProcessState stores information about a process, as reported by Wait.
type ProcessState struct {
	pid    int              // The process's id.
	status *syscall.Waitmsg // System-dependent status info.
}

// Pid returns the process id of the exited process.
func (p *ProcessState) Pid() int {
	return p.pid
}

func (p *ProcessState) exited() bool {
	return p.status.Exited()
}

func (p *ProcessState) success() bool {
	return p.status.ExitStatus() == 0
}

func (p *ProcessState) sys() interface{} {
	return p.status
}

func (p *ProcessState) sysUsage() interface{} {
	return p.status
}

func (p *ProcessState) userTime() time.Duration {
	return time.Duration(p.status.Time[0]) * time.Millisecond
}

func (p *ProcessState) systemTime() time.Duration {
	return time.Duration(p.status.Time[1]) * time.Millisecond
}

func (p *ProcessState) String() string {
	if p == nil {
		return "<nil>"
	}
	return "exit status: " + p.status.Msg
}
<commit_msg>os: relax the way we kill processes on Plan 9<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.

package os

import (
	"errors"
	"runtime"
	"syscall"
	"time"
)

// The only signal values guaranteed to be present on all systems
// are Interrupt (send the process an interrupt) and Kill (force
// the process to exit).
var (
	Interrupt Signal = syscall.Note("interrupt")
	Kill      Signal = syscall.Note("kill")
)

func startProcess(name string, argv []string, attr *ProcAttr) (p *Process, err error) {
	sysattr := &syscall.ProcAttr{
		Dir: attr.Dir,
		Env: attr.Env,
		Sys: attr.Sys,
	}

	for _, f := range attr.Files {
		sysattr.Files = append(sysattr.Files, f.Fd())
	}

	pid, h, e := syscall.StartProcess(name, argv, sysattr)
	if e != nil {
		return nil, &PathError{"fork/exec", name, e}
	}

	return newProcess(pid, h), nil
}

func (p *Process) writeProcFile(file string, data string) error {
	f, e := OpenFile("/proc/"+itoa(p.Pid)+"/"+file, O_WRONLY, 0)
	if e != nil {
		return e
	}
	defer f.Close()
	_, e = f.Write([]byte(data))
	return e
}

func (p *Process) signal(sig Signal) error {
	if p.done() {
		return errors.New("os: process already finished")
	}
	if e := p.writeProcFile("note", sig.String()); e != nil {
		return NewSyscallError("signal", e)
	}
	return nil
}

func (p *Process) kill() error {
	return p.signal(Kill)
}

func (p *Process) wait() (ps *ProcessState, err error) {
	var waitmsg syscall.Waitmsg

	if p.Pid == -1 {
		return nil, ErrInvalid
	}
	err = syscall.WaitProcess(p.Pid, &waitmsg)
	if err != nil {
		return nil, NewSyscallError("wait", err)
	}

	p.setDone()
	ps = &ProcessState{
		pid:    waitmsg.Pid,
		status: &waitmsg,
	}
	return ps, nil
}

func (p *Process) release() error {
	// NOOP for Plan 9.
	p.Pid = -1
	// no need for a finalizer anymore
	runtime.SetFinalizer(p, nil)
	return nil
}

func findProcess(pid int) (p *Process, err error) {
	// NOOP for Plan 9.
	return newProcess(pid, 0), nil
}

// ProcessState stores information about a process, as reported by Wait.
type ProcessState struct {
	pid    int              // The process's id.
	status *syscall.Waitmsg // System-dependent status info.
}

// Pid returns the process id of the exited process.
func (p *ProcessState) Pid() int {
	return p.pid
}

func (p *ProcessState) exited() bool {
	return p.status.Exited()
}

func (p *ProcessState) success() bool {
	return p.status.ExitStatus() == 0
}

func (p *ProcessState) sys() interface{} {
	return p.status
}

func (p *ProcessState) sysUsage() interface{} {
	return p.status
}

func (p *ProcessState) userTime() time.Duration {
	return time.Duration(p.status.Time[0]) * time.Millisecond
}

func (p *ProcessState) systemTime() time.Duration {
	return time.Duration(p.status.Time[1]) * time.Millisecond
}

func (p *ProcessState) String() string {
	if p == nil {
		return "<nil>"
	}
	return "exit status: " + p.status.Msg
}
<|endoftext|>


<commit_before>package three

import (
	"errors"
	"fmt"
	"log"

	gl "github.com/go-gl/gl"
	glfw "github.com/go-gl/glfw3"
	glh "github.com/tobscher/glh"
)

// Renderer handles mesh rendering to the window.
type Renderer struct {
	Width       int
	Height      int
	vertexArray gl.VertexArray
	window      *glfw.Window
}

// NewRenderer creates a new Renderer with the given window size and title.
func NewRenderer(width, height int, title string) (*Renderer, error) {
	// Error callback
	glfw.SetErrorCallback(errorCallback)

	// Init glfw
	if !glfw.Init() {
		return nil, errors.New("Could not initialise GLFW.")
	}

	glfw.WindowHint(glfw.Samples, 4)
	glfw.WindowHint(glfw.ContextVersionMajor, 3)
	glfw.WindowHint(glfw.ContextVersionMinor, 3)
	glfw.WindowHint(glfw.OpenglForwardCompatible, glfw.True)
	glfw.WindowHint(glfw.OpenglProfile, glfw.OpenglCoreProfile)

	// Create window
	window, err := glfw.CreateWindow(width, height, title, nil, nil)
	if err != nil {
		return nil, err
	}
	window.SetKeyCallback(keyCallback)
	window.MakeContextCurrent()

	// Use vsync
	glfw.SwapInterval(1)

	// Init glew
	if gl.Init() != 0 {
		return nil, errors.New("Could not initialise glew.")
	}
	gl.GetError()

	gl.Enable(gl.DEPTH_TEST)
	gl.DepthFunc(gl.LESS)

	// Vertex buffers
	vertexArray := gl.GenVertexArray()
	vertexArray.Bind()

	renderer := Renderer{vertexArray: vertexArray, window: window, Width: width, Height: height}
	return &renderer, nil
}

// Render renders the given scene with the given camera to the window.
func (r *Renderer) Render(scene *Scene, camera *PerspectiveCamera) {
	width, height := r.window.GetFramebufferSize()
	gl.Viewport(0, 0, width, height)
	gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)

	for _, element := range scene.objects {
		program := element.material.Program()
		if program == nil {
			program = createProgram(element)
			element.material.SetProgram(program)
		}
		program.use()

		// Is already inverted by multiplier
		view := camera.Transform.modelMatrix()
		projection := camera.projectionMatrix
		MVP := projection.Mul4(view).Mul4(element.Transform.modelMatrix())

		// Set model view projection matrix
		program.uniforms["MVP"].apply(MVP)

		if c, ok := element.material.(Colored); ok {
			if c.Color() != nil {
				program.uniforms["diffuse"].apply(c.Color())
			}
		}

		var toDisable []gl.AttribLocation

		for _, attribute := range program.attributes {
			toDisable = append(toDisable, attribute.enableFor())
		}

		t, ok := element.material.(Wireframed)
		if ok {
			if t.Wireframe() {
				gl.PolygonMode(gl.FRONT_AND_BACK, gl.LINE)
			} else {
				gl.PolygonMode(gl.FRONT_AND_BACK, gl.FILL)
			}
		}

		gl.DrawArrays(gl.TRIANGLES, 0, len(element.geometry.Vertices()))

		for _, location := range toDisable {
			location.DisableArray()
		}
	}

	r.window.SwapBuffers()
	glfw.PollEvents()
}

// ShouldClose indicates if the window should be closed.
func (r *Renderer) ShouldClose() bool {
	return r.window.ShouldClose()
}

func createProgram(mesh *Mesh) *Program {
	program := NewProgram()
	material := mesh.material
	geometry := mesh.geometry

	// Attributes
	program.attributes["vertex"] = NewAttribute(0, 3, newVertexBuffer(geometry))

	var feature ProgramFeature
	if c, cOk := material.(Colored); cOk {
		if c.Color() != nil {
			feature = COLOR
		}
	}

	// Let geometry return UVs
	if t, tOk := material.(Textured); tOk {
		if t.Texture() != nil {
			program.attributes["texture"] = NewAttribute(1, 2, newUvBuffer(geometry))
			feature = TEXTURE
		}
	}

	program.Load(MakeProgram(feature))

	// Uniforms
	program.uniforms["MVP"] = NewUniform(program, "MVP")
	program.uniforms["diffuse"] = NewUniform(program, "diffuse")

	return program
}

func newVertexBuffer(geometry Shape) *Buffer {
	result := []float32{}

	for _, vertex := range geometry.Vertices() {
		result = append(result, vertex.X(), vertex.Y(), vertex.Z())
	}

	b := NewBuffer(result)
	return &b
}

func newUvBuffer(geometry Shape) *Buffer {
	result := []float32{}

	for _, uv := range geometry.VertexUvs() {
		result = append(result, uv.X(), uv.Y())
	}

	// Invert V because we're using a compressed texture
	for i := 1; i < len(result); i += 2 {
		result[i] = 1.0 - result[i]
	}

	b := NewBuffer(result)
	return &b
}

// Unload deallocates the given scene and all its shader programs.
func (r *Renderer) Unload(s *Scene) {
	log.Println("Cleaning up...")

	for _, element := range s.objects {
		program := element.material.Program()
		program.unload()
	}

	r.vertexArray.Delete()
	glfw.Terminate()
}

// OpenGLSentinel reports any OpenGL related errors.
func (r *Renderer) OpenGLSentinel() {
	glh.OpenGLSentinel()
}

func keyCallback(w *glfw.Window, key glfw.Key, scancode int, action glfw.Action, mods glfw.ModifierKey) {
	if key == glfw.KeyEscape && action == glfw.Press {
		w.SetShouldClose(true)
	}
}

func errorCallback(err glfw.ErrorCode, desc string) {
	fmt.Printf("%v: %v\n", err, desc)
}
<commit_msg>lock OS thread<commit_after>package three

import (
	"errors"
	"fmt"
	"log"
	"runtime"

	gl "github.com/go-gl/gl"
	glfw "github.com/go-gl/glfw3"
	glh "github.com/tobscher/glh"
)

// Renderer handles mesh rendering to the window.
type Renderer struct {
	Width       int
	Height      int
	vertexArray gl.VertexArray
	window      *glfw.Window
}

// NewRenderer creates a new Renderer with the given window size and title.
func NewRenderer(width, height int, title string) (*Renderer, error) {
	runtime.LockOSThread()

	// Error callback
	glfw.SetErrorCallback(errorCallback)

	// Init glfw
	if !glfw.Init() {
		return nil, errors.New("Could not initialise GLFW.")
	}

	glfw.WindowHint(glfw.Samples, 4)
	glfw.WindowHint(glfw.ContextVersionMajor, 3)
	glfw.WindowHint(glfw.ContextVersionMinor, 3)
	glfw.WindowHint(glfw.OpenglForwardCompatible, glfw.True)
	glfw.WindowHint(glfw.OpenglProfile, glfw.OpenglCoreProfile)

	// Create window
	window, err := glfw.CreateWindow(width, height, title, nil, nil)
	if err != nil {
		return nil, err
	}
	window.SetKeyCallback(keyCallback)
	window.MakeContextCurrent()

	// Use vsync
	glfw.SwapInterval(1)

	// Init glew
	if gl.Init() != 0 {
		return nil, errors.New("Could not initialise glew.")
	}
	gl.GetError()

	gl.Enable(gl.DEPTH_TEST)
	gl.DepthFunc(gl.LESS)

	// Vertex buffers
	vertexArray := gl.GenVertexArray()
	vertexArray.Bind()

	renderer := Renderer{vertexArray: vertexArray, window: window, Width: width, Height: height}
	return &renderer, nil
}

// Render renders the given scene with the given camera to the window.
func (r *Renderer) Render(scene *Scene, camera *PerspectiveCamera) {
	width, height := r.window.GetFramebufferSize()
	gl.Viewport(0, 0, width, height)
	gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)

	for _, element := range scene.objects {
		program := element.material.Program()
		if program == nil {
			program = createProgram(element)
			element.material.SetProgram(program)
		}
		program.use()

		// Is already inverted by multiplier
		view := camera.Transform.modelMatrix()
		projection := camera.projectionMatrix
		MVP := projection.Mul4(view).Mul4(element.Transform.modelMatrix())

		// Set model view projection matrix
		program.uniforms["MVP"].apply(MVP)

		if c, ok := element.material.(Colored); ok {
			if c.Color() != nil {
				program.uniforms["diffuse"].apply(c.Color())
			}
		}

		var toDisable []gl.AttribLocation

		for _, attribute := range program.attributes {
			toDisable = append(toDisable, attribute.enableFor())
		}

		t, ok := element.material.(Wireframed)
		if ok {
			if t.Wireframe() {
				gl.PolygonMode(gl.FRONT_AND_BACK, gl.LINE)
			} else {
				gl.PolygonMode(gl.FRONT_AND_BACK, gl.FILL)
			}
		}

		gl.DrawArrays(gl.TRIANGLES, 0, len(element.geometry.Vertices()))

		for _, location := range toDisable {
			location.DisableArray()
		}
	}

	r.window.SwapBuffers()
	glfw.PollEvents()
}

// ShouldClose indicates if the window should be closed.
func (r *Renderer) ShouldClose() bool {
	return r.window.ShouldClose()
}

func createProgram(mesh *Mesh) *Program {
	program := NewProgram()
	material := mesh.material
	geometry := mesh.geometry

	// Attributes
	program.attributes["vertex"] = NewAttribute(0, 3, newVertexBuffer(geometry))

	var feature ProgramFeature
	if c, cOk := material.(Colored); cOk {
		if c.Color() != nil {
			feature = COLOR
		}
	}

	// Let geometry return UVs
	if t, tOk := material.(Textured); tOk {
		if t.Texture() != nil {
			program.attributes["texture"] = NewAttribute(1, 2, newUvBuffer(geometry))
			feature = TEXTURE
		}
	}

	program.Load(MakeProgram(feature))

	// Uniforms
	program.uniforms["MVP"] = NewUniform(program, "MVP")
	program.uniforms["diffuse"] = NewUniform(program, "diffuse")

	return program
}

func newVertexBuffer(geometry Shape) *Buffer {
	result := []float32{}

	for _, vertex := range geometry.Vertices() {
		result = append(result, vertex.X(), vertex.Y(), vertex.Z())
	}

	b := NewBuffer(result)
	return &b
}

func newUvBuffer(geometry Shape) *Buffer {
	result := []float32{}

	for _, uv := range geometry.VertexUvs() {
		result = append(result, uv.X(), uv.Y())
	}

	// Invert V because we're using a compressed texture
	for i := 1; i < len(result); i += 2 {
		result[i] = 1.0 - result[i]
	}

	b := NewBuffer(result)
	return &b
}

// Unload deallocates the given scene and all its shader programs.
func (r *Renderer) Unload(s *Scene) {
	log.Println("Cleaning up...")

	for _, element := range s.objects {
		program := element.material.Program()
		program.unload()
	}

	r.vertexArray.Delete()
	glfw.Terminate()
}

// OpenGLSentinel reports any OpenGL related errors.
func (r *Renderer) OpenGLSentinel() {
	glh.OpenGLSentinel()
}

func keyCallback(w *glfw.Window, key glfw.Key, scancode int, action glfw.Action, mods glfw.ModifierKey) {
	if key == glfw.KeyEscape && action == glfw.Press {
		w.SetShouldClose(true)
	}
}

func errorCallback(err glfw.ErrorCode, desc string) {
	fmt.Printf("%v: %v\n", err, desc)
}
<|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.

package strconv

import (
	"bytes"
	"os"
	"strings"
	"unicode"
	"utf8"
)

const lowerhex = "0123456789abcdef"

// Quote returns a double-quoted Go string literal
// representing s.  The returned string s uses Go escape
// sequences (\t, \n, \xFF, \u0100) for control characters
// and non-ASCII characters.
func Quote(s string) string {
	var buf bytes.Buffer
	buf.WriteByte('"')
	for ; len(s) > 0; s = s[1:] {
		switch c := s[0]; {
		case c == '"':
			buf.WriteString(`\"`)
		case c == '\\':
			buf.WriteString(`\\`)
		case ' ' <= c && c <= '~':
			buf.WriteString(string(c))
		case c == '\a':
			buf.WriteString(`\a`)
		case c == '\b':
			buf.WriteString(`\b`)
		case c == '\f':
			buf.WriteString(`\f`)
		case c == '\n':
			buf.WriteString(`\n`)
		case c == '\r':
			buf.WriteString(`\r`)
		case c == '\t':
			buf.WriteString(`\t`)
		case c == '\v':
			buf.WriteString(`\v`)

		case c >= utf8.RuneSelf && utf8.FullRuneInString(s):
			r, size := utf8.DecodeRuneInString(s)
			if r == utf8.RuneError && size == 1 {
				goto EscX
			}
			s = s[size-1:] // next iteration will slice off 1 more
			if r < 0x10000 {
				buf.WriteString(`\u`)
				for j := uint(0); j < 4; j++ {
					buf.WriteByte(lowerhex[(r>>(12-4*j))&0xF])
				}
			} else {
				buf.WriteString(`\U`)
				for j := uint(0); j < 8; j++ {
					buf.WriteByte(lowerhex[(r>>(28-4*j))&0xF])
				}
			}

		default:
		EscX:
			buf.WriteString(`\x`)
			buf.WriteByte(lowerhex[c>>4])
			buf.WriteByte(lowerhex[c&0xF])
		}
	}
	buf.WriteByte('"')
	return buf.String()
}

// CanBackquote returns whether the string s would be
// a valid Go string literal if enclosed in backquotes.
func CanBackquote(s string) bool {
	for i := 0; i < len(s); i++ {
		if (s[i] < ' ' && s[i] != '\t') || s[i] == '`' {
			return false
		}
	}
	return true
}

func unhex(b byte) (v int, ok bool) {
	c := int(b)
	switch {
	case '0' <= c && c <= '9':
		return c - '0', true
	case 'a' <= c && c <= 'f':
		return c - 'a' + 10, true
	case 'A' <= c && c <= 'F':
		return c - 'A' + 10, true
	}
	return
}

// UnquoteChar decodes the first character or byte in the escaped string
// or character literal represented by the string s.
// It returns four values:
// 1) value, the decoded Unicode code point or byte value;
// 2) multibyte, a boolean indicating whether the decoded character
//    requires a multibyte UTF-8 representation;
// 3) tail, the remainder of the string after the character; and
// 4) an error that will be nil if the character is syntactically valid.
// The second argument, quote, specifies the type of literal being parsed
// and therefore which escaped quote character is permitted.
// If set to a single quote, it permits the sequence \' and disallows unescaped '.
// If set to a double quote, it permits \" and disallows unescaped ".
// If set to zero, it does not permit either escape and allows both quote characters to appear unescaped.
func UnquoteChar(s string, quote byte) (value int, multibyte bool, tail string, err os.Error) {
	// easy cases
	switch c := s[0]; {
	case c == quote && (quote == '\'' || quote == '"'):
		err = os.EINVAL
		return
	case c >= utf8.RuneSelf:
		r, size := utf8.DecodeRuneInString(s)
		return r, true, s[size:], nil
	case c != '\\':
		return int(s[0]), false, s[1:], nil
	}

	// hard case: c is backslash
	if len(s) <= 1 {
		err = os.EINVAL
		return
	}
	c := s[1]
	s = s[2:]

	switch c {
	case 'a':
		value = '\a'
	case 'b':
		value = '\b'
	case 'f':
		value = '\f'
	case 'n':
		value = '\n'
	case 'r':
		value = '\r'
	case 't':
		value = '\t'
	case 'v':
		value = '\v'
	case 'x', 'u', 'U':
		n := 0
		switch c {
		case 'x':
			n = 2
		case 'u':
			n = 4
		case 'U':
			n = 8
		}
		v := 0
		if len(s) < n {
			err = os.EINVAL
			return
		}
		for j := 0; j < n; j++ {
			x, ok := unhex(s[j])
			if !ok {
				err = os.EINVAL
				return
			}
			v = v<<4 | x
		}
		s = s[n:]
		if c == 'x' {
			// single-byte string, possibly not UTF-8
			value = v
			break
		}
		if v > unicode.MaxRune {
			err = os.EINVAL
			return
		}
		value = v
		multibyte = true
	case '0', '1', '2', '3', '4', '5', '6', '7':
		v := int(c) - '0'
		if len(s) < 2 {
			err = os.EINVAL
			return
		}
		for j := 0; j < 2; j++ { // one digit already; two more
			x := int(s[j]) - '0'
			if x < 0 || x > 7 {
				return
			}
			v = (v << 3) | x
		}
		s = s[2:]
		if v > 255 {
			err = os.EINVAL
			return
		}
		value = v
	case '\\':
		value = '\\'
	case '\'', '"':
		if c != quote {
			err = os.EINVAL
			return
		}
		value = int(c)
	default:
		err = os.EINVAL
		return
	}
	tail = s
	return
}

// Unquote interprets s as a single-quoted, double-quoted,
// or backquoted Go string literal, returning the string value
// that s quotes.  (If s is single-quoted, it would be a Go
// character literal; Unquote returns the corresponding
// one-character string.)
func Unquote(s string) (t string, err os.Error) {
	n := len(s)
	if n < 2 {
		return "", os.EINVAL
	}
	quote := s[0]
	if quote != s[n-1] {
		return "", os.EINVAL
	}
	s = s[1 : n-1]

	if quote == '`' {
		if strings.Index(s, "`") >= 0 {
			return "", os.EINVAL
		}
		return s, nil
	}
	if quote != '"' && quote != '\'' {
		return "", err
	}

	var buf bytes.Buffer
	for len(s) > 0 {
		c, multibyte, ss, err := UnquoteChar(s, quote)
		if err != nil {
			return "", err
		}
		s = ss
		if c < utf8.RuneSelf || !multibyte {
			buf.WriteByte(byte(c))
		} else {
			buf.WriteString(string(c))
		}
		if quote == '\'' && len(s) != 0 {
			// single-quoted must be single character
			return "", os.EINVAL
		}
	}
	return buf.String(), nil
}
<commit_msg>strconv.Unquote could wrongly return a nil error on error.<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.

package strconv

import (
	"bytes"
	"os"
	"strings"
	"unicode"
	"utf8"
)

const lowerhex = "0123456789abcdef"

// Quote returns a double-quoted Go string literal
// representing s.  The returned string s uses Go escape
// sequences (\t, \n, \xFF, \u0100) for control characters
// and non-ASCII characters.
func Quote(s string) string {
	var buf bytes.Buffer
	buf.WriteByte('"')
	for ; len(s) > 0; s = s[1:] {
		switch c := s[0]; {
		case c == '"':
			buf.WriteString(`\"`)
		case c == '\\':
			buf.WriteString(`\\`)
		case ' ' <= c && c <= '~':
			buf.WriteString(string(c))
		case c == '\a':
			buf.WriteString(`\a`)
		case c == '\b':
			buf.WriteString(`\b`)
		case c == '\f':
			buf.WriteString(`\f`)
		case c == '\n':
			buf.WriteString(`\n`)
		case c == '\r':
			buf.WriteString(`\r`)
		case c == '\t':
			buf.WriteString(`\t`)
		case c == '\v':
			buf.WriteString(`\v`)

		case c >= utf8.RuneSelf && utf8.FullRuneInString(s):
			r, size := utf8.DecodeRuneInString(s)
			if r == utf8.RuneError && size == 1 {
				goto EscX
			}
			s = s[size-1:] // next iteration will slice off 1 more
			if r < 0x10000 {
				buf.WriteString(`\u`)
				for j := uint(0); j < 4; j++ {
					buf.WriteByte(lowerhex[(r>>(12-4*j))&0xF])
				}
			} else {
				buf.WriteString(`\U`)
				for j := uint(0); j < 8; j++ {
					buf.WriteByte(lowerhex[(r>>(28-4*j))&0xF])
				}
			}

		default:
		EscX:
			buf.WriteString(`\x`)
			buf.WriteByte(lowerhex[c>>4])
			buf.WriteByte(lowerhex[c&0xF])
		}
	}
	buf.WriteByte('"')
	return buf.String()
}

// CanBackquote returns whether the string s would be
// a valid Go string literal if enclosed in backquotes.
func CanBackquote(s string) bool {
	for i := 0; i < len(s); i++ {
		if (s[i] < ' ' && s[i] != '\t') || s[i] == '`' {
			return false
		}
	}
	return true
}

func unhex(b byte) (v int, ok bool) {
	c := int(b)
	switch {
	case '0' <= c && c <= '9':
		return c - '0', true
	case 'a' <= c && c <= 'f':
		return c - 'a' + 10, true
	case 'A' <= c && c <= 'F':
		return c - 'A' + 10, true
	}
	return
}

// UnquoteChar decodes the first character or byte in the escaped string
// or character literal represented by the string s.
// It returns four values:
// 1) value, the decoded Unicode code point or byte value;
// 2) multibyte, a boolean indicating whether the decoded character
//    requires a multibyte UTF-8 representation;
// 3) tail, the remainder of the string after the character; and
// 4) an error that will be nil if the character is syntactically valid.
// The second argument, quote, specifies the type of literal being parsed
// and therefore which escaped quote character is permitted.
// If set to a single quote, it permits the sequence \' and disallows unescaped '.
// If set to a double quote, it permits \" and disallows unescaped ".
// If set to zero, it does not permit either escape and allows both quote characters to appear unescaped.
func UnquoteChar(s string, quote byte) (value int, multibyte bool, tail string, err os.Error) {
	// easy cases
	switch c := s[0]; {
	case c == quote && (quote == '\'' || quote == '"'):
		err = os.EINVAL
		return
	case c >= utf8.RuneSelf:
		r, size := utf8.DecodeRuneInString(s)
		return r, true, s[size:], nil
	case c != '\\':
		return int(s[0]), false, s[1:], nil
	}

	// hard case: c is backslash
	if len(s) <= 1 {
		err = os.EINVAL
		return
	}
	c := s[1]
	s = s[2:]

	switch c {
	case 'a':
		value = '\a'
	case 'b':
		value = '\b'
	case 'f':
		value = '\f'
	case 'n':
		value = '\n'
	case 'r':
		value = '\r'
	case 't':
		value = '\t'
	case 'v':
		value = '\v'
	case 'x', 'u', 'U':
		n := 0
		switch c {
		case 'x':
			n = 2
		case 'u':
			n = 4
		case 'U':
			n = 8
		}
		v := 0
		if len(s) < n {
			err = os.EINVAL
			return
		}
		for j := 0; j < n; j++ {
			x, ok := unhex(s[j])
			if !ok {
				err = os.EINVAL
				return
			}
			v = v<<4 | x
		}
		s = s[n:]
		if c == 'x' {
			// single-byte string, possibly not UTF-8
			value = v
			break
		}
		if v > unicode.MaxRune {
			err = os.EINVAL
			return
		}
		value = v
		multibyte = true
	case '0', '1', '2', '3', '4', '5', '6', '7':
		v := int(c) - '0'
		if len(s) < 2 {
			err = os.EINVAL
			return
		}
		for j := 0; j < 2; j++ { // one digit already; two more
			x := int(s[j]) - '0'
			if x < 0 || x > 7 {
				return
			}
			v = (v << 3) | x
		}
		s = s[2:]
		if v > 255 {
			err = os.EINVAL
			return
		}
		value = v
	case '\\':
		value = '\\'
	case '\'', '"':
		if c != quote {
			err = os.EINVAL
			return
		}
		value = int(c)
	default:
		err = os.EINVAL
		return
	}
	tail = s
	return
}

// Unquote interprets s as a single-quoted, double-quoted,
// or backquoted Go string literal, returning the string value
// that s quotes.  (If s is single-quoted, it would be a Go
// character literal; Unquote returns the corresponding
// one-character string.)
func Unquote(s string) (t string, err os.Error) {
	n := len(s)
	if n < 2 {
		return "", os.EINVAL
	}
	quote := s[0]
	if quote != s[n-1] {
		return "", os.EINVAL
	}
	s = s[1 : n-1]

	if quote == '`' {
		if strings.Index(s, "`") >= 0 {
			return "", os.EINVAL
		}
		return s, nil
	}
	if quote != '"' && quote != '\'' {
		return "", os.EINVAL
	}

	var buf bytes.Buffer
	for len(s) > 0 {
		c, multibyte, ss, err := UnquoteChar(s, quote)
		if err != nil {
			return "", err
		}
		s = ss
		if c < utf8.RuneSelf || !multibyte {
			buf.WriteByte(byte(c))
		} else {
			buf.WriteString(string(c))
		}
		if quote == '\'' && len(s) != 0 {
			// single-quoted must be single character
			return "", os.EINVAL
		}
	}
	return buf.String(), nil
}
<|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.

/*
	The unsafe package contains operations that step around the type safety of Go programs.
*/
package unsafe

// ArbitraryType is here for the purposes of documentation only and is not actually
// part of the unsafe package.  It represents the type of an arbitrary Go expression.
type ArbitraryType int

// Pointer represents a pointer to an arbitrary type.  There are three special operations
// available for type Pointer that are not available for other types.
//	1) A pointer value of any type can be converted to a Pointer.
//	2) A Pointer can be converted to a pointer value of any type.
//	3) A uintptr can be converted to a Pointer.
//	4) A Pointer can be converted to a uintptr.
// Pointer therefore allows a program to defeat the type system and read and write
// arbitrary memory. It should be used with extreme care.
type Pointer *ArbitraryType

// Sizeof returns the size in bytes occupied by the value v.  The size is that of the
// "top level" of the value only.  For instance, if v is a slice, it returns the size of
// the slice descriptor, not the size of the memory referenced by the slice.
func Sizeof(v ArbitraryType) int

// Offsetof returns the offset within the struct of the field represented by v,
// which must be of the form struct_value.field.  In other words, it returns the
// number of bytes between the start of the struct and the start of the field.
func Offsetof(v ArbitraryType) int

// Alignof returns the alignment of the value v.  It is the maximum value m such
// that the address of a variable with the type of v will always always be zero mod m.
// If v is of the form obj.f, it returns the alignment of field f within struct object obj.
func Alignof(v ArbitraryType) int

// Typeof returns the type of an interface value, a runtime.Type.
func Typeof(i interface{}) (typ interface{})

// Reflect unpacks an interface value into its type and the address of a copy of the
// internal value.
func Reflect(i interface{}) (typ interface{}, addr uintptr)

// Unreflect inverts Reflect: Given a type and a pointer, it returns an empty interface value
// with those contents.  The typ is assumed to contain a pointer to a runtime type;
// the type information in the interface{} is ignored, so that, for example, both
// *reflect.StructType and *runtime.StructType can be passed for typ.
func Unreflect(typ interface{}, addr uintptr) (ret interface{})

// New allocates and returns a pointer to memory for a new value of the given type.
// The typ is assumed to hold a pointer to a runtime type.
// Callers should use reflect.MakeZero instead of invoking unsafe.New directly.
func New(typ interface{}) Pointer

// NewArray allocates and returns a pointer to an array of n elements of the given type.
// The typ is assumed to hold a pointer to a runtime type.
// Callers should use reflect.MakeSlice instead of invoking unsafe.NewArray directly.
func NewArray(typ interface{}, n int) Pointer
<commit_msg>unsafe: fix the documentation Reflection is about Pointer, not uintptr. Also clarify that Reflect and Unreflect are indirect.<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.

/*
	The unsafe package contains operations that step around the type safety of Go programs.
*/
package unsafe

// ArbitraryType is here for the purposes of documentation only and is not actually
// part of the unsafe package.  It represents the type of an arbitrary Go expression.
type ArbitraryType int

// Pointer represents a pointer to an arbitrary type.  There are three special operations
// available for type Pointer that are not available for other types.
//	1) A pointer value of any type can be converted to a Pointer.
//	2) A Pointer can be converted to a pointer value of any type.
//	3) A uintptr can be converted to a Pointer.
//	4) A Pointer can be converted to a uintptr.
// Pointer therefore allows a program to defeat the type system and read and write
// arbitrary memory. It should be used with extreme care.
type Pointer *ArbitraryType

// Sizeof returns the size in bytes occupied by the value v.  The size is that of the
// "top level" of the value only.  For instance, if v is a slice, it returns the size of
// the slice descriptor, not the size of the memory referenced by the slice.
func Sizeof(v ArbitraryType) int

// Offsetof returns the offset within the struct of the field represented by v,
// which must be of the form struct_value.field.  In other words, it returns the
// number of bytes between the start of the struct and the start of the field.
func Offsetof(v ArbitraryType) int

// Alignof returns the alignment of the value v.  It is the maximum value m such
// that the address of a variable with the type of v will always always be zero mod m.
// If v is of the form obj.f, it returns the alignment of field f within struct object obj.
func Alignof(v ArbitraryType) int

// Typeof returns the type of an interface value, a runtime.Type.
func Typeof(i interface{}) (typ interface{})

// Reflect unpacks an interface value into its type and the address of a copy of the
// internal value.
func Reflect(i interface{}) (typ interface{}, addr Pointer)

// Unreflect inverts Reflect: Given a type and a pointer to a value, it returns an
// empty interface value with contents the type and the value (not the pointer to
// the value).  The typ is assumed to contain a pointer to a runtime type; the type
// information in the interface{} is ignored, so that, for example, both
// *reflect.StructType and *runtime.StructType can be passed for typ.
func Unreflect(typ interface{}, addr Pointer) (ret interface{})

// New allocates and returns a pointer to memory for a new value of the given type.
// The typ is assumed to hold a pointer to a runtime type.
// Callers should use reflect.MakeZero instead of invoking unsafe.New directly.
func New(typ interface{}) Pointer

// NewArray allocates and returns a pointer to an array of n elements of the given type.
// The typ is assumed to hold a pointer to a runtime type.
// Callers should use reflect.MakeSlice instead of invoking unsafe.NewArray directly.
func NewArray(typ interface{}, n int) Pointer
<|endoftext|>


<commit_before>package main

func ReportThread(t []target) {
    for {
        k := 0
        for i := range t {
            impl := target.GetImpl(t[i])
            addr := impl.conf.Target.Addr
            if impl.conf.Target.Prot == "EXEC" {
                addr = "127.0.0.1"
            }
            _stdscr.MovePrintf(k, 0, "%2d: Target Name: %s, Addr: %s, Sys: %s\n", i, impl.conf.Target.Name, addr, impl.conf.Target.Sys)
            _stdscr.ClearToEOL()
            k++
            for range impl.task {
                if _, err := target.Report(t[i]); err == nil {
                }
            }
            for j := range impl.db {
                val := 0.
                prefix := ""
                switch impl.task[j].Exec.Reports[0] {
                    case "RATE":
                        val = impl.db[j].rate
                    case "RAW":
                        val = impl.db[j].dpN.y
                    default:
                        val = -1.
                }
                val, prefix = ToUnits(val, 10)
                _stdscr.MovePrintf(k, 0, "    %4d: [%-96s] %.3f%s%s", impl.db[j].N, impl.db[j].task, val, prefix, impl.db[j].units)
                _stdscr.ClearToEOL()
                k++
            }
            _stdscr.Refresh()
        }
    }
}
<commit_msg>Fixed reporter formatting<commit_after>package main

func ReportThread(t []target) {
    for {
        k := 0
        for i := range t {
            impl := target.GetImpl(t[i])
            addr := impl.conf.Target.Addr
            if impl.conf.Target.Prot == "EXEC" {
                addr = "127.0.0.1"
            }
            _stdscr.MovePrintf(k, 0, "%2d: Target Name: %s, Addr: %s, Sys: %s\n", i, impl.conf.Target.Name, addr, impl.conf.Target.Sys)
            _stdscr.ClearToEOL()
            k++
            for range impl.task {
                if _, err := target.Report(t[i]); err == nil {
                }
            }
            for j := range impl.db {
                val := 0.
                prefix := ""
                switch impl.task[j].Exec.Reports[0] {
                    case "RATE":
                        val = impl.db[j].rate
                    case "RAW":
                        val = impl.db[j].dpN.y
                    default:
                        val = -1.
                }
                val, prefix = ToUnits(val, 10)
                _stdscr.MovePrintf(k, 0, "    %4d: [%-96s] %7.3f %s%s", impl.db[j].N, impl.db[j].task, val, prefix, impl.db[j].units)
                _stdscr.ClearToEOL()
                k++
            }
            _stdscr.Refresh()
        }
    }
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"os"
	"os/signal"
	"sort"
	"strconv"
	"syscall"
	"time"

	"github.com/gophergala2016/goad"
	"github.com/gophergala2016/goad/Godeps/_workspace/src/github.com/nsf/termbox-go"
	"github.com/gophergala2016/goad/queue"
)

var (
	url         string
	concurrency uint
	requests    uint
	timeout     uint
	region      string
)

const coldef = termbox.ColorDefault
const nano = 1000000000

func main() {
	flag.UintVar(&concurrency, "c", 10, "number of concurrent requests")
	flag.UintVar(&requests, "n", 1000, "number of total requests to make")
	flag.UintVar(&timeout, "t", 15, "request timeout in seconds")
	flag.StringVar(&region, "r", "us-east-1", "AWS region")
	flag.Parse()

	if len(flag.Args()) < 1 {
		fmt.Println("You must specify a URL")
		os.Exit(1)
	}

	url = flag.Args()[0]

	test, testerr := goad.NewTest(&goad.TestConfig{
		URL:            url,
		Concurrency:    concurrency,
		TotalRequests:  requests,
		RequestTimeout: time.Duration(timeout) * time.Second,
		Region:         region,
	})
	if testerr != nil {
		fmt.Println(testerr)
		os.Exit(1)
	}

	var finalResult queue.RegionsAggData
	defer printSummary(&finalResult)

	sigChan := make(chan os.Signal, 1)
	signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM) // but interrupts from kbd are blocked by termbox

	start(test, &finalResult, sigChan)
}

func start(test *goad.Test, finalResult *queue.RegionsAggData, sigChan chan os.Signal) {
	err := termbox.Init()
	if err != nil {
		panic(err)
	}

	defer termbox.Close()

	resultChan := test.Start()
	termbox.Sync()
	renderString(0, 0, "Launching on AWS...", coldef, coldef)
	_, h := termbox.Size()
	renderString(0, h-1, "Press ctrl-c to interrupt", coldef, coldef)
	termbox.Flush()

	go func() {
		for {
			event := termbox.PollEvent()
			if event.Key == 3 {
				sigChan <- syscall.SIGINT
			}
		}
	}()

outer:
	for {
		select {
		case result, ok := <-resultChan:
			if !ok {
				break outer
			}
			//		result.Regions["eu-west-1"] = result.Regions["us-east-1"]
			// sort so that regions always appear in the same order
			var regions []string
			for key := range result.Regions {
				regions = append(regions, key)
			}
			sort.Strings(regions)
			y := 3
			totalReqs := 0
			for _, region := range regions {
				data := result.Regions[region]
				totalReqs += data.TotalReqs
				y = renderRegion(data, y)
				y++
			}

			y = 0
			percentDone := float64(totalReqs) / float64(result.TotalExpectedRequests)
			drawProgressBar(percentDone, y)

			termbox.Flush()
			finalResult.Regions = result.Regions

		case <-sigChan:
			break outer
		}
	}
}

// renderRegion returns the y for the next empty line
func renderRegion(data queue.AggData, y int) int {
	x := 0
	renderString(x, y, "Region: ", termbox.ColorWhite, termbox.ColorBlue)
	x += 8
	regionStr := fmt.Sprintf("%-10s", data.Region)
	renderString(x, y, regionStr, termbox.ColorWhite|termbox.AttrBold, termbox.ColorBlue)
	x = 0
	y++
	headingStr := "   TotReqs   TotBytes    AveTime   AveReq/s Ave1stByte"
	renderString(x, y, headingStr, coldef|termbox.AttrBold, coldef)
	y++
	resultStr := fmt.Sprintf("%10d %10d   %7.2fs %10.2f   %7.2fs", data.TotalReqs, data.TotBytesRead, float64(data.AveTimeForReq)/nano, data.AveReqPerSec, float64(data.AveTimeToFirst)/nano)
	renderString(x, y, resultStr, coldef, coldef)
	y++
	headingStr = "   Slowest    Fastest     Errors"
	renderString(x, y, headingStr, coldef|termbox.AttrBold, coldef)
	y++
	resultStr = fmt.Sprintf("   %7.2f    %7.2f %10d", float64(data.Slowest)/nano, float64(data.Fastest)/nano, totErrors(&data))
	renderString(x, y, resultStr, coldef, coldef)
	y++

	return y
}

func totErrors(data *queue.AggData) int {
	var okReqs int
	for statusStr, value := range data.Statuses {
		status, _ := strconv.Atoi(statusStr)
		if status >= 200 && status <= 299 {
			okReqs += value
		}
	}
	return data.TotalReqs - okReqs
}

func drawProgressBar(percent float64, y int) {
	x := 0
	percentStr := fmt.Sprintf("%5.1f%%            ", percent*100)
	renderString(x, y, percentStr, coldef, coldef)
	y++

	hashes := int(percent * 50)
	if percent > 0.98 {
		hashes = 50
	}
	renderString(x, y, "[", coldef, coldef)

	for x++; x <= hashes; x++ {
		renderString(x, y, "#", coldef, coldef)
	}
	renderString(51, y, "]", coldef, coldef)
}

func renderString(x int, y int, str string, f termbox.Attribute, b termbox.Attribute) {
	for i, c := range str {
		termbox.SetCell(x+i, y, c, f, b)
	}
}

func boldPrintln(msg string) {
	fmt.Printf("\033[1m%s\033[0m\n", msg)
}

func printSummary(result *queue.RegionsAggData) {
	if len(result.Regions) == 0 {
		boldPrintln("No results received")
		return
	}
	boldPrintln("Regional results")
	fmt.Println("")

	for region, data := range result.Regions {
		fmt.Println("Region: " + region)
		boldPrintln("   TotReqs   TotBytes    AveTime   AveReq/s Ave1stByte")
		fmt.Printf("%10d %10d   %7.2fs %10.2f   %7.2fs\n", data.TotalReqs, data.TotBytesRead, float64(data.AveTimeForReq)/nano, data.AveReqPerSec, float64(data.AveTimeToFirst)/nano)
		boldPrintln("   Slowest    Fastest     Errors")
		fmt.Printf("   %7.2f    %7.2f %10d", float64(data.Slowest)/nano, float64(data.Fastest)/nano, totErrors(&data))
		fmt.Println("")
	}

	overall := queue.SumRegionResults(result)

	fmt.Println("")
	boldPrintln("Overall")
	fmt.Println("")
	boldPrintln("   TotReqs   TotBytes    AveTime   AveReq/s Ave1stByte")
	fmt.Printf("%10d %10d   %7.2fs %10.2f   %7.2fs\n", overall.TotalReqs, overall.TotBytesRead, float64(overall.AveTimeForReq)/nano, overall.AveReqPerSec, float64(overall.AveTimeToFirst)/nano)
	boldPrintln("   Slowest    Fastest     Errors")
	fmt.Printf("   %7.2f    %7.2f %10d", float64(overall.Slowest)/nano, float64(overall.Fastest)/nano, totErrors(overall))
	fmt.Println("")

	boldPrintln("HTTPStatus   Requests")
	for statusStr, value := range overall.Statuses {
		fmt.Printf("%10s %10d\n", statusStr, value)
	}
	fmt.Println("")
}
<commit_msg>Hardcode ReportingFrequency for now<commit_after>package main

import (
	"flag"
	"fmt"
	"os"
	"os/signal"
	"sort"
	"strconv"
	"syscall"
	"time"

	"github.com/gophergala2016/goad"
	"github.com/gophergala2016/goad/Godeps/_workspace/src/github.com/nsf/termbox-go"
	"github.com/gophergala2016/goad/queue"
)

var (
	url         string
	concurrency uint
	requests    uint
	timeout     uint
	region      string
)

const coldef = termbox.ColorDefault
const nano = 1000000000

func main() {
	flag.UintVar(&concurrency, "c", 10, "number of concurrent requests")
	flag.UintVar(&requests, "n", 1000, "number of total requests to make")
	flag.UintVar(&timeout, "t", 15, "request timeout in seconds")
	flag.StringVar(&region, "r", "us-east-1", "AWS region")
	flag.Parse()

	if len(flag.Args()) < 1 {
		fmt.Println("You must specify a URL")
		os.Exit(1)
	}

	url = flag.Args()[0]

	test, testerr := goad.NewTest(&goad.TestConfig{
		URL:                url,
		Concurrency:        concurrency,
		TotalRequests:      requests,
		RequestTimeout:     time.Duration(timeout) * time.Second,
		Region:             region,
		ReportingFrequency: 1,
	})
	if testerr != nil {
		fmt.Println(testerr)
		os.Exit(1)
	}

	var finalResult queue.RegionsAggData
	defer printSummary(&finalResult)

	sigChan := make(chan os.Signal, 1)
	signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM) // but interrupts from kbd are blocked by termbox

	start(test, &finalResult, sigChan)
}

func start(test *goad.Test, finalResult *queue.RegionsAggData, sigChan chan os.Signal) {
	err := termbox.Init()
	if err != nil {
		panic(err)
	}

	defer termbox.Close()

	resultChan := test.Start()
	termbox.Sync()
	renderString(0, 0, "Launching on AWS...", coldef, coldef)
	_, h := termbox.Size()
	renderString(0, h-1, "Press ctrl-c to interrupt", coldef, coldef)
	termbox.Flush()

	go func() {
		for {
			event := termbox.PollEvent()
			if event.Key == 3 {
				sigChan <- syscall.SIGINT
			}
		}
	}()

outer:
	for {
		select {
		case result, ok := <-resultChan:
			if !ok {
				break outer
			}
			//		result.Regions["eu-west-1"] = result.Regions["us-east-1"]
			// sort so that regions always appear in the same order
			var regions []string
			for key := range result.Regions {
				regions = append(regions, key)
			}
			sort.Strings(regions)
			y := 3
			totalReqs := 0
			for _, region := range regions {
				data := result.Regions[region]
				totalReqs += data.TotalReqs
				y = renderRegion(data, y)
				y++
			}

			y = 0
			percentDone := float64(totalReqs) / float64(result.TotalExpectedRequests)
			drawProgressBar(percentDone, y)

			termbox.Flush()
			finalResult.Regions = result.Regions

		case <-sigChan:
			break outer
		}
	}
}

// renderRegion returns the y for the next empty line
func renderRegion(data queue.AggData, y int) int {
	x := 0
	renderString(x, y, "Region: ", termbox.ColorWhite, termbox.ColorBlue)
	x += 8
	regionStr := fmt.Sprintf("%-10s", data.Region)
	renderString(x, y, regionStr, termbox.ColorWhite|termbox.AttrBold, termbox.ColorBlue)
	x = 0
	y++
	headingStr := "   TotReqs   TotBytes    AveTime   AveReq/s Ave1stByte"
	renderString(x, y, headingStr, coldef|termbox.AttrBold, coldef)
	y++
	resultStr := fmt.Sprintf("%10d %10d   %7.2fs %10.2f   %7.2fs", data.TotalReqs, data.TotBytesRead, float64(data.AveTimeForReq)/nano, data.AveReqPerSec, float64(data.AveTimeToFirst)/nano)
	renderString(x, y, resultStr, coldef, coldef)
	y++
	headingStr = "   Slowest    Fastest     Errors"
	renderString(x, y, headingStr, coldef|termbox.AttrBold, coldef)
	y++
	resultStr = fmt.Sprintf("   %7.2f    %7.2f %10d", float64(data.Slowest)/nano, float64(data.Fastest)/nano, totErrors(&data))
	renderString(x, y, resultStr, coldef, coldef)
	y++

	return y
}

func totErrors(data *queue.AggData) int {
	var okReqs int
	for statusStr, value := range data.Statuses {
		status, _ := strconv.Atoi(statusStr)
		if status >= 200 && status <= 299 {
			okReqs += value
		}
	}
	return data.TotalReqs - okReqs
}

func drawProgressBar(percent float64, y int) {
	x := 0
	percentStr := fmt.Sprintf("%5.1f%%            ", percent*100)
	renderString(x, y, percentStr, coldef, coldef)
	y++

	hashes := int(percent * 50)
	if percent > 0.98 {
		hashes = 50
	}
	renderString(x, y, "[", coldef, coldef)

	for x++; x <= hashes; x++ {
		renderString(x, y, "#", coldef, coldef)
	}
	renderString(51, y, "]", coldef, coldef)
}

func renderString(x int, y int, str string, f termbox.Attribute, b termbox.Attribute) {
	for i, c := range str {
		termbox.SetCell(x+i, y, c, f, b)
	}
}

func boldPrintln(msg string) {
	fmt.Printf("\033[1m%s\033[0m\n", msg)
}

func printSummary(result *queue.RegionsAggData) {
	if len(result.Regions) == 0 {
		boldPrintln("No results received")
		return
	}
	boldPrintln("Regional results")
	fmt.Println("")

	for region, data := range result.Regions {
		fmt.Println("Region: " + region)
		boldPrintln("   TotReqs   TotBytes    AveTime   AveReq/s Ave1stByte")
		fmt.Printf("%10d %10d   %7.2fs %10.2f   %7.2fs\n", data.TotalReqs, data.TotBytesRead, float64(data.AveTimeForReq)/nano, data.AveReqPerSec, float64(data.AveTimeToFirst)/nano)
		boldPrintln("   Slowest    Fastest     Errors")
		fmt.Printf("   %7.2f    %7.2f %10d", float64(data.Slowest)/nano, float64(data.Fastest)/nano, totErrors(&data))
		fmt.Println("")
	}

	overall := queue.SumRegionResults(result)

	fmt.Println("")
	boldPrintln("Overall")
	fmt.Println("")
	boldPrintln("   TotReqs   TotBytes    AveTime   AveReq/s Ave1stByte")
	fmt.Printf("%10d %10d   %7.2fs %10.2f   %7.2fs\n", overall.TotalReqs, overall.TotBytesRead, float64(overall.AveTimeForReq)/nano, overall.AveReqPerSec, float64(overall.AveTimeToFirst)/nano)
	boldPrintln("   Slowest    Fastest     Errors")
	fmt.Printf("   %7.2f    %7.2f %10d", float64(overall.Slowest)/nano, float64(overall.Fastest)/nano, totErrors(overall))
	fmt.Println("")

	boldPrintln("HTTPStatus   Requests")
	for statusStr, value := range overall.Statuses {
		fmt.Printf("%10s %10d\n", statusStr, value)
	}
	fmt.Println("")
}
<|endoftext|>


<commit_before>// Package cli provides all methods to control command line functions
package cli

import (
	"encoding/json"
	"fmt"
	"github.com/mehrdadrad/mylg/banner"
	"gopkg.in/readline.v1"
	"io/ioutil"
	"net/http"
	"regexp"
	"strconv"
	"strings"
)

const usage = `Usage:
	The myLG tool developed to troubleshoot networking situations.
	The vi/emacs mode,almost all basic features is supported. press tab to see what options are available.

	connect <provider name>     connects to external looking glass, press tab to see the menu
	node <city/country name>    connects to specific node at current looking glass, press tab to see the available nodes
	local                       back to local
	lg                          change mode to external looking glass
	ns                          change mode to name server looking up
	ping                        ping ip address or domain name
	dig                         name server looking up
	whois                       resolve AS number/IP/CIDR to holder (provides by ripe ncc)
	hping                       Ping through HTTP/HTTPS w/ GET/HEAD methods
	scan                        scan tcp ports (you can provide range >scan host minport maxport)
	dump                        prints out a description of the contents of packets on a network interface
	disc                        discover all the devices on a LAN
	peering                     peering information (provides by peeringdb.com)
	web                         web dashboard - opens dashboard at your default browser
	`

// Readline structure
type Readline struct {
	instance  *readline.Instance
	completer *readline.PrefixCompleter
	prompt    string
	next      chan struct{}
}

var (
	// CMDReg holds validation command regex
	CMDReg, _ = regexp.Compile(
		`(ping|trace|bgp|lg|ns|dig|dump|disc|whois|peering|scan|hping|connect|node|local|mode|help|web|show|set|exit|quit)\s{0,1}(.*)`)
)

// Init set readline imain items
func Init(prompt, version string) *Readline {
	var (
		r         Readline
		err       error
		completer = readline.NewPrefixCompleter(
			readline.PcItem("ping"),
			readline.PcItem("trace"),
			readline.PcItem("bgp"),
			readline.PcItem("hping"),
			readline.PcItem("connect"),
			readline.PcItem("node"),
			readline.PcItem("local"),
			readline.PcItem("lg"),
			readline.PcItem("ns"),
			readline.PcItem("dig"),
			readline.PcItem("whois"),
			readline.PcItem("scan"),
			readline.PcItem("dump"),
			readline.PcItem("disc"),
			readline.PcItem("peering"),
			readline.PcItem("help"),
			readline.PcItem("web"),
			readline.PcItem("set"),
			readline.PcItem("exit"),
			readline.PcItem("show",
				readline.PcItem("config"),
			),
		)
	)
	r.completer = completer
	r.instance, err = readline.NewEx(&readline.Config{
		Prompt:          prompt + "> ",
		HistoryFile:     "/tmp/myping",
		InterruptPrompt: "^C",
		EOFPrompt:       "exit",
		AutoComplete:    completer,
	})
	if err != nil {
		panic(err)
	}
	banner.Println(version) // print banner
	go checkUpdate(version) // check update version
	r.prompt = prompt       // init local prompt
	return &r
}

// RemoveItemCompleter removes subitem(s) from a specific main item
func (r *Readline) RemoveItemCompleter(pcItem string) {
	child := []readline.PrefixCompleterInterface{}
	for _, p := range r.completer.Children {
		if strings.TrimSpace(string(p.GetName())) != pcItem {
			child = append(child, p)
		}
	}

	r.completer.Children = child

}

// AddCompleter updates subitem(s) from a specific main item
func (r *Readline) AddCompleter(pcItem string, pcSubItems []string) {
	var pc readline.PrefixCompleter
	c := []readline.PrefixCompleterInterface{}
	for _, item := range pcSubItems {
		c = append(c, readline.PcItem(item))
	}
	pc.Name = []rune(pcItem + " ")
	pc.Children = c
	r.completer.Children = append(r.completer.Children, &pc)
}

// UpdateCompleter updates subitem(s) from a specific main item
func (r *Readline) UpdateCompleter(pcItem string, pcSubItems []string) {
	child := []readline.PrefixCompleterInterface{}
	var pc readline.PrefixCompleter
	for _, p := range r.completer.Children {
		if strings.TrimSpace(string(p.GetName())) == pcItem {
			c := []readline.PrefixCompleterInterface{}
			for _, item := range pcSubItems {
				c = append(c, readline.PcItem(item))
			}
			pc.Name = []rune(pcItem + " ")
			pc.Children = c
			child = append(child, &pc)
		} else {
			child = append(child, p)
		}
	}
	if len(pc.Name) < 1 {
		// todo adding new
	}
	r.completer.Children = child
}

// SetPrompt set readline prompt and store it
func (r *Readline) SetPrompt(p string) {
	p = strings.ToLower(p)
	r.prompt = p
	r.instance.SetPrompt(p + "> ")
}

// UpdatePromptN appends readline prompt
func (r *Readline) UpdatePromptN(p string, n int) {
	var parts []string
	p = strings.ToLower(p)
	parts = strings.SplitAfterN(r.prompt, "/", n)
	if n <= len(parts) && n > -1 {
		parts[n-1] = p
		r.prompt = strings.Join(parts, "")
	} else {
		r.prompt += "/" + p
	}
	r.instance.SetPrompt(r.prompt + "> ")
}

// GetPrompt returns the current prompt string
func (r *Readline) GetPrompt() string {
	return r.prompt
}

// Refresh prompt
func (r *Readline) Refresh() {
	r.instance.Refresh()
}

// SetVim set mode to vim
func (r *Readline) SetVim() {
	if !r.instance.IsVimMode() {
		r.instance.SetVimMode(true)
		println("mode changed to vim")
	} else {
		println("mode already is vim")
	}
}

// SetEmacs set mode to emacs
func (r *Readline) SetEmacs() {
	if r.instance.IsVimMode() {
		r.instance.SetVimMode(false)
		println("mode changed to emacs")
	} else {
		println("mode already is emacs")
	}
}

// Next trigers to read next line
func (r *Readline) Next() {
	r.next <- struct{}{}
}

// Run the main loop
func (r *Readline) Run(cmd chan<- string, next chan struct{}) {
	r.next = next
	defer close(cmd)

	for {
		line, err := r.instance.Readline()
		if err != nil { // io.EOF, readline.ErrInterrupt
			break
		}
		cmd <- line
		if _, ok := <-next; !ok {
			break
		}
	}
}

// Close the readline instance
func (r *Readline) Close(next chan struct{}) {
	r.instance.Close()
}

// Help print out the main help
func (r *Readline) Help() {
	fmt.Println(usage)
}

// checkUpdate checks if any new version is available
func checkUpdate(version string) {
	type mylg struct {
		Version string
	}
	var appCtl mylg

	if version == "test" {
		return
	}

	resp, err := http.Get("http://mylg.io/appctl/mylg")
	if err != nil {
		println("error: check update has been failed ")
		return
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		println("error: check update has been failed (2)" + err.Error())
		return
	}
	err = json.Unmarshal(body, &appCtl)
	if err != nil {
		return
	}
	if version != appCtl.Version {
		fmt.Printf("New version is available (v%s) at http://mylg.io/download\n", appCtl.Version)
	}
}

//Flag parses the command arguments syntax:
// -flag=x
// -flag x
// help
func Flag(args string) (string, map[string]interface{}) {
	var (
		r      = make(map[string]interface{}, 10)
		err    error
		target string
	)

	args = strings.TrimSpace(args)
	// target
	re := regexp.MustCompile(`(?i)^[^-][\S|\w]*`)
	t := re.FindStringSubmatch(args)
	if len(t) > 0 {
		target = t[0]
	}
	// range
	re = regexp.MustCompile(`(?i)\s-([a-z|0-9]+)[=|\s]{0,1}(\d+\-\d+)`)
	f := re.FindAllStringSubmatch(args, -1)
	for _, kv := range f {
		r[kv[1]] = kv[2]
		args = strings.Replace(args, kv[0], "", 1)
	}
	// other flags
	re = regexp.MustCompile(`(?i)\s{0,1}-([a-z|0-9]+)[=|\s]{0,1}([0-9|a-z|'"{}:\/]*)`)
	f = re.FindAllStringSubmatch(args, -1)
	for _, kv := range f {
		if len(kv) > 1 {
			// trim extra characters (' and ") from value
			kv[2] = strings.Trim(kv[2], "'")
			kv[2] = strings.Trim(kv[2], `"`)
			r[kv[1]], err = strconv.Atoi(kv[2])
			if err != nil {
				r[kv[1]] = kv[2]
			}
		}
	}
	// help
	if m, _ := regexp.MatchString(`(?i)help$`, args); m {
		r["help"] = true
	}

	return target, r
}

// SetFlag returns command option(s)
func SetFlag(flag map[string]interface{}, option string, v interface{}) interface{} {
	if sValue, ok := flag[option]; ok {
		switch v.(type) {
		case int:
			return sValue.(int)
		case string:
			switch sValue.(type) {
			case string:
				return sValue.(string)
			case int:
				str := strconv.FormatInt(int64(sValue.(int)), 10)
				return str
			case float64:
				str := strconv.FormatFloat(sValue.(float64), 'f', -1, 64)
				return str
			}
		case bool:
			return !v.(bool)
		default:
			return sValue.(string)
		}
	}
	return v
}
<commit_msg>handle interrupt error<commit_after>// Package cli provides all methods to control command line functions
package cli

import (
	"encoding/json"
	"fmt"
	"github.com/mehrdadrad/mylg/banner"
	"gopkg.in/readline.v1"
	"io"
	"io/ioutil"
	"net/http"
	"regexp"
	"strconv"
	"strings"
)

const usage = `Usage:
	The myLG tool developed to troubleshoot networking situations.
	The vi/emacs mode,almost all basic features is supported. press tab to see what options are available.

	connect <provider name>     connects to external looking glass, press tab to see the menu
	node <city/country name>    connects to specific node at current looking glass, press tab to see the available nodes
	local                       back to local
	lg                          change mode to external looking glass
	ns                          change mode to name server looking up
	ping                        ping ip address or domain name
	dig                         name server looking up
	whois                       resolve AS number/IP/CIDR to holder (provides by ripe ncc)
	hping                       Ping through HTTP/HTTPS w/ GET/HEAD methods
	scan                        scan tcp ports (you can provide range >scan host minport maxport)
	dump                        prints out a description of the contents of packets on a network interface
	disc                        discover all the devices on a LAN
	peering                     peering information (provides by peeringdb.com)
	web                         web dashboard - opens dashboard at your default browser
	`

// Readline structure
type Readline struct {
	instance  *readline.Instance
	completer *readline.PrefixCompleter
	prompt    string
	next      chan struct{}
}

var (
	// CMDReg holds validation command regex
	CMDReg, _ = regexp.Compile(
		`(ping|trace|bgp|lg|ns|dig|dump|disc|whois|peering|scan|hping|connect|node|local|mode|help|web|show|set|exit|quit)\s{0,1}(.*)`)
)

// Init set readline imain items
func Init(prompt, version string) *Readline {
	var (
		r         Readline
		err       error
		completer = readline.NewPrefixCompleter(
			readline.PcItem("ping"),
			readline.PcItem("trace"),
			readline.PcItem("bgp"),
			readline.PcItem("hping"),
			readline.PcItem("connect"),
			readline.PcItem("node"),
			readline.PcItem("local"),
			readline.PcItem("lg"),
			readline.PcItem("ns"),
			readline.PcItem("dig"),
			readline.PcItem("whois"),
			readline.PcItem("scan"),
			readline.PcItem("dump"),
			readline.PcItem("disc"),
			readline.PcItem("peering"),
			readline.PcItem("help"),
			readline.PcItem("web"),
			readline.PcItem("set"),
			readline.PcItem("exit"),
			readline.PcItem("show",
				readline.PcItem("config"),
			),
		)
	)
	r.completer = completer
	r.instance, err = readline.NewEx(&readline.Config{
		Prompt:          prompt + "> ",
		HistoryFile:     "/tmp/myping",
		InterruptPrompt: "^C",
		EOFPrompt:       "exit",
		AutoComplete:    completer,
	})
	if err != nil {
		panic(err)
	}
	banner.Println(version) // print banner
	go checkUpdate(version) // check update version
	r.prompt = prompt       // init local prompt
	return &r
}

// RemoveItemCompleter removes subitem(s) from a specific main item
func (r *Readline) RemoveItemCompleter(pcItem string) {
	child := []readline.PrefixCompleterInterface{}
	for _, p := range r.completer.Children {
		if strings.TrimSpace(string(p.GetName())) != pcItem {
			child = append(child, p)
		}
	}

	r.completer.Children = child

}

// AddCompleter updates subitem(s) from a specific main item
func (r *Readline) AddCompleter(pcItem string, pcSubItems []string) {
	var pc readline.PrefixCompleter
	c := []readline.PrefixCompleterInterface{}
	for _, item := range pcSubItems {
		c = append(c, readline.PcItem(item))
	}
	pc.Name = []rune(pcItem + " ")
	pc.Children = c
	r.completer.Children = append(r.completer.Children, &pc)
}

// UpdateCompleter updates subitem(s) from a specific main item
func (r *Readline) UpdateCompleter(pcItem string, pcSubItems []string) {
	child := []readline.PrefixCompleterInterface{}
	var pc readline.PrefixCompleter
	for _, p := range r.completer.Children {
		if strings.TrimSpace(string(p.GetName())) == pcItem {
			c := []readline.PrefixCompleterInterface{}
			for _, item := range pcSubItems {
				c = append(c, readline.PcItem(item))
			}
			pc.Name = []rune(pcItem + " ")
			pc.Children = c
			child = append(child, &pc)
		} else {
			child = append(child, p)
		}
	}
	if len(pc.Name) < 1 {
		// todo adding new
	}
	r.completer.Children = child
}

// SetPrompt set readline prompt and store it
func (r *Readline) SetPrompt(p string) {
	p = strings.ToLower(p)
	r.prompt = p
	r.instance.SetPrompt(p + "> ")
}

// UpdatePromptN appends readline prompt
func (r *Readline) UpdatePromptN(p string, n int) {
	var parts []string
	p = strings.ToLower(p)
	parts = strings.SplitAfterN(r.prompt, "/", n)
	if n <= len(parts) && n > -1 {
		parts[n-1] = p
		r.prompt = strings.Join(parts, "")
	} else {
		r.prompt += "/" + p
	}
	r.instance.SetPrompt(r.prompt + "> ")
}

// GetPrompt returns the current prompt string
func (r *Readline) GetPrompt() string {
	return r.prompt
}

// Refresh prompt
func (r *Readline) Refresh() {
	r.instance.Refresh()
}

// SetVim set mode to vim
func (r *Readline) SetVim() {
	if !r.instance.IsVimMode() {
		r.instance.SetVimMode(true)
		println("mode changed to vim")
	} else {
		println("mode already is vim")
	}
}

// SetEmacs set mode to emacs
func (r *Readline) SetEmacs() {
	if r.instance.IsVimMode() {
		r.instance.SetVimMode(false)
		println("mode changed to emacs")
	} else {
		println("mode already is emacs")
	}
}

// Next trigers to read next line
func (r *Readline) Next() {
	r.next <- struct{}{}
}

// Run the main loop
func (r *Readline) Run(cmd chan<- string, next chan struct{}) {
	r.next = next
	defer close(cmd)

LOOP:
	for {
		line, err := r.instance.Readline()
		if err != nil { // io.EOF, readline.ErrInterrupt
			switch err {
			case io.EOF:
				break LOOP
			case readline.ErrInterrupt:
			default:
				println(err.Error())
				break LOOP
			}
		}
		cmd <- line
		if _, ok := <-next; !ok {
			break
		}
	}
}

// Close the readline instance
func (r *Readline) Close(next chan struct{}) {
	r.instance.Close()
}

// Help print out the main help
func (r *Readline) Help() {
	fmt.Println(usage)
}

// checkUpdate checks if any new version is available
func checkUpdate(version string) {
	type mylg struct {
		Version string
	}
	var appCtl mylg

	if version == "test" {
		return
	}

	resp, err := http.Get("http://mylg.io/appctl/mylg")
	if err != nil {
		println("error: check update has been failed ")
		return
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		println("error: check update has been failed (2)" + err.Error())
		return
	}
	err = json.Unmarshal(body, &appCtl)
	if err != nil {
		return
	}
	if version != appCtl.Version {
		fmt.Printf("New version is available (v%s) at http://mylg.io/download\n", appCtl.Version)
	}
}

//Flag parses the command arguments syntax:
// -flag=x
// -flag x
// help
func Flag(args string) (string, map[string]interface{}) {
	var (
		r      = make(map[string]interface{}, 10)
		err    error
		target string
	)

	args = strings.TrimSpace(args)
	// target
	re := regexp.MustCompile(`(?i)^[^-][\S|\w]*`)
	t := re.FindStringSubmatch(args)
	if len(t) > 0 {
		target = t[0]
	}
	// range
	re = regexp.MustCompile(`(?i)\s-([a-z|0-9]+)[=|\s]{0,1}(\d+\-\d+)`)
	f := re.FindAllStringSubmatch(args, -1)
	for _, kv := range f {
		r[kv[1]] = kv[2]
		args = strings.Replace(args, kv[0], "", 1)
	}
	// other flags
	re = regexp.MustCompile(`(?i)\s{0,1}-([a-z|0-9]+)[=|\s]{0,1}([0-9|a-z|'"{}:\/]*)`)
	f = re.FindAllStringSubmatch(args, -1)
	for _, kv := range f {
		if len(kv) > 1 {
			// trim extra characters (' and ") from value
			kv[2] = strings.Trim(kv[2], "'")
			kv[2] = strings.Trim(kv[2], `"`)
			r[kv[1]], err = strconv.Atoi(kv[2])
			if err != nil {
				r[kv[1]] = kv[2]
			}
		}
	}
	// help
	if m, _ := regexp.MatchString(`(?i)help$`, args); m {
		r["help"] = true
	}

	return target, r
}

// SetFlag returns command option(s)
func SetFlag(flag map[string]interface{}, option string, v interface{}) interface{} {
	if sValue, ok := flag[option]; ok {
		switch v.(type) {
		case int:
			return sValue.(int)
		case string:
			switch sValue.(type) {
			case string:
				return sValue.(string)
			case int:
				str := strconv.FormatInt(int64(sValue.(int)), 10)
				return str
			case float64:
				str := strconv.FormatFloat(sValue.(float64), 'f', -1, 64)
				return str
			}
		case bool:
			return !v.(bool)
		default:
			return sValue.(string)
		}
	}
	return v
}
<|endoftext|>


<commit_before>package cli

import (
	"fmt"
	"os"
	"path"

	log "github.com/Sirupsen/logrus"
	"github.com/bitrise-io/stepman/stepman"
	"github.com/codegangsta/cli"
)

func before(c *cli.Context) error {
	// Log level
	if logLevel, err := log.ParseLevel(c.String(LogLevelKey)); err != nil {
		log.Fatal("[BITRISE_CLI] - Failed to parse log level:", err)
	} else {
		log.SetLevel(logLevel)
	}

	// Setup
	err := stepman.CreateStepManDirIfNeeded()
	if err != nil {
		return err
	}

	// Debug mode
	stepman.DebugMode = c.Bool(DebugKey)
	return nil
}

func printVersion(c *cli.Context) {
	fmt.Fprintf(c.App.Writer, "%v\n", c.App.Version)
}

// Run ...
func Run() {
	cli.VersionPrinter = printVersion

	app := cli.NewApp()
	app.Name = path.Base(os.Args[0])
	app.Usage = "Step manager"
	app.Version = "0.9.7"

	app.Author = ""
	app.Email = ""

	app.Before = before

	app.Flags = flags
	app.Commands = commands

	if err := app.Run(os.Args); err != nil {
		log.Error("[STEPMAN] - Stepman finished:", err)
	}
}
<commit_msg>start of v0.9.8<commit_after>package cli

import (
	"fmt"
	"os"
	"path"

	log "github.com/Sirupsen/logrus"
	"github.com/bitrise-io/stepman/stepman"
	"github.com/codegangsta/cli"
)

func before(c *cli.Context) error {
	// Log level
	if logLevel, err := log.ParseLevel(c.String(LogLevelKey)); err != nil {
		log.Fatal("[BITRISE_CLI] - Failed to parse log level:", err)
	} else {
		log.SetLevel(logLevel)
	}

	// Setup
	err := stepman.CreateStepManDirIfNeeded()
	if err != nil {
		return err
	}

	// Debug mode
	stepman.DebugMode = c.Bool(DebugKey)
	return nil
}

func printVersion(c *cli.Context) {
	fmt.Fprintf(c.App.Writer, "%v\n", c.App.Version)
}

// Run ...
func Run() {
	cli.VersionPrinter = printVersion

	app := cli.NewApp()
	app.Name = path.Base(os.Args[0])
	app.Usage = "Step manager"
	app.Version = "0.9.8"

	app.Author = ""
	app.Email = ""

	app.Before = before

	app.Flags = flags
	app.Commands = commands

	if err := app.Run(os.Args); err != nil {
		log.Error("[STEPMAN] - Stepman finished:", err)
	}
}
<|endoftext|>


<commit_before>package cli

import (
	"os/exec"
	"strings"
	"os"
	"runtime"
	"github.com/axgle/mahonia"
	"io/ioutil"
	"fmt"
	"github.com/pkg/errors"
)

var exitWithOutZero = errors.New("Has not run command exit code with 0")

type CmdTea struct {
	ErrorInfo  error
	ChartSet   string
	CmdStrings string
	IsSuccess  bool
	Pid        int
	TeaState   string
	Out        string
	Err        string

	Env       []string
	ShellPath string
	Dir       string
	Args      []string
}

func getSystem() string {
	return runtime.GOOS
}

func IsSysWindows() bool {
	return getSystem() == "windows"
}

// chartSet "" default in windows "gbk", other is "utf-8"
// return isSuccess bool PID processState string and cmdOut string
func (ct *CmdTea) CmdTeaInit(chartSet string, cmd ...string) {
	cmdStr := make([]string, 8)
	for i, ct := range cmd {
		trim := strings.Trim(ct, " ")
		cmdStr[i] = trim
	}
	cmdString := strings.Join(cmdStr, " ")
	ct.ChartSet = chartSet
	ct.CmdStrings = cmdString
}

func (ct CmdTea) CmdTeaRun() (bool, CmdTea) {
	if ct.CmdStrings == "" {
		ct.ErrorInfo = errors.New("You Cmd is Empty!")
		return false, ct

	}
	var c *exec.Cmd
	if IsSysWindows() {
		argArray := strings.Split("/c "+ct.CmdStrings, " ")
		c = exec.Command("cmd", argArray...)
	} else {
		c = exec.Command("/bin/sh", "-c", ct.CmdStrings)
	}
	stdout, err := c.StdoutPipe()
	stdErr, stderrErr := c.StderrPipe()
	c.Start()

	content, err := ioutil.ReadAll(stdout)
	contentErr, stderrErr := ioutil.ReadAll(stdErr)
	ct.Env = c.Env
	ct.ShellPath = c.Path
	ct.Dir = c.Dir
	ct.Args = c.Args

	if err != nil {
		ct.IsSuccess = false
		ct.ErrorInfo = err
		return false, ct
	}
	if stderrErr != nil {
		ct.IsSuccess = false
		ct.ErrorInfo = stderrErr
		return false, ct
	}
	var processState os.ProcessState
	c.ProcessState = &processState
	processPid := processState.Pid()
	ct.Pid = processPid
	processStateStr := processState.String()
	ct.TeaState = processStateStr
	var dec mahonia.Decoder
	if ct.ChartSet == "" {
		if IsSysWindows() {
			ct.ChartSet = "gbk"
		} else {
			ct.ChartSet = "utf-8"
		}
	}
	dec = mahonia.NewDecoder(ct.ChartSet)
	processOut := string(content)
	processErr := string(contentErr)
	if len(contentErr) > 0 {
		ct.IsSuccess = false
		ct.Err = dec.ConvertString(processErr)
		ct.ErrorInfo = exitWithOutZero
		return false, ct
	} else {
		ct.IsSuccess = true
		ct.Out = dec.ConvertString(processOut)
		return true, ct
	}
}

func CmdExec(chartSet string, cmd ...string) (bool, int, string, string) {
	var c *exec.Cmd
	cmdStr := make([]string, 8)
	for i, ct := range cmd {
		trim := strings.Trim(ct, " ")
		cmdStr[i] = trim
	}
	cmdString := strings.Join(cmdStr, " ")

	if IsSysWindows() {
		argArray := strings.Split("/c "+cmdString, " ")
		c = exec.Command("cmd", argArray...)
	} else {
		c = exec.Command("/bin/sh", "-c", cmdString)
	}

	var cmdOut string
	//c.Stderr = os.Stderr do not set
	out, err := c.CombinedOutput()
	var processState os.ProcessState
	c.ProcessState = &processState
	processSuccess := processState.Success()
	processPid := processState.Pid()
	processStateStr := processState.String()
	cmdOut = string(out)
	if IsSysWindows() {
		if chartSet == "" {
			chartSet = "gbk"
		}
		dec := mahonia.NewDecoder(chartSet)
		cmdOut = dec.ConvertString(cmdOut)
	}
	if err != nil {
		return false, processPid, err.Error(), cmdOut
	}
	return processSuccess, processPid, processStateStr, cmdOut
}

func (ct *CmdTea) CmdTea(chartSet string, cmd ...string) (bool, error) {
	var c *exec.Cmd
	cmdStr := make([]string, 8)
	for i, ct := range cmd {
		trim := strings.Trim(ct, " ")
		cmdStr[i] = trim
	}
	cmdString := strings.Join(cmdStr, " ")

	if IsSysWindows() {
		argArray := strings.Split("/c "+cmdString, " ")
		c = exec.Command("cmd", argArray...)
	} else {
		c = exec.Command("/bin/sh", "-c", cmdString)
	}
	stdout, err := c.StdoutPipe() //指向cmd命令的stdout
	stdErr, stderrErr := c.StderrPipe()
	c.Start()

	content, err := ioutil.ReadAll(stdout)
	contentErr, stderrErr := ioutil.ReadAll(stdErr)
	if err != nil {
		ct.IsSuccess = false
		return false, err
	}
	if stderrErr != nil {
		ct.IsSuccess = false
		return false, stderrErr
	}
	var processState os.ProcessState
	c.ProcessState = &processState
	processPid := processState.Pid()
	ct.Pid = processPid
	processStateStr := processState.String()
	var dec mahonia.Decoder
	if chartSet == "" {
		if IsSysWindows() {
			chartSet = "gbk"
		} else {
			chartSet = "utf-8"
		}
	}
	dec = mahonia.NewDecoder(chartSet)
	processOut := string(content)
	processErr := string(contentErr)
	if len(contentErr) > 0 {
		ct.IsSuccess = false
		ct.TeaState = processStateStr
		ct.Err = dec.ConvertString(processErr)
		return false, nil
	} else {
		ct.IsSuccess = true
		ct.TeaState = processStateStr
		ct.Out = dec.ConvertString(processOut)
		return true, nil
	}
}

func CmdRun(chartSet string, cmd ...string) (bool, error) {
	var c *exec.Cmd
	cmdStr := make([]string, 8)
	for i, ct := range cmd {
		trim := strings.Trim(ct, " ")
		cmdStr[i] = trim
	}
	cmdString := strings.Join(cmdStr, " ")

	if IsSysWindows() {
		argArray := strings.Split("/c "+cmdString, " ")
		c = exec.Command("cmd", argArray...)
	} else {
		c = exec.Command("/bin/sh", "-c", cmdString)
	}
	if chartSet == "" {
		if IsSysWindows() {
			chartSet = "gbk"
		} else {
			chartSet = "utf-8"
		}
	}
	dec := mahonia.NewDecoder(chartSet)
	stdout, err := c.StdoutPipe() //指向cmd命令的stdout
	stdErr, stderrErr := c.StderrPipe()
	c.Start()
	content, err := ioutil.ReadAll(stdout)
	contentErr, stderrErr := ioutil.ReadAll(stdErr)
	if err != nil {
		fmt.Println(err)
		return false, err
	}
	if stderrErr != nil {
		fmt.Println(stderrErr)
		return false, stderrErr
	}
	if len(contentErr) > 0 {
		fmt.Println(Red(dec.ConvertString(string(contentErr))))
		return false, exitWithOutZero
	} else {
		fmt.Println(dec.ConvertString(string(content)))
		return true, nil
	}
}
<commit_msg>remove useless code<commit_after>package cli

import (
	"os/exec"
	"strings"
	"os"
	"runtime"
	"github.com/axgle/mahonia"
	"io/ioutil"
	"fmt"
	"github.com/pkg/errors"
)

var exitWithOutZero = errors.New("Has not run command exit code with 0")

type CmdTea struct {
	ErrorInfo  error
	ChartSet   string
	CmdStrings string
	IsSuccess  bool
	Pid        int
	TeaState   string
	Out        string
	Err        string

	Env       []string
	ShellPath string
	Dir       string
	Args      []string
}

func getSystem() string {
	return runtime.GOOS
}

func IsSysWindows() bool {
	return getSystem() == "windows"
}

// chartSet "" default in windows "gbk", other is "utf-8"
// return isSuccess bool PID processState string and cmdOut string
func (ct *CmdTea) CmdTeaInit(chartSet string, cmd ...string) {
	cmdStr := make([]string, 8)
	for i, ct := range cmd {
		trim := strings.Trim(ct, " ")
		cmdStr[i] = trim
	}
	cmdString := strings.Join(cmdStr, " ")
	ct.ChartSet = chartSet
	ct.CmdStrings = cmdString
}

func (ct CmdTea) CmdTeaRun() (bool, CmdTea) {
	if ct.CmdStrings == "" {
		ct.ErrorInfo = errors.New("You Cmd is Empty!")
		return false, ct

	}
	var c *exec.Cmd
	if IsSysWindows() {
		argArray := strings.Split("/c "+ct.CmdStrings, " ")
		c = exec.Command("cmd", argArray...)
	} else {
		c = exec.Command("/bin/sh", "-c", ct.CmdStrings)
	}
	stdout, err := c.StdoutPipe()
	stdErr, stderrErr := c.StderrPipe()
	c.Start()

	content, err := ioutil.ReadAll(stdout)
	contentErr, stderrErr := ioutil.ReadAll(stdErr)
	ct.Env = c.Env
	ct.ShellPath = c.Path
	ct.Dir = c.Dir
	ct.Args = c.Args

	if err != nil {
		ct.IsSuccess = false
		ct.ErrorInfo = err
		return false, ct
	}
	if stderrErr != nil {
		ct.IsSuccess = false
		ct.ErrorInfo = stderrErr
		return false, ct
	}
	var processState os.ProcessState
	c.ProcessState = &processState
	processPid := processState.Pid()
	ct.Pid = processPid
	processStateStr := processState.String()
	ct.TeaState = processStateStr
	var dec mahonia.Decoder
	if ct.ChartSet == "" {
		if IsSysWindows() {
			ct.ChartSet = "gbk"
		} else {
			ct.ChartSet = "utf-8"
		}
	}
	dec = mahonia.NewDecoder(ct.ChartSet)
	processOut := string(content)
	processErr := string(contentErr)
	if len(contentErr) > 0 {
		ct.IsSuccess = false
		ct.Err = dec.ConvertString(processErr)
		ct.ErrorInfo = exitWithOutZero
		return false, ct
	} else {
		ct.IsSuccess = true
		ct.Out = dec.ConvertString(processOut)
		return true, ct
	}
}

func CmdExec(chartSet string, cmd ...string) (bool, int, string, string) {
	var c *exec.Cmd
	cmdStr := make([]string, 8)
	for i, ct := range cmd {
		trim := strings.Trim(ct, " ")
		cmdStr[i] = trim
	}
	cmdString := strings.Join(cmdStr, " ")

	if IsSysWindows() {
		argArray := strings.Split("/c "+cmdString, " ")
		c = exec.Command("cmd", argArray...)
	} else {
		c = exec.Command("/bin/sh", "-c", cmdString)
	}

	var cmdOut string
	//c.Stderr = os.Stderr do not set
	out, err := c.CombinedOutput()
	var processState os.ProcessState
	c.ProcessState = &processState
	processSuccess := processState.Success()
	processPid := processState.Pid()
	processStateStr := processState.String()
	cmdOut = string(out)
	if IsSysWindows() {
		if chartSet == "" {
			chartSet = "gbk"
		}
		dec := mahonia.NewDecoder(chartSet)
		cmdOut = dec.ConvertString(cmdOut)
	}
	if err != nil {
		return false, processPid, err.Error(), cmdOut
	}
	return processSuccess, processPid, processStateStr, cmdOut
}

func CmdRun(chartSet string, cmd ...string) (bool, error) {
	var c *exec.Cmd
	cmdStr := make([]string, 8)
	for i, ct := range cmd {
		trim := strings.Trim(ct, " ")
		cmdStr[i] = trim
	}
	cmdString := strings.Join(cmdStr, " ")

	if IsSysWindows() {
		argArray := strings.Split("/c "+cmdString, " ")
		c = exec.Command("cmd", argArray...)
	} else {
		c = exec.Command("/bin/sh", "-c", cmdString)
	}
	if chartSet == "" {
		if IsSysWindows() {
			chartSet = "gbk"
		} else {
			chartSet = "utf-8"
		}
	}
	dec := mahonia.NewDecoder(chartSet)
	stdout, err := c.StdoutPipe() //指向cmd命令的stdout
	stdErr, stderrErr := c.StderrPipe()
	c.Start()
	content, err := ioutil.ReadAll(stdout)
	contentErr, stderrErr := ioutil.ReadAll(stdErr)
	if err != nil {
		fmt.Println(err)
		return false, err
	}
	if stderrErr != nil {
		fmt.Println(stderrErr)
		return false, stderrErr
	}
	if len(contentErr) > 0 {
		fmt.Println(Red(dec.ConvertString(string(contentErr))))
		return false, exitWithOutZero
	} else {
		fmt.Println(dec.ConvertString(string(content)))
		return true, nil
	}
}
<|endoftext|>