libgo: Update to weekly.2012-03-22.

From-SVN: r186026
This commit is contained in:
Ian Lance Taylor 2012-03-30 22:09:55 +00:00
parent 57c7433fdc
commit 9a18821cfc
51 changed files with 612 additions and 168 deletions

View File

@ -1,4 +1,4 @@
3cdba7b0650c bce220d03774
The first line of this file holds the Mercurial revision number of the The first line of this file holds the Mercurial revision number of the
last merge done from the master library sources. last merge done from the master library sources.

View File

@ -7,10 +7,12 @@ package zip
import ( import (
"bytes" "bytes"
"encoding/binary" "encoding/binary"
"encoding/hex"
"io" "io"
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"regexp"
"testing" "testing"
"time" "time"
) )
@ -62,13 +64,14 @@ var tests = []ZipTest{
}, },
}, },
{ {
Name: "r.zip", Name: "r.zip",
Source: returnRecursiveZip,
File: []ZipTestFile{ File: []ZipTestFile{
{ {
Name: "r/r.zip", Name: "r/r.zip",
File: "r.zip", Content: rZipBytes(),
Mtime: "03-04-10 00:24:16", Mtime: "03-04-10 00:24:16",
Mode: 0666, Mode: 0666,
}, },
}, },
}, },
@ -415,3 +418,49 @@ func returnCorruptNotStreamedZip() (r io.ReaderAt, size int64) {
// is what matters. // is what matters.
}) })
} }
// rZipBytes returns the bytes of a recursive zip file, without
// putting it on disk and triggering certain virus scanners.
func rZipBytes() []byte {
s := `
0000000 50 4b 03 04 14 00 00 00 08 00 08 03 64 3c f9 f4
0000010 89 64 48 01 00 00 b8 01 00 00 07 00 00 00 72 2f
0000020 72 2e 7a 69 70 00 25 00 da ff 50 4b 03 04 14 00
0000030 00 00 08 00 08 03 64 3c f9 f4 89 64 48 01 00 00
0000040 b8 01 00 00 07 00 00 00 72 2f 72 2e 7a 69 70 00
0000050 2f 00 d0 ff 00 25 00 da ff 50 4b 03 04 14 00 00
0000060 00 08 00 08 03 64 3c f9 f4 89 64 48 01 00 00 b8
0000070 01 00 00 07 00 00 00 72 2f 72 2e 7a 69 70 00 2f
0000080 00 d0 ff c2 54 8e 57 39 00 05 00 fa ff c2 54 8e
0000090 57 39 00 05 00 fa ff 00 05 00 fa ff 00 14 00 eb
00000a0 ff c2 54 8e 57 39 00 05 00 fa ff 00 05 00 fa ff
00000b0 00 14 00 eb ff 42 88 21 c4 00 00 14 00 eb ff 42
00000c0 88 21 c4 00 00 14 00 eb ff 42 88 21 c4 00 00 14
00000d0 00 eb ff 42 88 21 c4 00 00 14 00 eb ff 42 88 21
00000e0 c4 00 00 00 00 ff ff 00 00 00 ff ff 00 34 00 cb
00000f0 ff 42 88 21 c4 00 00 00 00 ff ff 00 00 00 ff ff
0000100 00 34 00 cb ff 42 e8 21 5e 0f 00 00 00 ff ff 0a
0000110 f0 66 64 12 61 c0 15 dc e8 a0 48 bf 48 af 2a b3
0000120 20 c0 9b 95 0d c4 67 04 42 53 06 06 06 40 00 06
0000130 00 f9 ff 6d 01 00 00 00 00 42 e8 21 5e 0f 00 00
0000140 00 ff ff 0a f0 66 64 12 61 c0 15 dc e8 a0 48 bf
0000150 48 af 2a b3 20 c0 9b 95 0d c4 67 04 42 53 06 06
0000160 06 40 00 06 00 f9 ff 6d 01 00 00 00 00 50 4b 01
0000170 02 14 00 14 00 00 00 08 00 08 03 64 3c f9 f4 89
0000180 64 48 01 00 00 b8 01 00 00 07 00 00 00 00 00 00
0000190 00 00 00 00 00 00 00 00 00 00 00 72 2f 72 2e 7a
00001a0 69 70 50 4b 05 06 00 00 00 00 01 00 01 00 35 00
00001b0 00 00 6d 01 00 00 00 00`
s = regexp.MustCompile(`[0-9a-f]{7}`).ReplaceAllString(s, "")
s = regexp.MustCompile(`\s+`).ReplaceAllString(s, "")
b, err := hex.DecodeString(s)
if err != nil {
panic(err)
}
return b
}
func returnRecursiveZip() (r io.ReaderAt, size int64) {
b := rZipBytes()
return bytes.NewReader(b), int64(len(b))
}

View File

