libgo patch committed: Remove old exp packages

Ian Lance Taylor iant@golang.org
Wed Jan 10 15:41:00 GMT 2018


This libgo patch removes the exp/proxy and exp/terminal packages.

The exp/proxy package was removed from the master library in
https://golang.org/cl/6461056 (August, 2012).

The exp/terminal package was removed from the master library in
https://golang.org/cl/5970044 (March, 2012).

I'm not sure why they lingered in the gofrontend copy, but let's
finally remove them now.

Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu.  Committed
to mainline.

Ian
-------------- next part --------------
Index: gcc/go/gofrontend/MERGE
===================================================================
--- gcc/go/gofrontend/MERGE	(revision 256433)
+++ gcc/go/gofrontend/MERGE	(working copy)
@@ -1,4 +1,4 @@
-87df767807acac466edb3bb6445ad83a48141d17
+4b8036b3f995cdb0b99a9fa26c2af1e2420b4fa2
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
Index: libgo/Makefile.am
===================================================================
--- libgo/Makefile.am	(revision 256366)
+++ libgo/Makefile.am	(working copy)
@@ -235,12 +235,6 @@ toolexeclibgoencoding_DATA = \
 	encoding/pem.gox \
 	encoding/xml.gox
 
-toolexeclibgoexpdir = $(toolexeclibgodir)/exp
-
-toolexeclibgoexp_DATA = \
-	exp/proxy.gox \
-	exp/terminal.gox
-
 toolexeclibgogodir = $(toolexeclibgodir)/go
 
 toolexeclibgogo_DATA = \
@@ -759,8 +753,6 @@ PACKAGES = \
 	encoding/pem \
 	encoding/xml \
 	errors \
-	exp/proxy \
-	exp/terminal \
 	expvar \
 	flag \
 	fmt \
@@ -1066,7 +1058,6 @@ CHECK_DEPS = \
 	$(toolexeclibgocrypto_DATA) \
 	$(toolexeclibgodebug_DATA) \
 	$(toolexeclibgoencoding_DATA) \
-	$(toolexeclibgoexp_DATA) \
 	$(toolexeclibgogo_DATA) \
 	$(toolexeclibgohash_DATA) \
 	$(toolexeclibgoimage_DATA) \
@@ -1352,8 +1343,6 @@ TEST_PACKAGES = \
 	encoding/json/check \
 	encoding/pem/check \
 	encoding/xml/check \
-	exp/proxy/check \
-	exp/terminal/check \
 	html/template/check \
 	go/ast/check \
 	go/build/check \