@ -166,8 +166,11 @@ func (c *Conn) clientHandshake() error {
} }
var certToSend *Certificate var certToSend *Certificate
var certRequested bool
certReq, ok := msg.(*certificateRequestMsg) certReq, ok := msg.(*certificateRequestMsg)
if ok { if ok {
certRequested = true
// RFC 4346 on the certificateAuthorities field: // RFC 4346 on the certificateAuthorities field:
// A list of the distinguished names of acceptable certificate // A list of the distinguished names of acceptable certificate
// authorities. These distinguished names may specify a desired // authorities. These distinguished names may specify a desired
@ -238,9 +241,14 @@ func (c *Conn) clientHandshake() error {
} }
finishedHash.Write(shd.marshal()) finishedHash.Write(shd.marshal())
if certToSend != nil { // If the server requested a certificate then we have to send a
// Certificate message, even if it's empty because we don't have a
// certificate to send.
if certRequested {
certMsg = new(certificateMsg) certMsg = new(certificateMsg)
certMsg.certificates = certToSend.Certificate if certToSend != nil {
certMsg.certificates = certToSend.Certificate
}
finishedHash.Write(certMsg.marshal()) finishedHash.Write(certMsg.marshal())
c.writeRecord(recordTypeHandshake, certMsg.marshal()) c.writeRecord(recordTypeHandshake, certMsg.marshal())
} }

View File

@ -226,7 +226,7 @@ where * signifies zero or more repetitions and the type id of a value must
be predefined or be defined before the value in the stream. be predefined or be defined before the value in the stream.
See "Gobs of data" for a design discussion of the gob wire format: See "Gobs of data" for a design discussion of the gob wire format:
http://blog.golang.org/2011/03/gobs-of-data.html http://golang.org/doc/articles/gobs_of_data.html
*/ */
package gob package gob

View File

@ -6,7 +6,7 @@
// RFC 4627. // RFC 4627.
// //
// See "JSON and Go" for an introduction to this package: // See "JSON and Go" for an introduction to this package:
// http://blog.golang.org/2011/01/json-and-go.html // http://golang.org/doc/articles/json_and_go.html
package json package json
import ( import (

View File

@ -356,7 +356,7 @@ func lastBoundary(fd *formInfo, b []byte) int {
return -1 return -1
} }
if info.size == 0 { // ends with incomplete rune if info.size == 0 { // ends with incomplete rune
if p == 0 { // starts wtih incomplete rune if p == 0 { // starts with incomplete rune
return -1 return -1
} }
i = p i = p

View File

@ -102,11 +102,6 @@ func init() {
defType("Pointer") defType("Pointer")
defFun("Alignof") defFun("Alignof")
defFun("New")
defFun("NewArray")
defFun("Offsetof") defFun("Offsetof")
defFun("Reflect")
defFun("Sizeof") defFun("Sizeof")
defFun("Typeof")
defFun("Unreflect")
} }

View File

@ -0,0 +1,83 @@
// Copyright 2012 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.
// These examples demonstrate more intricate uses of the flag package.
package flag_test
import (
"errors"
"flag"
"fmt"
"strings"
"time"
)
// Example 1: A single string flag called "species" with default value "gopher".
var species = flag.String("species", "gopher", "the species we are studying")
// Example 2: Two flags sharing a variable, so we can have a shorthand.
// The order of initialization is undefined, so make sure both use the
// same default value. They must be set up with an init function.
var gopherType string
func init() {
const (
defaultGopher = "pocket"
usage = "the variety of gopher"
)
flag.StringVar(&gopherType, "gopher_type", defaultGopher, usage)
flag.StringVar(&gopherType, "g", defaultGopher, usage+" (shorthand)")
}
// Example 3: A user-defined flag type, a slice of durations.
type interval []time.Duration
// String is the method to format the flag's value, part of the flag.Value interface.
// The String method's output will be used in diagnostics.
func (i *interval) String() string {
return fmt.Sprint(*i)
}
// Set is the method to set the flag value, part of the flag.Value interface.
// Set's argument is a string to be parsed to set the flag.
// It's a comma-separated list, so we split it.
func (i *interval) Set(value string) error {
// If we wanted to allow the flag to be set multiple times,
// accumulating values, we would delete this if statement.
// That would permit usages such as
// -deltaT 10s -deltaT 15s
// and other combinations.
if len(*i) > 0 {
return errors.New("interval flag already set")
}
for _, dt := range strings.Split(value, ",") {
duration, err := time.ParseDuration(dt)
if err != nil {
return err
}
*i = append(*i, duration)
}
return nil
}
// Define a flag to accumulate durations. Because it has a special type,
// we need to use the Var function and therefore create the flag during
// init.
var intervalFlag interval
func init() {
// Tie the command-line flag to the intervalFlag variable and
// set a usage message.
flag.Var(&intervalFlag, "deltaT", "comma-separated list of intervals to use between events")
}
func Example() {
// All the interesting pieces are with the variables declared above, but
// to enable the flag package to see the flags defined there, one must
// execute, typically at the start of main (not init!):
// flag.Parse()
// We don't run it here because this is not a main function and
// the testing suite has already parsed the flags.
}

View File

@ -810,7 +810,7 @@ func TestMultiLine(t *testing.T) {
} }
} }
// RecursiveInt accepts an string matching %d.%d.%d.... // RecursiveInt accepts a string matching %d.%d.%d....
// and parses it into a linked list. // and parses it into a linked list.
// It allows us to benchmark recursive descent style scanners. // It allows us to benchmark recursive descent style scanners.
type RecursiveInt struct { type RecursiveInt struct {
@ -826,7 +826,7 @@ func (r *RecursiveInt) Scan(state ScanState, verb rune) (err error) {
next := new(RecursiveInt) next := new(RecursiveInt)
_, err = Fscanf(state, ".%v", next) _, err = Fscanf(state, ".%v", next)
if err != nil { if err != nil {
if err == errors.New("input does not match format") || err == io.ErrUnexpectedEOF { if err == io.ErrUnexpectedEOF {
err = nil err = nil
} }
return return

View File

@ -328,22 +328,22 @@ func (e *NoGoError) Error() string {
} }
// Import returns details about the Go package named by the import path, // Import returns details about the Go package named by the import path,
// interpreting local import paths relative to the src directory. If the path // interpreting local import paths relative to the srcDir directory.
// is a local import path naming a package that can be imported using a // If the path is a local import path naming a package that can be imported
// standard import path, the returned package will set p.ImportPath to // using a standard import path, the returned package will set p.ImportPath
// that path. // to that path.
// //
// In the directory containing the package, .go, .c, .h, and .s files are // In the directory containing the package, .go, .c, .h, and .s files are
// considered part of the package except for: // considered part of the package except for:
// //
// - .go files in package documentation // - .go files in package documentation
// - files starting with _ or . // - files starting with _ or . (likely editor temporary files)
// - files with build constraints not satisfied by the context // - files with build constraints not satisfied by the context
// //
// If an error occurs, Import returns a non-nil error also returns a non-nil // If an error occurs, Import returns a non-nil error also returns a non-nil
// *Package containing partial information. // *Package containing partial information.
// //
func (ctxt *Context) Import(path string, src string, mode ImportMode) (*Package, error) { func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Package, error) {
p := &Package{ p := &Package{
ImportPath: path, ImportPath: path,
} }
@ -363,11 +363,12 @@ func (ctxt *Context) Import(path string, src string, mode ImportMode) (*Package,
binaryOnly := false binaryOnly := false
if IsLocalImport(path) { if IsLocalImport(path) {
if src == "" { pkga = "" // local imports have no installed path
if srcDir == "" {
return p, fmt.Errorf("import %q: import relative to unknown directory", path) return p, fmt.Errorf("import %q: import relative to unknown directory", path)
} }
if !ctxt.isAbsPath(path) { if !ctxt.isAbsPath(path) {
p.Dir = ctxt.joinPath(src, path) p.Dir = ctxt.joinPath(srcDir, path)
} }
// Determine canonical import path, if any. // Determine canonical import path, if any.
if ctxt.GOROOT != "" { if ctxt.GOROOT != "" {
@ -640,8 +641,8 @@ func cleanImports(m map[string][]token.Position) ([]string, map[string][]token.P
} }
// Import is shorthand for Default.Import. // Import is shorthand for Default.Import.
func Import(path, src string, mode ImportMode) (*Package, error) { func Import(path, srcDir string, mode ImportMode) (*Package, error) {
return Default.Import(path, src, mode) return Default.Import(path, srcDir, mode)
} }
// ImportDir is shorthand for Default.ImportDir. // ImportDir is shorthand for Default.ImportDir.
@ -874,7 +875,7 @@ func splitQuoted(s string) (r []string, err error) {
// !cgo (if cgo is disabled) // !cgo (if cgo is disabled)
// tag (if tag is listed in ctxt.BuildTags) // tag (if tag is listed in ctxt.BuildTags)
// !tag (if tag is not listed in ctxt.BuildTags) // !tag (if tag is not listed in ctxt.BuildTags)
// a slash-separated list of any of these // a comma-separated list of any of these
// //
func (ctxt *Context) match(name string) bool { func (ctxt *Context) match(name string) bool {
if name == "" { if name == "" {
@ -888,11 +889,11 @@ func (ctxt *Context) match(name string) bool {
return false return false
} }
if strings.HasPrefix(name, "!") { // negation if strings.HasPrefix(name, "!") { // negation
return !ctxt.match(name[1:]) return len(name) > 1 && !ctxt.match(name[1:])
} }
// Tags must be letters, digits, underscores. // Tags must be letters, digits, underscores.
// Unlike in Go identifiers, all digits is fine (e.g., "386"). // Unlike in Go identifiers, all digits are fine (e.g., "386").
for _, c := range name { for _, c := range name {
if !unicode.IsLetter(c) && !unicode.IsDigit(c) && c != '_' { if !unicode.IsLetter(c) && !unicode.IsDigit(c) && c != '_' {
return false return false

View File

@ -36,6 +36,7 @@ func TestMatch(t *testing.T) {
nomatch(runtime.GOOS + "," + runtime.GOARCH + ",!foo") nomatch(runtime.GOOS + "," + runtime.GOARCH + ",!foo")
match(runtime.GOOS + "," + runtime.GOARCH + ",!bar") match(runtime.GOOS + "," + runtime.GOARCH + ",!bar")
nomatch(runtime.GOOS + "," + runtime.GOARCH + ",bar") nomatch(runtime.GOOS + "," + runtime.GOARCH + ",bar")
nomatch("!")
} }
func TestDotSlashImport(t *testing.T) { func TestDotSlashImport(t *testing.T) {

View File

@ -365,7 +365,7 @@ func (p *printer) setLineComment(text string) {
} }
func (p *printer) isMultiLine(n ast.Node) bool { func (p *printer) isMultiLine(n ast.Node) bool {
return p.lineFor(n.End())-p.lineFor(n.Pos()) > 1 return p.lineFor(n.End())-p.lineFor(n.Pos()) > 0
} }
func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool) { func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool) {

View File

@ -500,7 +500,7 @@ type _ struct {
type _ struct { type _ struct {
a, b, a, b,
c, d int // this line should be indented c, d int // this line should be indented
u, v, w, x float // this line should be indented u, v, w, x float // this line should be indented
p, q, p, q,
r, s float // this line should be indented r, s float // this line should be indented
@ -562,10 +562,21 @@ var a2, b2,
var ( var (
a3, b3, a3, b3,
c3, d3 int // this line should be indented c3, d3 int // this line should be indented
a4, b4, c4 int // this line should be indented a4, b4, c4 int // this line should be indented
) )
// Test case from issue 3304: multi-line declarations must end
// a formatting section and not influence indentation of the
// next line.
var (
minRefreshTimeSec = flag.Int64("min_refresh_time_sec", 604800,
"minimum time window between two refreshes for a given user.")
x = flag.Int64("refresh_user_rollout_percent", 100,
"temporary flag to ramp up the refresh user rpc")
aVeryLongVariableName = stats.GetVarInt("refresh-user-count")
)
func _() { func _() {
var privateKey2 = &Block{Type: "RSA PRIVATE KEY", var privateKey2 = &Block{Type: "RSA PRIVATE KEY",
Headers: map[string]string{}, Headers: map[string]string{},

View File

@ -577,6 +577,16 @@ c3, d3 int // this line should be indented
a4, b4, c4 int // this line should be indented a4, b4, c4 int // this line should be indented
) )
// Test case from issue 3304: multi-line declarations must end
// a formatting section and not influence indentation of the
// next line.
var (
minRefreshTimeSec = flag.Int64("min_refresh_time_sec", 604800,
"minimum time window between two refreshes for a given user.")
x = flag.Int64("refresh_user_rollout_percent", 100,
"temporary flag to ramp up the refresh user rpc")
aVeryLongVariableName = stats.GetVarInt("refresh-user-count")
)
func _() { func _() {
var privateKey2 = &Block{Type: "RSA PRIVATE KEY", var privateKey2 = &Block{Type: "RSA PRIVATE KEY",

View File

@ -113,3 +113,36 @@ func TestClone(t *testing.T) {
t.Errorf("t3: got %q want %q", got, want) t.Errorf("t3: got %q want %q", got, want)
} }
} }
func TestTemplates(t *testing.T) {
names := []string{"t0", "a", "lhs", "rhs"}
// Some template definitions borrowed from TestClone.
const tmpl = `
{{define "a"}}{{template "lhs"}}{{.}}{{template "rhs"}}{{end}}
{{define "lhs"}} <a href=" {{end}}
{{define "rhs"}} "></a> {{end}}`
t0 := Must(New("t0").Parse(tmpl))
templates := t0.Templates()
if len(templates) != len(names) {
t.Errorf("expected %d templates; got %d", len(names), len(templates))
}
for _, name := range names {
found := false
for _, tmpl := range templates {
if name == tmpl.text.Name() {
found = true
break
}
}
if !found {
t.Error("could not find template", name)
}
}
}
// This used to crash; http://golang.org/issue/3281
func TestCloneCrash(t *testing.T) {
t1 := New("all")
Must(t1.New("t1").Parse(`{{define "foo"}}foo{{end}}`))
t1.Clone()
}

View File

@ -26,10 +26,10 @@ type (
HTML string HTML string
// HTMLAttr encapsulates an HTML attribute from a trusted source, // HTMLAttr encapsulates an HTML attribute from a trusted source,
// for example: ` dir="ltr"`. // for example, ` dir="ltr"`.
HTMLAttr string HTMLAttr string
// JS encapsulates a known safe EcmaScript5 Expression, or example, // JS encapsulates a known safe EcmaScript5 Expression, for example,
// `(x + y * z())`. // `(x + y * z())`.
// Template authors are responsible for ensuring that typed expressions // Template authors are responsible for ensuring that typed expressions
// do not break the intended precedence and that there is no // do not break the intended precedence and that there is no

View File

@ -8,6 +8,7 @@ import (
"bytes" "bytes"
"fmt" "fmt"
"html" "html"
"io"
"text/template" "text/template"
"text/template/parse" "text/template/parse"
) )
@ -751,3 +752,44 @@ func (e *escaper) template(name string) *template.Template {
} }
return t return t
} }
// Forwarding functions so that clients need only import this package
// to reach the general escaping functions of text/template.
// HTMLEscape writes to w the escaped HTML equivalent of the plain text data b.
func HTMLEscape(w io.Writer, b []byte) {
template.HTMLEscape(w, b)
}
// HTMLEscapeString returns the escaped HTML equivalent of the plain text data s.
func HTMLEscapeString(s string) string {
return template.HTMLEscapeString(s)
}
// HTMLEscaper returns the escaped HTML equivalent of the textual
// representation of its arguments.
func HTMLEscaper(args ...interface{}) string {
return template.HTMLEscaper(args...)
}
// JSEscape writes to w the escaped JavaScript equivalent of the plain text data b.
func JSEscape(w io.Writer, b []byte) {
template.JSEscape(w, b)
}
// JSEscapeString returns the escaped JavaScript equivalent of the plain text data s.
func JSEscapeString(s string) string {
return template.JSEscapeString(s)
}
// JSEscaper returns the escaped JavaScript equivalent of the textual
// representation of its arguments.
func JSEscaper(args ...interface{}) string {
return template.JSEscaper(args...)
}
// URLQueryEscaper returns the escaped value of the textual representation of
// its arguments in a form suitable for embedding in a URL query.
func URLQueryEscaper(args ...interface{}) string {
return template.URLQueryEscaper(args...)
}

View File

@ -8,6 +8,7 @@ import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"fmt" "fmt"
"os"
"strings" "strings"
"testing" "testing"
"text/template" "text/template"
@ -1637,6 +1638,14 @@ func TestIndirectPrint(t *testing.T) {
} }
} }
// This is a test for issue 3272.
func TestEmptyTemplate(t *testing.T) {
page := Must(New("page").ParseFiles(os.DevNull))
if err := page.ExecuteTemplate(os.Stdout, "page", "nothing"); err == nil {
t.Fatal("expected error")
}
}
func BenchmarkEscapedExecute(b *testing.B) { func BenchmarkEscapedExecute(b *testing.B) {
tmpl := Must(New("t").Parse(`<a onclick="alert('{{.}}')">{{.}}</a>`)) tmpl := Must(New("t").Parse(`<a onclick="alert('{{.}}')">{{.}}</a>`))
var buf bytes.Buffer var buf bytes.Buffer

View File

@ -31,6 +31,20 @@ type nameSpace struct {
set map[string]*Template set map[string]*Template
} }
// Templates returns a slice of the templates associated with t, including t
// itself.
func (t *Template) Templates() []*Template {
ns := t.nameSpace
ns.mu.Lock()
defer ns.mu.Unlock()
// Return a slice so we don't expose the map.
m := make([]*Template, 0, len(ns.set))
for _, v := range ns.set {
m = append(m, v)
}
return m
}
// Execute applies a parsed template to the specified data object, // Execute applies a parsed template to the specified data object,
// writing the output to wr. // writing the output to wr.
func (t *Template) Execute(wr io.Writer, data interface{}) (err error) { func (t *Template) Execute(wr io.Writer, data interface{}) (err error) {
@ -64,7 +78,13 @@ func (t *Template) lookupAndEscapeTemplate(name string) (tmpl *Template, err err
t.nameSpace.mu.Lock() t.nameSpace.mu.Lock()
defer t.nameSpace.mu.Unlock() defer t.nameSpace.mu.Unlock()
tmpl = t.set[name] tmpl = t.set[name]
if (tmpl == nil) != (t.text.Lookup(name) == nil) { if tmpl == nil {
return nil, fmt.Errorf("html/template: %q is undefined", name)
}
if tmpl.text.Tree == nil || tmpl.text.Root == nil {
return nil, fmt.Errorf("html/template: %q is an incomplete template", name)
}
if t.text.Lookup(name) == nil {
panic("html/template internal error: template escaping out of sync") panic("html/template internal error: template escaping out of sync")
} }
if tmpl != nil && !tmpl.escaped { if tmpl != nil && !tmpl.escaped {
@ -160,9 +180,11 @@ func (t *Template) Clone() (*Template, error) {
if src == nil || src.escaped { if src == nil || src.escaped {
return nil, fmt.Errorf("html/template: cannot Clone %q after it has executed", t.Name()) return nil, fmt.Errorf("html/template: cannot Clone %q after it has executed", t.Name())
} }
x.Tree = &parse.Tree{ if x.Tree != nil {
Name: x.Tree.Name, x.Tree = &parse.Tree{
Root: x.Tree.Root.CopyList(), Name: x.Tree.Name,
Root: x.Tree.Root.CopyList(),
}
} }
ret.set[name] = &Template{ ret.set[name] = &Template{
false, false,
@ -274,7 +296,7 @@ func (t *Template) ParseFiles(filenames ...string) (*Template, error) {
func parseFiles(t *Template, filenames ...string) (*Template, error) { func parseFiles(t *Template, filenames ...string) (*Template, error) {
if len(filenames) == 0 { if len(filenames) == 0 {
// Not really a problem, but be consistent. // Not really a problem, but be consistent.
return nil, fmt.Errorf("template: no files named in call to ParseFiles") return nil, fmt.Errorf("html/template: no files named in call to ParseFiles")
} }
for _, filename := range filenames { for _, filename := range filenames {
b, err := ioutil.ReadFile(filename) b, err := ioutil.ReadFile(filename)
@ -331,7 +353,7 @@ func parseGlob(t *Template, pattern string) (*Template, error) {
return nil, err return nil, err
} }
if len(filenames) == 0 { if len(filenames) == 0 {
return nil, fmt.Errorf("template: pattern matches no files: %#q", pattern) return nil, fmt.Errorf("html/template: pattern matches no files: %#q", pattern)
} }
return parseFiles(t, filenames...) return parseFiles(t, filenames...)
} }

View File

@ -5,7 +5,7 @@
// Package draw provides image composition functions. // Package draw provides image composition functions.
// //
// See "The Go image/draw package" for an introduction to this package: // See "The Go image/draw package" for an introduction to this package:
// http://blog.golang.org/2011/09/go-imagedraw-package.html // http://golang.org/doc/articles/image_draw.html
package draw package draw
import ( import (

View File

@ -11,7 +11,7 @@
// Consecutive groups of suffixes in sa are labeled as sorted groups or // Consecutive groups of suffixes in sa are labeled as sorted groups or
// unsorted groups. For a given pass of the sorter, all suffixes are ordered // unsorted groups. For a given pass of the sorter, all suffixes are ordered
// up to their first h characters, and sa is h-ordered. Suffixes in their // up to their first h characters, and sa is h-ordered. Suffixes in their
// final positions and unambiguouly sorted in h-order are in a sorted group. // final positions and unambiguously sorted in h-order are in a sorted group.
// Consecutive groups of suffixes with identical first h characters are an // Consecutive groups of suffixes with identical first h characters are an
// unsorted group. In each pass of the algorithm, unsorted groups are sorted // unsorted group. In each pass of the algorithm, unsorted groups are sorted
// according to the group number of their following suffix. // according to the group number of their following suffix.
@ -78,7 +78,7 @@ func sortedByFirstByte(data []byte) []int {
for _, b := range data { for _, b := range data {
count[b]++ count[b]++
} }
// make count[b] equal index of first occurence of b in sorted array // make count[b] equal index of first occurrence of b in sorted array
sum := 0 sum := 0
for b := range count { for b := range count {
count[b], sum = sum, count[b]+sum count[b], sum = sum, count[b]+sum

View File

@ -53,10 +53,13 @@ func ReadFile(filename string) ([]byte, error) {
defer f.Close() defer f.Close()
// It's a good but not certain bet that FileInfo will tell us exactly how much to // It's a good but not certain bet that FileInfo will tell us exactly how much to
// read, so let's try it but be prepared for the answer to be wrong. // read, so let's try it but be prepared for the answer to be wrong.
fi, err := f.Stat()
var n int64 var n int64
if size := fi.Size(); err == nil && size < 2e9 { // Don't preallocate a huge buffer, just in case.
n = size if fi, err := f.Stat(); err == nil {
// Don't preallocate a huge buffer, just in case.
if size := fi.Size(); size < 1e9 {
n = size
}
} }
// As initial capacity for readAll, use n + a little extra in case Size is zero, // As initial capacity for readAll, use n + a little extra in case Size is zero,
// and to avoid another allocation after Read has filled the buffer. The readAll // and to avoid another allocation after Read has filled the buffer. The readAll

View File

@ -0,0 +1,8 @@
// Copyright 2012 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 syslog provides a simple interface to the system log service.
package syslog
// BUG(brainman): This package is not implemented on Windows yet.

View File

@ -826,7 +826,7 @@ func (x nat) string(charset string) string {
// iterative approach. This threshold is represented by leafSize. Benchmarking of leafSize in the // iterative approach. This threshold is represented by leafSize. Benchmarking of leafSize in the
// range 2..64 shows that values of 8 and 16 work well, with a 4x speedup at medium lengths and // range 2..64 shows that values of 8 and 16 work well, with a 4x speedup at medium lengths and
// ~30x for 20000 digits. Use nat_test.go's BenchmarkLeafSize tests to optimize leafSize for // ~30x for 20000 digits. Use nat_test.go's BenchmarkLeafSize tests to optimize leafSize for
// specfic hardware. // specific hardware.
// //
func (q nat) convertWords(s []byte, charset string, b Word, ndigits int, bb Word, table []divisor) { func (q nat) convertWords(s []byte, charset string, b Word, ndigits int, bb Word, table []divisor) {
// split larger blocks recursively // split larger blocks recursively

View File

@ -248,7 +248,7 @@ func Erf(x float64) float64 {
R = rb0 + s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*(rb5+s*rb6))))) R = rb0 + s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*(rb5+s*rb6)))))
S = 1 + s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*(sb5+s*(sb6+s*sb7)))))) S = 1 + s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*(sb5+s*(sb6+s*sb7))))))
} }
z := Float64frombits(Float64bits(x) & 0xffffffff00000000) // pseudo-single (20-bit) precison x z := Float64frombits(Float64bits(x) & 0xffffffff00000000) // pseudo-single (20-bit) precision x
r := Exp(-z*z-0.5625) * Exp((z-x)*(z+x)+R/S) r := Exp(-z*z-0.5625) * Exp((z-x)*(z+x)+R/S)
if sign { if sign {
return r/x - 1 return r/x - 1
@ -321,7 +321,7 @@ func Erfc(x float64) float64 {
R = rb0 + s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*(rb5+s*rb6))))) R = rb0 + s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*(rb5+s*rb6)))))
S = 1 + s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*(sb5+s*(sb6+s*sb7)))))) S = 1 + s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*(sb5+s*(sb6+s*sb7))))))
} }
z := Float64frombits(Float64bits(x) & 0xffffffff00000000) // pseudo-single (20-bit) precison x z := Float64frombits(Float64bits(x) & 0xffffffff00000000) // pseudo-single (20-bit) precision x
r := Exp(-z*z-0.5625) * Exp((z-x)*(z+x)+R/S) r := Exp(-z*z-0.5625) * Exp((z-x)*(z+x)+R/S)
if sign { if sign {
return 2 - r/x return 2 - r/x

View File

@ -15,7 +15,9 @@ import (
"log" "log"
"net/http" "net/http"
"os" "os"
"os/exec"
"strconv" "strconv"
"sync"
) )
// hello world, the web server // hello world, the web server
@ -28,14 +30,21 @@ func HelloServer(w http.ResponseWriter, req *http.Request) {
// Simple counter server. POSTing to it will set the value. // Simple counter server. POSTing to it will set the value.
type Counter struct { type Counter struct {
n int mu sync.Mutex // protects n
n int
} }
// This makes Counter satisfy the expvar.Var interface, so we can export // This makes Counter satisfy the expvar.Var interface, so we can export
// it directly. // it directly.
func (ctr *Counter) String() string { return fmt.Sprintf("%d", ctr.n) } func (ctr *Counter) String() string {
ctr.mu.Lock()
defer ctr.mu.Unlock()
return fmt.Sprintf("%d", ctr.n)
}
func (ctr *Counter) ServeHTTP(w http.ResponseWriter, req *http.Request) { func (ctr *Counter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
ctr.mu.Lock()
defer ctr.mu.Unlock()
switch req.Method { switch req.Method {
case "GET": case "GET":
ctr.n++ ctr.n++
@ -95,54 +104,36 @@ func (ch Chan) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// exec a program, redirecting output // exec a program, redirecting output
func DateServer(rw http.ResponseWriter, req *http.Request) { func DateServer(rw http.ResponseWriter, req *http.Request) {
rw.Header().Set("Content-Type", "text/plain; charset=utf-8") rw.Header().Set("Content-Type", "text/plain; charset=utf-8")
r, w, err := os.Pipe()
if err != nil {
fmt.Fprintf(rw, "pipe: %s\n", err)
return
}
p, err := os.StartProcess("/bin/date", []string{"date"}, &os.ProcAttr{Files: []*os.File{nil, w, w}}) date, err := exec.Command("/bin/date").Output()
defer r.Close()
w.Close()
if err != nil { if err != nil {
fmt.Fprintf(rw, "fork/exec: %s\n", err) http.Error(rw, err.Error(), 500)
return
}
io.Copy(rw, r)
wait, err := p.Wait(0)
if err != nil {
fmt.Fprintf(rw, "wait: %s\n", err)
return
}
if !wait.Exited() || wait.ExitStatus() != 0 {
fmt.Fprintf(rw, "date: %v\n", wait)
return return
} }
rw.Write(date)
} }
func Logger(w http.ResponseWriter, req *http.Request) { func Logger(w http.ResponseWriter, req *http.Request) {
log.Print(req.URL.Raw) log.Print(req.URL)
w.WriteHeader(404) http.Error(w, "oops", 404)
w.Write([]byte("oops"))
} }
var webroot = flag.String("root", "/home/rsc", "web root directory") var webroot = flag.String("root", os.Getenv("HOME"), "web root directory")
func main() { func main() {
flag.Parse() flag.Parse()
// The counter is published as a variable directly. // The counter is published as a variable directly.
ctr := new(Counter) ctr := new(Counter)
http.Handle("/counter", ctr)
expvar.Publish("counter", ctr) expvar.Publish("counter", ctr)
http.Handle("/counter", ctr)
http.Handle("/", http.HandlerFunc(Logger)) http.Handle("/", http.HandlerFunc(Logger))
http.Handle("/go/", http.StripPrefix("/go/", http.FileServer(http.Dir(*webroot)))) http.Handle("/go/", http.StripPrefix("/go/", http.FileServer(http.Dir(*webroot))))
http.Handle("/flags", http.HandlerFunc(FlagServer))
http.Handle("/args", http.HandlerFunc(ArgServer))
http.Handle("/go/hello", http.HandlerFunc(HelloServer))
http.Handle("/chan", ChanCreate()) http.Handle("/chan", ChanCreate())
http.Handle("/date", http.HandlerFunc(DateServer)) http.HandleFunc("/flags", FlagServer)
http.HandleFunc("/args", ArgServer)
http.HandleFunc("/go/hello", HelloServer)
http.HandleFunc("/date", DateServer)
err := http.ListenAndServe(":12345", nil) err := http.ListenAndServe(":12345", nil)
if err != nil { if err != nil {
log.Panicln("ListenAndServe:", err) log.Panicln("ListenAndServe:", err)

View File

@ -13,7 +13,7 @@ import (
) )
// If the ifindex is zero, interfaceTable returns mappings of all // If the ifindex is zero, interfaceTable returns mappings of all
// network interfaces. Otheriwse it returns a mapping of a specific // network interfaces. Otherwise it returns a mapping of a specific
// interface. // interface.
func interfaceTable(ifindex int) ([]Interface, error) { func interfaceTable(ifindex int) ([]Interface, error) {
tab, err := syscall.NetlinkRIB(syscall.RTM_GETLINK, syscall.AF_UNSPEC) tab, err := syscall.NetlinkRIB(syscall.RTM_GETLINK, syscall.AF_UNSPEC)

View File

@ -9,7 +9,7 @@
package net package net
// If the ifindex is zero, interfaceTable returns mappings of all // If the ifindex is zero, interfaceTable returns mappings of all
// network interfaces. Otheriwse it returns a mapping of a specific // network interfaces. Otherwise it returns a mapping of a specific
// interface. // interface.
func interfaceTable(ifindex int) ([]Interface, error) { func interfaceTable(ifindex int) ([]Interface, error) {
return nil, nil return nil, nil

View File

@ -56,7 +56,7 @@ func getInterfaceList() ([]syscall.InterfaceInfo, error) {
} }
// If the ifindex is zero, interfaceTable returns mappings of all // If the ifindex is zero, interfaceTable returns mappings of all
// network interfaces. Otheriwse it returns a mapping of a specific // network interfaces. Otherwise it returns a mapping of a specific
// interface. // interface.
func interfaceTable(ifindex int) ([]Interface, error) { func interfaceTable(ifindex int) ([]Interface, error) {
ai, err := getAdapterList() ai, err := getAdapterList()

View File

@ -5,7 +5,6 @@
package net package net
import ( import (
"io"
"runtime" "runtime"
"syscall" "syscall"
"testing" "testing"
@ -67,7 +66,7 @@ func TestTCPListener(t *testing.T) {
case syscall.AF_INET6: case syscall.AF_INET6:
testIPv6UnicastSocketOptions(t, fd) testIPv6UnicastSocketOptions(t, fd)
} }
l1.(io.Closer).Close() l1.Close()
} }
} }
@ -112,7 +111,7 @@ func TestUDPListener(t *testing.T) {
case syscall.AF_INET6: case syscall.AF_INET6:
testIPv6UnicastSocketOptions(t, fd) testIPv6UnicastSocketOptions(t, fd)
} }
l1.(io.Closer).Close() l1.Close()
} }
} }
@ -134,7 +133,7 @@ func TestSimpleTCPListener(t *testing.T) {
checkFirstListener(t, tt.net, tt.laddr+":"+port, l1) checkFirstListener(t, tt.net, tt.laddr+":"+port, l1)
l2, err := Listen(tt.net, tt.laddr+":"+port) l2, err := Listen(tt.net, tt.laddr+":"+port)
checkSecondListener(t, tt.net, tt.laddr+":"+port, err, l2) checkSecondListener(t, tt.net, tt.laddr+":"+port, err, l2)
l1.(io.Closer).Close() l1.Close()
} }
} }
@ -169,7 +168,7 @@ func TestSimpleUDPListener(t *testing.T) {
checkFirstListener(t, tt.net, tt.laddr+":"+port, l1) checkFirstListener(t, tt.net, tt.laddr+":"+port, l1)
l2, err := ListenPacket(tt.net, tt.laddr+":"+port) l2, err := ListenPacket(tt.net, tt.laddr+":"+port)
checkSecondListener(t, tt.net, tt.laddr+":"+port, err, l2) checkSecondListener(t, tt.net, tt.laddr+":"+port, err, l2)
l1.(io.Closer).Close() l1.Close()
} }
} }
@ -530,8 +529,9 @@ func TestProhibitionaryDialArgs(t *testing.T) {
defer l.Close() defer l.Close()
for _, tt := range prohibitionaryDialArgTests { for _, tt := range prohibitionaryDialArgTests {
_, err := Dial(tt.net, tt.addr+":"+port) c, err := Dial(tt.net, tt.addr+":"+port)
if err == nil { if err == nil {
c.Close()
t.Fatalf("Dial(%q, %q) should fail", tt.net, tt.addr) t.Fatalf("Dial(%q, %q) should fail", tt.net, tt.addr)
} }
} }

View File

@ -42,3 +42,21 @@ func NewSyscallError(syscall string, err error) error {
} }
return &SyscallError{syscall, err} return &SyscallError{syscall, err}
} }
// IsExist returns whether the error is known to report that a file or directory
// already exists. It is satisfied by ErrExist as well as some syscall errors.
func IsExist(err error) bool {
return isExist(err)
}
// IsNotExist returns whether the error is known to report that a file or directory
// does not exist. It is satisfied by ErrNotExist as well as some syscall errors.
func IsNotExist(err error) bool {
return isNotExist(err)
}
// IsPermission returns whether the error is known to report that permission is denied.
// It is satisfied by ErrPermission as well as some syscall errors.
func IsPermission(err error) bool {
return isPermission(err)
}

View File

@ -4,24 +4,21 @@
package os package os
// IsExist returns whether the error is known to report that a file already exists. func isExist(err error) bool {
func IsExist(err error) bool {
if pe, ok := err.(*PathError); ok { if pe, ok := err.(*PathError); ok {
err = pe.Err err = pe.Err
} }
return contains(err.Error(), " exists") return contains(err.Error(), " exists")
} }
// IsNotExist returns whether the error is known to report that a file does not exist. func isNotExist(err error) bool {
func IsNotExist(err error) bool {
if pe, ok := err.(*PathError); ok { if pe, ok := err.(*PathError); ok {
err = pe.Err err = pe.Err
} }
return contains(err.Error(), "does not exist") return contains(err.Error(), "does not exist")
} }
// IsPermission returns whether the error is known to report that permission is denied. func isPermission(err error) bool {
func IsPermission(err error) bool {
if pe, ok := err.(*PathError); ok { if pe, ok := err.(*PathError); ok {
err = pe.Err err = pe.Err
} }

View File

@ -8,27 +8,21 @@ package os
import "syscall" import "syscall"
// IsExist returns whether the error is known to report that a file already exists. func isExist(err error) bool {
// It is satisfied by ErrExist as well as some syscall errors.
func IsExist(err error) bool {
if pe, ok := err.(*PathError); ok { if pe, ok := err.(*PathError); ok {
err = pe.Err err = pe.Err
} }
return err == syscall.EEXIST || err == ErrExist return err == syscall.EEXIST || err == ErrExist
} }
// IsNotExist returns whether the error is known to report that a file does not exist. func isNotExist(err error) bool {
// It is satisfied by ErrNotExist as well as some syscall errors.
func IsNotExist(err error) bool {
if pe, ok := err.(*PathError); ok { if pe, ok := err.(*PathError); ok {
err = pe.Err err = pe.Err
} }
return err == syscall.ENOENT || err == ErrNotExist return err == syscall.ENOENT || err == ErrNotExist
} }
// IsPermission returns whether the error is known to report that permission is denied. func isPermission(err error) bool {
// It is satisfied by ErrPermission as well as some syscall errors.
func IsPermission(err error) bool {
if pe, ok := err.(*PathError); ok { if pe, ok := err.(*PathError); ok {
err = pe.Err err = pe.Err
} }

View File

@ -5,8 +5,10 @@
package os_test package os_test
import ( import (
"fmt"
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath"
"testing" "testing"
) )
@ -24,8 +26,56 @@ func TestErrIsExist(t *testing.T) {
t.Fatal("Open should have failed") t.Fatal("Open should have failed")
return return
} }
if !os.IsExist(err) { if s := checkErrorPredicate("os.IsExist", os.IsExist, err); s != "" {
t.Fatalf("os.IsExist does not work as expected for %#v", err) t.Fatal(s)
return return
} }
} }
func testErrNotExist(name string) string {
f, err := os.Open(name)
if err == nil {
f.Close()
return "Open should have failed"
}
if s := checkErrorPredicate("os.IsNotExist", os.IsNotExist, err); s != "" {
return s
}
err = os.Chdir(name)
if err == nil {
return "Chdir should have failed"
}
if s := checkErrorPredicate("os.IsNotExist", os.IsNotExist, err); s != "" {
return s
}
return ""
}
func TestErrIsNotExist(t *testing.T) {
tmpDir, err := ioutil.TempDir("", "_Go_ErrIsNotExist")
if err != nil {
t.Fatalf("create ErrIsNotExist tempdir: %s", err)
return
}
defer os.RemoveAll(tmpDir)
name := filepath.Join(tmpDir, "NotExists")
if s := testErrNotExist(name); s != "" {
t.Fatal(s)
return
}
name = filepath.Join(name, "NotExists2")
if s := testErrNotExist(name); s != "" {
t.Fatal(s)
return
}
}
func checkErrorPredicate(predName string, pred func(error) bool, err error) string {
if !pred(err) {
return fmt.Sprintf("%s does not work as expected for %#v", predName, err)
}
return ""
}