Index: libgo/go/exp/README
===================================================================
--- libgo/go/exp/README	(revision 256366)
+++ libgo/go/exp/README	(nonexistent)
@@ -1,3 +0,0 @@
-This directory tree contains experimental packages and
-unfinished code that is subject to even more change than the
-rest of the Go tree.
Index: libgo/go/exp/proxy/direct.go
===================================================================
--- libgo/go/exp/proxy/direct.go	(revision 256366)
+++ libgo/go/exp/proxy/direct.go	(nonexistent)
@@ -1,18 +0,0 @@
-// 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 proxy
-
-import (
-	"net"
-)
-
-type direct struct{}
-
-// Direct is a direct proxy: one that makes network connections directly.
-var Direct = direct{}
-
-func (direct) Dial(network, addr string) (net.Conn, error) {
-	return net.Dial(network, addr)
-}
Index: libgo/go/exp/proxy/per_host.go
===================================================================
--- libgo/go/exp/proxy/per_host.go	(revision 256366)
+++ libgo/go/exp/proxy/per_host.go	(nonexistent)
@@ -1,140 +0,0 @@
-// 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 proxy
-
-import (
-	"net"
-	"strings"
-)
-
-// A PerHost directs connections to a default Dailer unless the hostname
-// requested matches one of a number of exceptions.
-type PerHost struct {
-	def, bypass Dialer
-
-	bypassNetworks []*net.IPNet
-	bypassIPs      []net.IP
-	bypassZones    []string
-	bypassHosts    []string
-}
-
-// NewPerHost returns a PerHost Dialer that directs connections to either
-// defaultDialer or bypass, depending on whether the connection matches one of
-// the configured rules.
-func NewPerHost(defaultDialer, bypass Dialer) *PerHost {
-	return &PerHost{
-		def:    defaultDialer,
-		bypass: bypass,
-	}
-}
-
-// Dial connects to the address addr on the network net through either
-// defaultDialer or bypass.
-func (p *PerHost) Dial(network, addr string) (c net.Conn, err error) {
-	host, _, err := net.SplitHostPort(addr)
-	if err != nil {
-		return nil, err
-	}
-
-	return p.dialerForRequest(host).Dial(network, addr)
-}
-
-func (p *PerHost) dialerForRequest(host string) Dialer {
-	if ip := net.ParseIP(host); ip != nil {
-		for _, net := range p.bypassNetworks {
-			if net.Contains(ip) {
-				return p.bypass
-			}
-		}
-		for _, bypassIP := range p.bypassIPs {
-			if bypassIP.Equal(ip) {
-				return p.bypass
-			}
-		}
-		return p.def
-	}
-
-	for _, zone := range p.bypassZones {
-		if strings.HasSuffix(host, zone) {
-			return p.bypass
-		}
-		if host == zone[1:] {
-			// For a zone "example.com", we match "example.com"
-			// too.
-			return p.bypass
-		}
-	}
-	for _, bypassHost := range p.bypassHosts {
-		if bypassHost == host {
-			return p.bypass
-		}
-	}
-	return p.def
-}
-
-// AddFromString parses a string that contains comma-separated values
-// specifying hosts that should use the bypass proxy. Each value is either an
-// IP address, a CIDR range, a zone (*.example.com) or a hostname
-// (localhost). A best effort is made to parse the string and errors are
-// ignored.
-func (p *PerHost) AddFromString(s string) {
-	hosts := strings.Split(s, ",")
-	for _, host := range hosts {
-		host = strings.TrimSpace(host)
-		if len(host) == 0 {
-			continue
-		}
-		if strings.Contains(host, "/") {
-			// We assume that it's a CIDR address like 127.0.0.0/8
-			if _, net, err := net.ParseCIDR(host); err == nil {
-				p.AddNetwork(net)
-			}
-			continue
-		}
-		if ip := net.ParseIP(host); ip != nil {
-			p.AddIP(ip)
-			continue
-		}
-		if strings.HasPrefix(host, "*.") {
-			p.AddZone(host[1:])
-			continue
-		}
-		p.AddHost(host)
-	}
-}
-
-// AddIP specifies an IP address that will use the bypass proxy. Note that
-// this will only take effect if a literal IP address is dialed. A connection
-// to a named host will never match an IP.
-func (p *PerHost) AddIP(ip net.IP) {
-	p.bypassIPs = append(p.bypassIPs, ip)
-}
-
-// AddIP specifies an IP range that will use the bypass proxy. Note that this
-// will only take effect if a literal IP address is dialed. A connection to a
-// named host will never match.
-func (p *PerHost) AddNetwork(net *net.IPNet) {
-	p.bypassNetworks = append(p.bypassNetworks, net)
-}
-
-// AddZone specifies a DNS suffix that will use the bypass proxy. A zone of
-// "example.com" matches "example.com" and all of its subdomains.
-func (p *PerHost) AddZone(zone string) {
-	if strings.HasSuffix(zone, ".") {
-		zone = zone[:len(zone)-1]
-	}
-	if !strings.HasPrefix(zone, ".") {
-		zone = "." + zone
-	}
-	p.bypassZones = append(p.bypassZones, zone)
-}
-
-// AddHost specifies a hostname that will use the bypass proxy.
-func (p *PerHost) AddHost(host string) {
-	if strings.HasSuffix(host, ".") {
-		host = host[:len(host)-1]
-	}
-	p.bypassHosts = append(p.bypassHosts, host)
-}
Index: libgo/go/exp/proxy/per_host_test.go
===================================================================
--- libgo/go/exp/proxy/per_host_test.go	(revision 256366)
+++ libgo/go/exp/proxy/per_host_test.go	(nonexistent)
@@ -1,55 +0,0 @@
-// 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 proxy
-
-import (
-	"errors"
-	"net"
-	"reflect"
-	"testing"
-)
-
-type recordingProxy struct {
-	addrs []string
-}
-
-func (r *recordingProxy) Dial(network, addr string) (net.Conn, error) {
-	r.addrs = append(r.addrs, addr)
-	return nil, errors.New("recordingProxy")
-}
-
-func TestPerHost(t *testing.T) {
-	var def, bypass recordingProxy
-	perHost := NewPerHost(&def, &bypass)
-	perHost.AddFromString("localhost,*.zone,127.0.0.1,10.0.0.1/8,1000::/16")
-
-	expectedDef := []string{
-		"example.com:123",
-		"1.2.3.4:123",
-		"[1001::]:123",
-	}
-	expectedBypass := []string{
-		"localhost:123",
-		"zone:123",
-		"foo.zone:123",
-		"127.0.0.1:123",
-		"10.1.2.3:123",
-		"[1000::]:123",
-	}
-
-	for _, addr := range expectedDef {
-		perHost.Dial("tcp", addr)
-	}
-	for _, addr := range expectedBypass {
-		perHost.Dial("tcp", addr)
-	}
-
-	if !reflect.DeepEqual(expectedDef, def.addrs) {
-		t.Errorf("Hosts which went to the default proxy didn't match. Got %v, want %v", def.addrs, expectedDef)
-	}
-	if !reflect.DeepEqual(expectedBypass, bypass.addrs) {
-		t.Errorf("Hosts which went to the bypass proxy didn't match. Got %v, want %v", bypass.addrs, expectedBypass)
-	}
-}
Index: libgo/go/exp/proxy/proxy.go
===================================================================
--- libgo/go/exp/proxy/proxy.go	(revision 256366)
+++ libgo/go/exp/proxy/proxy.go	(nonexistent)
@@ -1,94 +0,0 @@
-// 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 proxy provides support for a variety of protocols to proxy network
-// data.
-package proxy
-
-import (
-	"errors"
-	"net"
-	"net/url"
-	"os"
-)
-
-// A Dialer is a means to establish a connection.
-type Dialer interface {
-	// Dial connects to the given address via the proxy.
-	Dial(network, addr string) (c net.Conn, err error)
-}
-
-// Auth contains authentication parameters that specific Dialers may require.
-type Auth struct {
-	User, Password string
-}
-
-// DefaultDialer returns the dialer specified by the proxy related variables in
-// the environment.
-func FromEnvironment() Dialer {
-	allProxy := os.Getenv("all_proxy")
-	if len(allProxy) == 0 {
-		return Direct
-	}
-
-	proxyURL, err := url.Parse(allProxy)
-	if err != nil {
-		return Direct
-	}
-	proxy, err := FromURL(proxyURL, Direct)
-	if err != nil {
-		return Direct
-	}
-
-	noProxy := os.Getenv("no_proxy")
-	if len(noProxy) == 0 {
-		return proxy
-	}
-
-	perHost := NewPerHost(proxy, Direct)
-	perHost.AddFromString(noProxy)
-	return perHost
-}
-
-// proxySchemes is a map from URL schemes to a function that creates a Dialer
-// from a URL with such a scheme.
-var proxySchemes map[string]func(*url.URL, Dialer) (Dialer, error)
-
-// RegisterDialerType takes a URL scheme and a function to generate Dialers from
-// a URL with that scheme and a forwarding Dialer. Registered schemes are used
-// by FromURL.
-func RegisterDialerType(scheme string, f func(*url.URL, Dialer) (Dialer, error)) {
-	if proxySchemes == nil {
-		proxySchemes = make(map[string]func(*url.URL, Dialer) (Dialer, error))
-	}
-	proxySchemes[scheme] = f
-}
-
-// FromURL returns a Dialer given a URL specification and an underlying
-// Dialer for it to make network requests.
-func FromURL(u *url.URL, forward Dialer) (Dialer, error) {
-	var auth *Auth
-	if u.User != nil {
-		auth = new(Auth)
-		auth.User = u.User.Username()
-		if p, ok := u.User.Password(); ok {
-			auth.Password = p
-		}
-	}
-
-	switch u.Scheme {
-	case "socks5":
-		return SOCKS5("tcp", u.Host, auth, forward)
-	}
-
-	// If the scheme doesn't match any of the built-in schemes, see if it
-	// was registered by another package.
-	if proxySchemes != nil {
-		if f, ok := proxySchemes[u.Scheme]; ok {
-			return f(u, forward)
-		}
-	}
-
-	return nil, errors.New("proxy: unknown scheme: " + u.Scheme)
-}
Index: libgo/go/exp/proxy/proxy_test.go
===================================================================
--- libgo/go/exp/proxy/proxy_test.go	(revision 256366)
+++ libgo/go/exp/proxy/proxy_test.go	(nonexistent)
@@ -1,50 +0,0 @@
-// 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 proxy
-
-import (
-	"net"
-	"net/url"
-	"testing"
-)
-
-type testDialer struct {
-	network, addr string
-}
-
-func (t *testDialer) Dial(network, addr string) (net.Conn, error) {
-	t.network = network
-	t.addr = addr
-	return nil, t
-}
-
-func (t *testDialer) Error() string {
-	return "testDialer " + t.network + " " + t.addr
-}
-
-func TestFromURL(t *testing.T) {
-	u, err := url.Parse("socks5://user:password@1.2.3.4:5678")
-	if err != nil {
-		t.Fatalf("failed to parse URL: %s", err)
-	}
-
-	tp := &testDialer{}
-	proxy, err := FromURL(u, tp)
-	if err != nil {
-		t.Fatalf("FromURL failed: %s", err)
-	}
-
-	conn, err := proxy.Dial("tcp", "example.com:80")
-	if conn != nil {
-		t.Error("Dial unexpected didn't return an error")
-	}
-	if tp, ok := err.(*testDialer); ok {
-		if tp.network != "tcp" || tp.addr != "1.2.3.4:5678" {
-			t.Errorf("Dialer connected to wrong host. Wanted 1.2.3.4:5678, got: %v", tp)
-		}
-	} else {
-		t.Errorf("Unexpected error from Dial: %s", err)
-	}
-}
Index: libgo/go/exp/proxy/socks5.go
===================================================================
--- libgo/go/exp/proxy/socks5.go	(revision 256366)
+++ libgo/go/exp/proxy/socks5.go	(nonexistent)
@@ -1,207 +0,0 @@
-// 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 proxy
-
-import (
-	"errors"
-	"io"
-	"net"
-	"strconv"
-)
-
-// SOCKS5 returns a Dialer that makes SOCKSv5 connections to the given address
-// with an optional username and password. See RFC 1928.
-func SOCKS5(network, addr string, auth *Auth, forward Dialer) (Dialer, error) {
-	s := &socks5{
-		network: network,
-		addr:    addr,
-		forward: forward,
-	}
-	if auth != nil {
-		s.user = auth.User
-		s.password = auth.Password
-	}
-
-	return s, nil
-}
-
-type socks5 struct {
-	user, password string
-	network, addr  string
-	forward        Dialer
-}
-
-const socks5Version = 5
-
-const (
-	socks5AuthNone     = 0
-	socks5AuthPassword = 2
-)
-
-const socks5Connect = 1
-
-const (
-	socks5IP4    = 1
-	socks5Domain = 3
-	socks5IP6    = 4
-)
-
-var socks5Errors = []string{
-	"",
-	"general failure",
-	"connection forbidden",
-	"network unreachable",
-	"host unreachable",
-	"connection refused",
-	"TTL expired",
-	"command not supported",
-	"address type not supported",
-}
-
-// Dial connects to the address addr on the network net via the SOCKS5 proxy.
-func (s *socks5) Dial(network, addr string) (net.Conn, error) {
-	switch network {
-	case "tcp", "tcp6", "tcp4":
-		break
-	default:
-		return nil, errors.New("proxy: no support for SOCKS5 proxy connections of type " + network)
-	}
-
-	conn, err := s.forward.Dial(s.network, s.addr)
-	if err != nil {
-		return nil, err
-	}
-	closeConn := &conn
-	defer func() {
-		if closeConn != nil {
-			(*closeConn).Close()
-		}
-	}()
-
-	host, portStr, err := net.SplitHostPort(addr)
-	if err != nil {
-		return nil, err
-	}
-
-	port, err := strconv.Atoi(portStr)
-	if err != nil {
-		return nil, errors.New("proxy: failed to parse port number: " + portStr)
-	}
-	if port < 1 || port > 0xffff {
-		return nil, errors.New("proxy: port number out of range: " + portStr)
-	}
-
-	// the size here is just an estimate
-	buf := make([]byte, 0, 6+len(host))
-
-	buf = append(buf, socks5Version)
-	if len(s.user) > 0 && len(s.user) < 256 && len(s.password) < 256 {
-		buf = append(buf, 2 /* num auth methods */, socks5AuthNone, socks5AuthPassword)
-	} else {
-		buf = append(buf, 1 /* num auth methods */, socks5AuthNone)
-	}
-
-	if _, err = conn.Write(buf); err != nil {
-		return nil, errors.New("proxy: failed to write greeting to SOCKS5 proxy at " + s.addr + ": " + err.Error())
-	}
-
-	if _, err = io.ReadFull(conn, buf[:2]); err != nil {
-		return nil, errors.New("proxy: failed to read greeting from SOCKS5 proxy at " + s.addr + ": " + err.Error())
-	}
-	if buf[0] != 5 {
-		return nil, errors.New("proxy: SOCKS5 proxy at " + s.addr + " has unexpected version " + strconv.Itoa(int(buf[0])))
-	}
-	if buf[1] == 0xff {
-		return nil, errors.New("proxy: SOCKS5 proxy at " + s.addr + " requires authentication")
-	}
-
-	if buf[1] == socks5AuthPassword {
-		buf = buf[:0]
-		buf = append(buf, socks5Version)
-		buf = append(buf, uint8(len(s.user)))
-		buf = append(buf, s.user...)
-		buf = append(buf, uint8(len(s.password)))
-		buf = append(buf, s.password...)
-
-		if _, err = conn.Write(buf); err != nil {
-			return nil, errors.New("proxy: failed to write authentication request to SOCKS5 proxy at " + s.addr + ": " + err.Error())
-		}
-
-		if _, err = io.ReadFull(conn, buf[:2]); err != nil {
-			return nil, errors.New("proxy: failed to read authentication reply from SOCKS5 proxy at " + s.addr + ": " + err.Error())
-		}
-
-		if buf[1] != 0 {
-			return nil, errors.New("proxy: SOCKS5 proxy at " + s.addr + " rejected username/password")
-		}
-	}
-
-	buf = buf[:0]
-	buf = append(buf, socks5Version, socks5Connect, 0 /* reserved */)
-
-	if ip := net.ParseIP(host); ip != nil {
-		if len(ip) == 4 {
-			buf = append(buf, socks5IP4)
-		} else {
-			buf = append(buf, socks5IP6)
-		}
-		buf = append(buf, []byte(ip)...)
-	} else {
-		buf = append(buf, socks5Domain)
-		buf = append(buf, byte(len(host)))
-		buf = append(buf, host...)
-	}
-	buf = append(buf, byte(port>>8), byte(port))
-
-	if _, err = conn.Write(buf); err != nil {
-		return nil, errors.New("proxy: failed to write connect request to SOCKS5 proxy at " + s.addr + ": " + err.Error())
-	}
-
-	if _, err = io.ReadFull(conn, buf[:4]); err != nil {
-		return nil, errors.New("proxy: failed to read connect reply from SOCKS5 proxy at " + s.addr + ": " + err.Error())
-	}
-
-	failure := "unknown error"
-	if int(buf[1]) < len(socks5Errors) {
-		failure = socks5Errors[buf[1]]
-	}
-
-	if len(failure) > 0 {
-		return nil, errors.New("proxy: SOCKS5 proxy at " + s.addr + " failed to connect: " + failure)
-	}
-
-	bytesToDiscard := 0
-	switch buf[3] {
-	case socks5IP4:
-		bytesToDiscard = 4
-	case socks5IP6:
-		bytesToDiscard = 16
-	case socks5Domain:
-		_, err := io.ReadFull(conn, buf[:1])
-		if err != nil {
-			return nil, errors.New("proxy: failed to read domain length from SOCKS5 proxy at " + s.addr + ": " + err.Error())
-		}
-		bytesToDiscard = int(buf[0])
-	default:
-		return nil, errors.New("proxy: got unknown address type " + strconv.Itoa(int(buf[3])) + " from SOCKS5 proxy at " + s.addr)
-	}
-
-	if cap(buf) < bytesToDiscard {
-		buf = make([]byte, bytesToDiscard)
-	} else {
-		buf = buf[:bytesToDiscard]
-	}
-	if _, err = io.ReadFull(conn, buf); err != nil {
-		return nil, errors.New("proxy: failed to read address from SOCKS5 proxy at " + s.addr + ": " + err.Error())
-	}
-
-	// Also need to discard the port number
-	if _, err = io.ReadFull(conn, buf[:2]); err != nil {
-		return nil, errors.New("proxy: failed to read port from SOCKS5 proxy at " + s.addr + ": " + err.Error())
-	}
-
-	closeConn = nil
-	return conn, nil
-}
Index: libgo/go/exp/terminal/terminal.go
===================================================================
--- libgo/go/exp/terminal/terminal.go	(revision 256366)
+++ libgo/go/exp/terminal/terminal.go	(nonexistent)
@@ -1,520 +0,0 @@
-// 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 terminal
-
-import (
-	"io"
-	"sync"
-)
-
-// EscapeCodes contains escape sequences that can be written to the terminal in
-// order to achieve different styles of text.
-type EscapeCodes struct {
-	// Foreground colors
-	Black, Red, Green, Yellow, Blue, Magenta, Cyan, White []byte
-
-	// Reset all attributes
-	Reset []byte
-}
-
-var vt100EscapeCodes = EscapeCodes{
-	Black:   []byte{keyEscape, '[', '3', '0', 'm'},
-	Red:     []byte{keyEscape, '[', '3', '1', 'm'},
-	Green:   []byte{keyEscape, '[', '3', '2', 'm'},
-	Yellow:  []byte{keyEscape, '[', '3', '3', 'm'},
-	Blue:    []byte{keyEscape, '[', '3', '4', 'm'},
-	Magenta: []byte{keyEscape, '[', '3', '5', 'm'},
-	Cyan:    []byte{keyEscape, '[', '3', '6', 'm'},
-	White:   []byte{keyEscape, '[', '3', '7', 'm'},
-
-	Reset: []byte{keyEscape, '[', '0', 'm'},
-}
-
-// Terminal contains the state for running a VT100 terminal that is capable of
-// reading lines of input.
-type Terminal struct {
-	// AutoCompleteCallback, if non-null, is called for each keypress
-	// with the full input line and the current position of the cursor.
-	// If it returns a nil newLine, the key press is processed normally.
-	// Otherwise it returns a replacement line and the new cursor position.
-	AutoCompleteCallback func(line []byte, pos, key int) (newLine []byte, newPos int)
-
-	// Escape contains a pointer to the escape codes for this terminal.
-	// It's always a valid pointer, although the escape codes themselves
-	// may be empty if the terminal doesn't support them.
-	Escape *EscapeCodes
-
-	// lock protects the terminal and the state in this object from
-	// concurrent processing of a key press and a Write() call.
-	lock sync.Mutex
-
-	c      io.ReadWriter
-	prompt string
-
-	// line is the current line being entered.
-	line []byte
-	// pos is the logical position of the cursor in line
-	pos int
-	// echo is true if local echo is enabled
-	echo bool
-
-	// cursorX contains the current X value of the cursor where the left
-	// edge is 0. cursorY contains the row number where the first row of
-	// the current line is 0.
-	cursorX, cursorY int
-	// maxLine is the greatest value of cursorY so far.
-	maxLine int
-
-	termWidth, termHeight int
-
-	// outBuf contains the terminal data to be sent.
-	outBuf []byte
-	// remainder contains the remainder of any partial key sequences after
-	// a read. It aliases into inBuf.
-	remainder []byte
-	inBuf     [256]byte
-}
-
-// NewTerminal runs a VT100 terminal on the given ReadWriter. If the ReadWriter is
-// a local terminal, that terminal must first have been put into raw mode.
-// prompt is a string that is written at the start of each input line (i.e.
-// "> ").
-func NewTerminal(c io.ReadWriter, prompt string) *Terminal {
-	return &Terminal{
-		Escape:     &vt100EscapeCodes,
-		c:          c,
-		prompt:     prompt,
-		termWidth:  80,
-		termHeight: 24,
-		echo:       true,
-	}
-}
-
-const (
-	keyCtrlD     = 4
-	keyEnter     = '\r'
-	keyEscape    = 27
-	keyBackspace = 127
-	keyUnknown   = 256 + iota
-	keyUp
-	keyDown
-	keyLeft
-	keyRight
-	keyAltLeft
-	keyAltRight
-)
-
-// bytesToKey tries to parse a key sequence from b. If successful, it returns
-// the key and the remainder of the input. Otherwise it returns -1.
-func bytesToKey(b []byte) (int, []byte) {
-	if len(b) == 0 {
-		return -1, nil
-	}
-
-	if b[0] != keyEscape {
-		return int(b[0]), b[1:]
-	}
-
-	if len(b) >= 3 && b[0] == keyEscape && b[1] == '[' {
-		switch b[2] {
-		case 'A':
-			return keyUp, b[3:]
-		case 'B':
-			return keyDown, b[3:]
-		case 'C':
-			return keyRight, b[3:]
-		case 'D':
-			return keyLeft, b[3:]
-		}
-	}
-
-	if len(b) >= 6 && b[0] == keyEscape && b[1] == '[' && b[2] == '1' && b[3] == ';' && b[4] == '3' {
-		switch b[5] {
-		case 'C':
-			return keyAltRight, b[6:]
-		case 'D':
-			return keyAltLeft, b[6:]
-		}
-	}
-
-	// If we get here then we have a key that we don't recognise, or a
-	// partial sequence. It's not clear how one should find the end of a
-	// sequence without knowing them all, but it seems that [a-zA-Z] only
-	// appears at the end of a sequence.
-	for i, c := range b[0:] {
-		if c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' {
-			return keyUnknown, b[i+1:]
-		}
-	}
-
-	return -1, b
-}
-
-// queue appends data to the end of t.outBuf
-func (t *Terminal) queue(data []byte) {
-	t.outBuf = append(t.outBuf, data...)
-}
-
-var eraseUnderCursor = []byte{' ', keyEscape, '[', 'D'}
-var space = []byte{' '}
-
-func isPrintable(key int) bool {
-	return key >= 32 && key < 127
-}
-
-// moveCursorToPos appends data to t.outBuf which will move the cursor to the
-// given, logical position in the text.
-func (t *Terminal) moveCursorToPos(pos int) {
-	if !t.echo {
-		return
-	}
-
-	x := len(t.prompt) + pos
-	y := x / t.termWidth
-	x = x % t.termWidth
-
-	up := 0
-	if y < t.cursorY {
-		up = t.cursorY - y
-	}
-
-	down := 0
-	if y > t.cursorY {
-		down = y - t.cursorY
-	}
-
-	left := 0
-	if x < t.cursorX {
-		left = t.cursorX - x
-	}
-
-	right := 0
-	if x > t.cursorX {
-		right = x - t.cursorX
-	}
-
-	t.cursorX = x
-	t.cursorY = y
-	t.move(up, down, left, right)
-}
-
-func (t *Terminal) move(up, down, left, right int) {
-	movement := make([]byte, 3*(up+down+left+right))
-	m := movement
-	for i := 0; i < up; i++ {
-		m[0] = keyEscape
-		m[1] = '['
-		m[2] = 'A'
-		m = m[3:]
-	}
-	for i := 0; i < down; i++ {
-		m[0] = keyEscape
-		m[1] = '['
-		m[2] = 'B'
-		m = m[3:]
-	}
-	for i := 0; i < left; i++ {
-		m[0] = keyEscape
-		m[1] = '['
-		m[2] = 'D'
-		m = m[3:]
-	}
-	for i := 0; i < right; i++ {
-		m[0] = keyEscape
-		m[1] = '['
-		m[2] = 'C'
-		m = m[3:]
-	}
-
-	t.queue(movement)
-}
-
-func (t *Terminal) clearLineToRight() {
-	op := []byte{keyEscape, '[', 'K'}
-	t.queue(op)
-}
-
-const maxLineLength = 4096
-
-// handleKey processes the given key and, optionally, returns a line of text
-// that the user has entered.
-func (t *Terminal) handleKey(key int) (line string, ok bool) {
-	switch key {
-	case keyBackspace:
-		if t.pos == 0 {
-			return
-		}
-		t.pos--
-		t.moveCursorToPos(t.pos)
-
-		copy(t.line[t.pos:], t.line[1+t.pos:])
-		t.line = t.line[:len(t.line)-1]
-		if t.echo {
-			t.writeLine(t.line[t.pos:])
-		}
-		t.queue(eraseUnderCursor)
-		t.moveCursorToPos(t.pos)
-	case keyAltLeft:
-		// move left by a word.
-		if t.pos == 0 {
-			return
-		}
-		t.pos--
-		for t.pos > 0 {
-			if t.line[t.pos] != ' ' {
-				break
-			}
-			t.pos--
-		}
-		for t.pos > 0 {
-			if t.line[t.pos] == ' ' {
-				t.pos++
-				break
-			}
-			t.pos--
-		}
-		t.moveCursorToPos(t.pos)
-	case keyAltRight:
-		// move right by a word.
-		for t.pos < len(t.line) {
-			if t.line[t.pos] == ' ' {
-				break
-			}
-			t.pos++
-		}
-		for t.pos < len(t.line) {
-			if t.line[t.pos] != ' ' {
-				break
-			}
-			t.pos++
-		}
-		t.moveCursorToPos(t.pos)
-	case keyLeft:
-		if t.pos == 0 {
-			return
-		}
-		t.pos--
-		t.moveCursorToPos(t.pos)
-	case keyRight:
-		if t.pos == len(t.line) {
-			return
-		}
-		t.pos++
-		t.moveCursorToPos(t.pos)
-	case keyEnter:
-		t.moveCursorToPos(len(t.line))
-		t.queue([]byte("\r\n"))
-		line = string(t.line)
-		ok = true
-		t.line = t.line[:0]
-		t.pos = 0
-		t.cursorX = 0
-		t.cursorY = 0
-		t.maxLine = 0
-	default:
-		if t.AutoCompleteCallback != nil {
-			t.lock.Unlock()
-			newLine, newPos := t.AutoCompleteCallback(t.line, t.pos, key)
-			t.lock.Lock()
-
-			if newLine != nil {
-				if t.echo {
-					t.moveCursorToPos(0)
-					t.writeLine(newLine)
-					for i := len(newLine); i < len(t.line); i++ {
-						t.writeLine(space)
-					}
-					t.moveCursorToPos(newPos)
-				}
-				t.line = newLine
-				t.pos = newPos
-				return
-			}
-		}
-		if !isPrintable(key) {
-			return
-		}
-		if len(t.line) == maxLineLength {
-			return
-		}
-		if len(t.line) == cap(t.line) {
-			newLine := make([]byte, len(t.line), 2*(1+len(t.line)))
-			copy(newLine, t.line)
-			t.line = newLine
-		}
-		t.line = t.line[:len(t.line)+1]
-		copy(t.line[t.pos+1:], t.line[t.pos:])
-		t.line[t.pos] = byte(key)
-		if t.echo {
-			t.writeLine(t.line[t.pos:])
-		}
-		t.pos++
-		t.moveCursorToPos(t.pos)
-	}
-	return
-}
-
-func (t *Terminal) writeLine(line []byte) {
-	for len(line) != 0 {
-		remainingOnLine := t.termWidth - t.cursorX
-		todo := len(line)
-		if todo > remainingOnLine {
-			todo = remainingOnLine
-		}
-		t.queue(line[:todo])
-		t.cursorX += todo
-		line = line[todo:]
-
-		if t.cursorX == t.termWidth {
-			t.cursorX = 0
-			t.cursorY++
-			if t.cursorY > t.maxLine {
-				t.maxLine = t.cursorY
-			}
-		}
-	}
-}
-
-func (t *Terminal) Write(buf []byte) (n int, err error) {
-	t.lock.Lock()
-	defer t.lock.Unlock()
-
-	if t.cursorX == 0 && t.cursorY == 0 {
-		// This is the easy case: there's nothing on the screen that we
-		// have to move out of the way.
-		return t.c.Write(buf)
-	}
-
-	// We have a prompt and possibly user input on the screen. We
-	// have to clear it first.
-	t.move(0 /* up */, 0 /* down */, t.cursorX /* left */, 0 /* right */)
-	t.cursorX = 0
-	t.clearLineToRight()
-
-	for t.cursorY > 0 {
-		t.move(1 /* up */, 0, 0, 0)
-		t.cursorY--
-		t.clearLineToRight()
-	}
-
-	if _, err = t.c.Write(t.outBuf); err != nil {
-		return
-	}
-	t.outBuf = t.outBuf[:0]
-
-	if n, err = t.c.Write(buf); err != nil {
-		return
-	}
-
-	t.queue([]byte(t.prompt))
-	chars := len(t.prompt)
-	if t.echo {
-		t.queue(t.line)
-		chars += len(t.line)
-	}
-	t.cursorX = chars % t.termWidth
-	t.cursorY = chars / t.termWidth
-	t.moveCursorToPos(t.pos)
-
-	if _, err = t.c.Write(t.outBuf); err != nil {
-		return
-	}
-	t.outBuf = t.outBuf[:0]
-	return
-}
-
-// ReadPassword temporarily changes the prompt and reads a password, without
-// echo, from the terminal.
-func (t *Terminal) ReadPassword(prompt string) (line string, err error) {
-	t.lock.Lock()
-	defer t.lock.Unlock()
-
-	oldPrompt := t.prompt
-	t.prompt = prompt
-	t.echo = false
-
-	line, err = t.readLine()
-
-	t.prompt = oldPrompt
-	t.echo = true
-
-	return
-}
-
-// ReadLine returns a line of input from the terminal.
-func (t *Terminal) ReadLine() (line string, err error) {
-	t.lock.Lock()
-	defer t.lock.Unlock()
-
-	return t.readLine()
-}
-
-func (t *Terminal) readLine() (line string, err error) {
-	// t.lock must be held at this point
-
-	if t.cursorX == 0 && t.cursorY == 0 {
-		t.writeLine([]byte(t.prompt))
-		t.c.Write(t.outBuf)
-		t.outBuf = t.outBuf[:0]
-	}
-
-	for {
-		rest := t.remainder
-		lineOk := false
-		for !lineOk {
-			var key int
-			key, rest = bytesToKey(rest)
-			if key < 0 {
-				break
-			}
-			if key == keyCtrlD {
-				return "", io.EOF
-			}
-			line, lineOk = t.handleKey(key)
-		}
-		if len(rest) > 0 {
-			n := copy(t.inBuf[:], rest)
-			t.remainder = t.inBuf[:n]
-		} else {
-			t.remainder = nil
-		}
-		t.c.Write(t.outBuf)
-		t.outBuf = t.outBuf[:0]
-		if lineOk {
-			return
-		}
-
-		// t.remainder is a slice at the beginning of t.inBuf
-		// containing a partial key sequence
-		readBuf := t.inBuf[len(t.remainder):]
-		var n int
-
-		t.lock.Unlock()
-		n, err = t.c.Read(readBuf)
-		t.lock.Lock()
-
-		if err != nil {
-			return
-		}
-
-		t.remainder = t.inBuf[:n+len(t.remainder)]
-	}
-	panic("unreachable")
-}
-
-// SetPrompt sets the prompt to be used when reading subsequent lines.
-func (t *Terminal) SetPrompt(prompt string) {
-	t.lock.Lock()
-	defer t.lock.Unlock()
-
-	t.prompt = prompt
-}
-
-func (t *Terminal) SetSize(width, height int) {
-	t.lock.Lock()
-	defer t.lock.Unlock()
-
-	t.termWidth, t.termHeight = width, height
-}
Index: libgo/go/exp/terminal/terminal_test.go
===================================================================
--- libgo/go/exp/terminal/terminal_test.go	(revision 256366)
+++ libgo/go/exp/terminal/terminal_test.go	(nonexistent)
@@ -1,110 +0,0 @@
-// 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 terminal
-
-import (
-	"io"
-	"testing"
-)
-
-type MockTerminal struct {
-	toSend       []byte
-	bytesPerRead int
-	received     []byte
-}
-
-func (c *MockTerminal) Read(data []byte) (n int, err error) {
-	n = len(data)
-	if n == 0 {
-		return
-	}
-	if n > len(c.toSend) {
-		n = len(c.toSend)
-	}
-	if n == 0 {
-		return 0, io.EOF
-	}
-	if c.bytesPerRead > 0 && n > c.bytesPerRead {
-		n = c.bytesPerRead
-	}
-	copy(data, c.toSend[:n])
-	c.toSend = c.toSend[n:]
-	return
-}
-
-func (c *MockTerminal) Write(data []byte) (n int, err error) {
-	c.received = append(c.received, data...)
-	return len(data), nil
-}
-
-func TestClose(t *testing.T) {
-	c := &MockTerminal{}
-	ss := NewTerminal(c, "> ")
-	line, err := ss.ReadLine()
-	if line != "" {
-		t.Errorf("Expected empty line but got: %s", line)
-	}
-	if err != io.EOF {
-		t.Errorf("Error should have been EOF but got: %s", err)
-	}
-}
-
-var keyPressTests = []struct {
-	in   string
-	line string
-	err  error
-}{
-	{
-		"",
-		"",
-		io.EOF,
-	},
-	{
-		"\r",
-		"",
-		nil,
-	},
-	{
-		"foo\r",
-		"foo",
-		nil,
-	},
-	{
-		"a\x1b[Cb\r", // right
-		"ab",
-		nil,
-	},
-	{
-		"a\x1b[Db\r", // left
-		"ba",
-		nil,
-	},
-	{
-		"a\177b\r", // backspace
-		"b",
-		nil,
-	},
-}
-
-func TestKeyPresses(t *testing.T) {
-	for i, test := range keyPressTests {
-		for j := 0; j < len(test.in); j++ {
-			c := &MockTerminal{
-				toSend:       []byte(test.in),
-				bytesPerRead: j,
-			}
-			ss := NewTerminal(c, "> ")
-			line, err := ss.ReadLine()
-			if line != test.line {
-				t.Errorf("Line resulting from test %d (%d bytes per read) was '%s', expected '%s'", i, j, line, test.line)
-				break
-			}
-			if err != test.err {
-				t.Errorf("Error resulting from test %d (%d bytes per read) was '%v', expected '%v'", i, j, err, test.err)
-				break
-			}
-		}
-	}
-}
Index: libgo/go/exp/terminal/util.go
===================================================================
--- libgo/go/exp/terminal/util.go	(revision 256366)
+++ libgo/go/exp/terminal/util.go	(nonexistent)
@@ -1,118 +0,0 @@
-// 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.
-
-// +build linux
-
-// Package terminal provides support functions for dealing with terminals, as
-// commonly found on UNIX systems.
-//
-// Putting a terminal into raw mode is the most common requirement:
-//
-// 	oldState, err := terminal.MakeRaw(0)
-// 	if err != nil {
-// 	        panic(err)
-// 	}
-// 	defer terminal.Restore(0, oldState)
-package terminal
-
-import (
-	"io"
-	"syscall"
-	"unsafe"
-)
-
-// State contains the state of a terminal.
-type State struct {
-	termios syscall.Termios
-}
-
-// IsTerminal returns true if the given file descriptor is a terminal.
-func IsTerminal(fd int) bool {
-	var termios syscall.Termios
-	err := syscall.Tcgetattr(fd, &termios)
-	return err == nil
-}
-
-// MakeRaw put the terminal connected to the given file descriptor into raw
-// mode and returns the previous state of the terminal so that it can be
-// restored.
-func MakeRaw(fd int) (*State, error) {
-	var oldState State
-	if err := syscall.Tcgetattr(fd, &oldState.termios); err != nil {
-		return nil, err
-	}
-
-	newState := oldState.termios
-	newState.Iflag &^= syscall.ISTRIP | syscall.INLCR | syscall.ICRNL | syscall.IGNCR | syscall.IXON | syscall.IXOFF
-	newState.Lflag &^= syscall.ECHO | syscall.ICANON | syscall.ISIG
-	if err := syscall.Tcsetattr(fd, syscall.TCSANOW, &newState); err != nil {
-		return nil, err
-	}
-
-	return &oldState, nil
-}
-
-// Restore restores the terminal connected to the given file descriptor to a
-// previous state.
-func Restore(fd int, state *State) error {
-	err := syscall.Tcsetattr(fd, syscall.TCSANOW, &state.termios)
-	return err
-}
-
-//extern ioctl
-func ioctl(int, int, unsafe.Pointer) int
-
-// GetSize returns the dimensions of the given terminal.
-func GetSize(fd int) (width, height int, err error) {
-	var dimensions [4]uint16
-
-	if ioctl(fd, syscall.TIOCGWINSZ, unsafe.Pointer(&dimensions)) < 0 {
-		return -1, -1, syscall.GetErrno()
-	}
-	return int(dimensions[1]), int(dimensions[0]), nil
-}
-
-// ReadPassword reads a line of input from a terminal without local echo.  This
-// is commonly used for inputting passwords and other sensitive data. The slice
-// returned does not include the \n.
-func ReadPassword(fd int) ([]byte, error) {
-	var oldState syscall.Termios
-	if err := syscall.Tcgetattr(fd, &oldState); err != nil {
-		return nil, err
-	}
-
-	newState := oldState
-	newState.Lflag &^= syscall.ECHO
-	if err := syscall.Tcsetattr(fd, syscall.TCSANOW, &newState); err != nil {
-		return nil, err
-	}
-
-	defer func() {
-		syscall.Tcsetattr(fd, syscall.TCSANOW, &oldState)
-	}()
-
-	var buf [16]byte
-	var ret []byte
-	for {
-		n, err := syscall.Read(fd, buf[:])
-		if err != nil {
-			return nil, err
-		}
-		if n == 0 {
-			if len(ret) == 0 {
-				return nil, io.EOF
-			}
-			break
-		}
-		if buf[n-1] == '\n' {
-			n--
-		}
-		ret = append(ret, buf[:n]...)
-		if n < len(buf) {
-			break
-		}
-	}
-
-	return ret, nil
-}


More information about the Gcc-patches mailing list