View File

@ -6,30 +6,25 @@ package os
import "syscall" import "syscall"
// IsExist returns whether the error is known to report that a file already exists. func isExist(err error) bool {
// It is satisfied by ErrExist as well as some syscall errors.
func IsExist(err error) bool {
if pe, ok := err.(*PathError); ok { if pe, ok := err.(*PathError); ok {
err = pe.Err err = pe.Err
} }
return err == syscall.EEXIST || err == syscall.ERROR_ALREADY_EXISTS || return err == syscall.ERROR_ALREADY_EXISTS ||
err == syscall.ERROR_FILE_EXISTS || err == ErrExist err == syscall.ERROR_FILE_EXISTS || err == ErrExist
} }
// IsNotExist returns whether the error is known to report that a file does not exist. func isNotExist(err error) bool {
// It is satisfied by ErrNotExist as well as some syscall errors.
func IsNotExist(err error) bool {
if pe, ok := err.(*PathError); ok { if pe, ok := err.(*PathError); ok {
err = pe.Err err = pe.Err
} }
return err == syscall.ENOENT || err == ErrNotExist return err == syscall.ERROR_FILE_NOT_FOUND ||
err == syscall.ERROR_PATH_NOT_FOUND || err == ErrNotExist
} }
// IsPermission returns whether the error is known to report that permission is denied. func isPermission(err error) bool {
// It is satisfied by ErrPermission as well as some syscall errors.
func IsPermission(err error) bool {
if pe, ok := err.(*PathError); ok { if pe, ok := err.(*PathError); ok {
err = pe.Err err = pe.Err
} }
return err == syscall.EACCES || err == syscall.EPERM || err == ErrPermission return err == ErrPermission
} }

View File

@ -179,7 +179,21 @@ func (f *File) pread(b []byte, off int64) (n int, err error) {
// write writes len(b) bytes to the File. // write writes len(b) bytes to the File.
// It returns the number of bytes written and an error, if any. // It returns the number of bytes written and an error, if any.
func (f *File) write(b []byte) (n int, err error) { func (f *File) write(b []byte) (n int, err error) {
return syscall.Write(f.fd, b) for {
m, err := syscall.Write(f.fd, b)
n += m
// If the syscall wrote some data but not all (short write)
// or it returned EINTR, then assume it stopped early for
// reasons that are uninteresting to the caller, and try again.
if 0 < m && m < len(b) || err == syscall.EINTR {
b = b[m:]
continue
}
return n, err
}
panic("not reached")
} }
// pwrite writes len(b) bytes to the File starting at byte offset off. // pwrite writes len(b) bytes to the File starting at byte offset off.

View File

@ -1045,3 +1045,22 @@ func TestSameFile(t *testing.T) {
t.Errorf("files should be different") t.Errorf("files should be different")
} }
} }
func TestDevNullFile(t *testing.T) {
f, err := Open(DevNull)
if err != nil {
t.Fatalf("Open(%s): %v", DevNull, err)
}
defer f.Close()
fi, err := f.Stat()
if err != nil {
t.Fatalf("Stat(%s): %v", DevNull, err)
}
name := filepath.Base(DevNull)
if fi.Name() != name {
t.Fatalf("wrong file name have %v want %v", fi.Name(), name)
}
if fi.Size() != 0 {
t.Fatalf("wrong file size have %d want 0", fi.Size())
}
}

View File

@ -7,6 +7,7 @@ package filepath
import ( import (
"errors" "errors"
"os" "os"
"runtime"
"sort" "sort"
"strings" "strings"
"unicode/utf8" "unicode/utf8"
@ -37,6 +38,9 @@ var ErrBadPattern = errors.New("syntax error in pattern")
// The only possible returned error is ErrBadPattern, when pattern // The only possible returned error is ErrBadPattern, when pattern
// is malformed. // is malformed.
// //
// On Windows, escaping is disabled. Instead, '\\' is treated as
// path separator.
//
func Match(pattern, name string) (matched bool, err error) { func Match(pattern, name string) (matched bool, err error) {
Pattern: Pattern:
for len(pattern) > 0 { for len(pattern) > 0 {
@ -95,9 +99,11 @@ Scan:
for i = 0; i < len(pattern); i++ { for i = 0; i < len(pattern); i++ {
switch pattern[i] { switch pattern[i] {
case '\\': case '\\':
// error check handled in matchChunk: bad pattern. if runtime.GOOS != "windows" {
if i+1 < len(pattern) { // error check handled in matchChunk: bad pattern.
i++ if i+1 < len(pattern) {
i++
}
} }
case '[': case '[':
inrange = true inrange = true
@ -167,10 +173,12 @@ func matchChunk(chunk, s string) (rest string, ok bool, err error) {
chunk = chunk[1:] chunk = chunk[1:]
case '\\': case '\\':
chunk = chunk[1:] if runtime.GOOS != "windows" {
if len(chunk) == 0 { chunk = chunk[1:]
err = ErrBadPattern if len(chunk) == 0 {
return err = ErrBadPattern
return
}
} }
fallthrough fallthrough
@ -191,7 +199,7 @@ func getEsc(chunk string) (r rune, nchunk string, err error) {
err = ErrBadPattern err = ErrBadPattern
return return
} }
if chunk[0] == '\\' { if chunk[0] == '\\' && runtime.GOOS != "windows" {
chunk = chunk[1:] chunk = chunk[1:]
if len(chunk) == 0 { if len(chunk) == 0 {
err = ErrBadPattern err = ErrBadPattern

View File

@ -7,6 +7,7 @@ package filepath_test
import ( import (
. "path/filepath" . "path/filepath"
"runtime" "runtime"
"strings"
"testing" "testing"
) )
@ -76,21 +77,26 @@ func errp(e error) string {
} }
func TestMatch(t *testing.T) { func TestMatch(t *testing.T) {
if runtime.GOOS == "windows" {
// XXX: Don't pass for windows.
return
}
for _, tt := range matchTests { for _, tt := range matchTests {
ok, err := Match(tt.pattern, tt.s) pattern := tt.pattern
s := tt.s
if runtime.GOOS == "windows" {
if strings.Index(pattern, "\\") >= 0 {
// no escape allowed on windows.
continue
}
pattern = Clean(pattern)
s = Clean(s)
}
ok, err := Match(pattern, s)
if ok != tt.match || err != tt.err { if ok != tt.match || err != tt.err {
t.Errorf("Match(%#q, %#q) = %v, %q want %v, %q", tt.pattern, tt.s, ok, errp(err), tt.match, errp(tt.err)) t.Errorf("Match(%#q, %#q) = %v, %q want %v, %q", pattern, s, ok, errp(err), tt.match, errp(tt.err))
} }
} }
} }
// contains returns true if vector contains the string s. // contains returns true if vector contains the string s.
func contains(vector []string, s string) bool { func contains(vector []string, s string) bool {
s = ToSlash(s)
for _, elem := range vector { for _, elem := range vector {
if elem == s { if elem == s {
return true return true
@ -110,18 +116,20 @@ var globTests = []struct {
} }
func TestGlob(t *testing.T) { func TestGlob(t *testing.T) {
if runtime.GOOS == "windows" {
// XXX: Don't pass for windows.
return
}
for _, tt := range globTests { for _, tt := range globTests {
matches, err := Glob(tt.pattern) pattern := tt.pattern
result := tt.result
if runtime.GOOS == "windows" {
pattern = Clean(pattern)
result = Clean(result)
}
matches, err := Glob(pattern)
if err != nil { if err != nil {
t.Errorf("Glob error for %q: %s", tt.pattern, err) t.Errorf("Glob error for %q: %s", pattern, err)
continue continue
} }
if !contains(matches, tt.result) { if !contains(matches, result) {
t.Errorf("Glob(%#q) = %#v want %v", tt.pattern, matches, tt.result) t.Errorf("Glob(%#q) = %#v want %v", pattern, matches, result)
} }
} }
for _, pattern := range []string{"no_match", "../*/no_match"} { for _, pattern := range []string{"no_match", "../*/no_match"} {

View File

@ -66,9 +66,10 @@ type Type interface {
// It returns an empty string for unnamed types. // It returns an empty string for unnamed types.
Name() string Name() string
// PkgPath returns the type's package path. // PkgPath returns a named type's package path, that is, the import path
// The package path is a full package import path like "encoding/base64". // that uniquely identifies the package, such as "encoding/base64".
// PkgPath returns an empty string for unnamed or predeclared types. // If the type was predeclared (string, error) or unnamed (*T, struct{}, []int),
// the package path will be the empty string.
PkgPath() string PkgPath() string
// Size returns the number of bytes needed to store // Size returns the number of bytes needed to store
@ -351,11 +352,18 @@ type structType struct {
// Method represents a single method. // Method represents a single method.
type Method struct { type Method struct {
PkgPath string // empty for uppercase Name // Name is the method name.
// PkgPath is the package path that qualifies a lower case (unexported)
// method name. It is empty for upper case (exported) method names.
// The combination of PkgPath and Name uniquely identifies a method
// in a method set.
// See http://golang.org/ref/spec#Uniqueness_of_identifiers
Name string Name string
Type Type PkgPath string
Func Value
Index int Type Type // method type
Func Value // func with receiver as first argument
Index int // index for Type.Method
} }
// High bit says whether type has // High bit says whether type has
@ -695,14 +703,20 @@ func (t *interfaceType) MethodByName(name string) (m Method, ok bool) {
return return
} }
// A StructField describes a single field in a struct.
type StructField struct { type StructField struct {
PkgPath string // empty for uppercase Name // Name is the field name.
Name string // PkgPath is the package path that qualifies a lower case (unexported)
Type Type // field name. It is empty for upper case (exported) field names.
Tag StructTag // See http://golang.org/ref/spec#Uniqueness_of_identifiers
Offset uintptr Name string
Index []int PkgPath string
Anonymous bool
Type Type // field type
Tag StructTag // field tag string
Offset uintptr // offset within struct, in bytes
Index []int // index sequence for Type.FieldByIndex
Anonymous bool // is an anonymous field
} }
// A StructTag is the tag string in a struct field. // A StructTag is the tag string in a struct field.

View File

@ -1624,6 +1624,15 @@ func MakeSlice(typ Type, len, cap int) Value {
if typ.Kind() != Slice { if typ.Kind() != Slice {
panic("reflect.MakeSlice of non-slice type") panic("reflect.MakeSlice of non-slice type")
} }
if len < 0 {
panic("reflect.MakeSlice: negative len")
}
if cap < 0 {
panic("reflect.MakeSlice: negative cap")
}
if len > cap {
panic("reflect.MakeSlice: len > cap")
}
// Declare slice so that gc can see the base pointer in it. // Declare slice so that gc can see the base pointer in it.
var x []byte var x []byte

View File

@ -183,17 +183,21 @@ func quickSort(data Interface, a, b, maxDepth int) {
} }
} }
// Sort sorts data.
// It makes one call to data.Len to determine n, and O(n*log(n)) calls to
// data.Less and data.Swap. The sort is not guaranteed to be stable.
func Sort(data Interface) { func Sort(data Interface) {
// Switch to heapsort if depth of 2*ceil(lg(n)) is reached. // Switch to heapsort if depth of 2*ceil(lg(n+1)) is reached.
n := data.Len() n := data.Len()
maxDepth := 0 maxDepth := 0
for 1<<uint(maxDepth) < n { for i := n; i > 0; i >>= 1 {
maxDepth++ maxDepth++
} }
maxDepth *= 2 maxDepth *= 2
quickSort(data, 0, n, maxDepth) quickSort(data, 0, n, maxDepth)
} }
// IsSorted reports whether data is sorted.
func IsSorted(data Interface) bool { func IsSorted(data Interface) bool {
n := data.Len() n := data.Len()
for i := n - 1; i > 0; i-- { for i := n - 1; i > 0; i-- {

View File

@ -369,6 +369,7 @@ func (s *state) evalVariableNode(dot reflect.Value, v *parse.VariableNode, args
// $x.Field has $x as the first ident, Field as the second. Eval the var, then the fields. // $x.Field has $x as the first ident, Field as the second. Eval the var, then the fields.
value := s.varValue(v.Ident[0]) value := s.varValue(v.Ident[0])
if len(v.Ident) == 1 { if len(v.Ident) == 1 {
s.notAFunction(args, final)
return value return value
} }
return s.evalFieldChain(dot, value, v.Ident[1:], args, final) return s.evalFieldChain(dot, value, v.Ident[1:], args, final)

View File

@ -466,6 +466,10 @@ var execTests = []execTest{
{"bug6b", "{{vfunc .V0 .V0}}", "vfunc", tVal, true}, {"bug6b", "{{vfunc .V0 .V0}}", "vfunc", tVal, true},
{"bug6c", "{{vfunc .V1 .V0}}", "vfunc", tVal, true}, {"bug6c", "{{vfunc .V1 .V0}}", "vfunc", tVal, true},
{"bug6d", "{{vfunc .V1 .V1}}", "vfunc", tVal, true}, {"bug6d", "{{vfunc .V1 .V1}}", "vfunc", tVal, true},
// Legal parse but illegal execution: non-function should have no arguments.
{"bug7a", "{{3 2}}", "", tVal, false},
{"bug7b", "{{$x := 1}}{{$x 2}}", "", tVal, false},
{"bug7c", "{{$x := 1}}{{3 | $x}}", "", tVal, false},
} }
func zeroArgs() string { func zeroArgs() string {

View File

@ -93,7 +93,7 @@ var multiExecTests = []execTest{
{"invoke dot []int", `{{template "dot" .SI}}`, "[3 4 5]", tVal, true}, {"invoke dot []int", `{{template "dot" .SI}}`, "[3 4 5]", tVal, true},
{"invoke dotV", `{{template "dotV" .U}}`, "v", tVal, true}, {"invoke dotV", `{{template "dotV" .U}}`, "v", tVal, true},
{"invoke nested int", `{{template "nested" .I}}`, "17", tVal, true}, {"invoke nested int", `{{template "nested" .I}}`, "17", tVal, true},
{"variable declared by template", `{{template "nested" $x=.SI}},{{index $x 1}}`, "[3 4 5],4", tVal, true}, {"variable declared by template", `{{template "nested" $x:=.SI}},{{index $x 1}}`, "[3 4 5],4", tVal, true},
// User-defined function: test argument evaluator. // User-defined function: test argument evaluator.
{"testFunc literal", `{{oneArg "joe"}}`, "oneArg=joe", tVal, true}, {"testFunc literal", `{{oneArg "joe"}}`, "oneArg=joe", tVal, true},

View File

@ -347,6 +347,9 @@ Loop:
default: default:
l.backup() l.backup()
word := l.input[l.start:l.pos] word := l.input[l.start:l.pos]
if !l.atTerminator() {
return l.errorf("unexpected character %+U", r)
}
switch { switch {
case key[word] > itemKeyword: case key[word] > itemKeyword:
l.emit(key[word]) l.emit(key[word])
@ -365,6 +368,28 @@ Loop:
return lexInsideAction return lexInsideAction
} }
// atTerminator reports whether the input is at valid termination character to
// appear after an identifier. Mostly to catch cases like "$x+2" not being
// acceptable without a space, in case we decide one day to implement
// arithmetic.
func (l *lexer) atTerminator() bool {
r := l.peek()
if isSpace(r) {
return true
}
switch r {
case eof, ',', '|', ':':
return true
}
// Does r start the delimiter? This can be ambiguous (with delim=="//", $x/2 will
// succeed but should fail) but only in extremely rare cases caused by willfully
// bad choice of delimiter.
if rd, _ := utf8.DecodeRuneInString(l.rightDelim); rd == r {
return true
}
return false
}
// lexChar scans a character constant. The initial quote is already // lexChar scans a character constant. The initial quote is already
// scanned. Syntax checking is done by the parse. // scanned. Syntax checking is done by the parse.
func lexChar(l *lexer) stateFn { func lexChar(l *lexer) stateFn {

View File

@ -326,7 +326,7 @@ func (t *Tree) pipeline(context string) (pipe *PipeNode) {
for { for {
if v := t.peek(); v.typ == itemVariable { if v := t.peek(); v.typ == itemVariable {
t.next() t.next()
if next := t.peek(); next.typ == itemColonEquals || next.typ == itemChar { if next := t.peek(); next.typ == itemColonEquals || (next.typ == itemChar && next.val == ",") {
t.next() t.next()
variable := newVariable(v.val) variable := newVariable(v.val)
if len(variable.Ident) != 1 { if len(variable.Ident) != 1 {

View File

@ -201,6 +201,10 @@ var parseTests = []parseTest{
`{{range .X | .M}}"true"{{else}}"false"{{end}}`}, `{{range .X | .M}}"true"{{else}}"false"{{end}}`},
{"range []int", "{{range .SI}}{{.}}{{end}}", noError, {"range []int", "{{range .SI}}{{.}}{{end}}", noError,
`{{range .SI}}{{.}}{{end}}`}, `{{range .SI}}{{.}}{{end}}`},
{"range 1 var", "{{range $x := .SI}}{{.}}{{end}}", noError,
`{{range $x := .SI}}{{.}}{{end}}`},
{"range 2 vars", "{{range $x, $y := .SI}}{{.}}{{end}}", noError,
`{{range $x, $y := .SI}}{{.}}{{end}}`},
{"constants", "{{range .SI 1 -3.2i true false 'a'}}{{end}}", noError, {"constants", "{{range .SI 1 -3.2i true false 'a'}}{{end}}", noError,
`{{range .SI 1 -3.2i true false 'a'}}{{end}}`}, `{{range .SI 1 -3.2i true false 'a'}}{{end}}`},
{"template", "{{template `x`}}", noError, {"template", "{{template `x`}}", noError,
@ -226,6 +230,17 @@ var parseTests = []parseTest{
{"invalid punctuation", "{{printf 3, 4}}", hasError, ""}, {"invalid punctuation", "{{printf 3, 4}}", hasError, ""},
{"multidecl outside range", "{{with $v, $u := 3}}{{end}}", hasError, ""}, {"multidecl outside range", "{{with $v, $u := 3}}{{end}}", hasError, ""},
{"too many decls in range", "{{range $u, $v, $w := 3}}{{end}}", hasError, ""}, {"too many decls in range", "{{range $u, $v, $w := 3}}{{end}}", hasError, ""},
// Equals (and other chars) do not assignments make (yet).
{"bug0a", "{{$x := 0}}{{$x}}", noError, "{{$x := 0}}{{$x}}"},
{"bug0b", "{{$x = 1}}{{$x}}", hasError, ""},
{"bug0c", "{{$x ! 2}}{{$x}}", hasError, ""},
{"bug0d", "{{$x % 3}}{{$x}}", hasError, ""},
// Check the parse fails for := rather than comma.
{"bug0e", "{{range $x := $y := 3}}{{end}}", hasError, ""},
// Another bug: variable read must ignore following punctuation.
{"bug1a", "{{$x:=.}}{{$x!2}}", hasError, ""}, // ! is just illegal here.
{"bug1b", "{{$x:=.}}{{$x+2}}", hasError, ""}, // $x+2 should not parse as ($x) (+2).
{"bug1c", "{{$x:=.}}{{$x +2}}", noError, "{{$x := .}}{{$x +2}}"}, // It's OK with a space.
} }
var builtins = map[string]interface{}{ var builtins = map[string]interface{}{

View File

@ -163,7 +163,7 @@ done
done done
done done
runtime="chan.c cpuprof.c goc2c.c lock_futex.c lock_sema.c mcache.c mcentral.c mfinal.c mfixalloc.c mgc0.c mheap.c msize.c proc.c runtime.c runtime.h signal_unix.c malloc.h malloc.goc mprof.goc runtime1.goc sema.goc sigqueue.goc string.goc time.goc" runtime="chan.c cpuprof.c lock_futex.c lock_sema.c mcache.c mcentral.c mfinal.c mfixalloc.c mgc0.c mheap.c msize.c proc.c runtime.c runtime.h signal_unix.c malloc.h malloc.goc mprof.goc runtime1.goc sema.goc sigqueue.goc string.goc time.goc"
for f in $runtime; do for f in $runtime; do
merge_c $f $f merge_c $f $f
done done

View File

@ -966,6 +966,11 @@ runtime_mstart(void* mp)
} }
#endif #endif
// Install signal handlers; after minit so that minit can
// prepare the thread to be able to handle the signals.
if(m == &runtime_m0)
runtime_initsig();
schedule(nil); schedule(nil);
return nil; return nil;
} }

View File

@ -74,7 +74,7 @@ void
runtime_panicstring(const char *s) runtime_panicstring(const char *s)
{ {
Eface err; Eface err;
if(runtime_m()->gcing) { if(runtime_m()->gcing) {
runtime_printf("panic: %s\n", s); runtime_printf("panic: %s\n", s);
runtime_throw("panic during gc"); runtime_throw("panic during gc");
@ -101,7 +101,7 @@ runtime_goargs(void)
{ {
String *s; String *s;
int32 i; int32 i;
// for windows implementation see "os" package // for windows implementation see "os" package
if(Windows) if(Windows)
return; return;
@ -119,7 +119,7 @@ runtime_goenvs_unix(void)
{ {
String *s; String *s;
int32 i, n; int32 i, n;
for(n=0; argv[argc+1+n] != 0; n++) for(n=0; argv[argc+1+n] != 0; n++)
; ;
@ -195,8 +195,6 @@ void
runtime_check(void) runtime_check(void)
{ {
__go_register_gc_roots(&runtime_roots); __go_register_gc_roots(&runtime_roots);
runtime_initsig ();
} }
int64 int64