[SCM] Packaging for Google Go branch, weekly-upstream-sid, updated. upstream-weekly/2011.06.23-1-gab23f6d

Ondřej Surý ondrej at sury.org
Mon Jul 18 09:31:21 UTC 2011


The following commit has been merged in the weekly-upstream-sid branch:
commit ab23f6dab91e6ec615481c4b3e77e4639c3f871b
Author: Ondřej Surý <ondrej at sury.org>
Date:   Fri Jul 8 09:16:22 2011 +0200

    Imported Upstream version 2011.07.07

diff --git a/AUTHORS b/AUTHORS
index 5471a8f..f9af1a7 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -16,6 +16,7 @@ Alexander Orlov <alexander.orlov at loxal.net>
 Alexey Borzenkov <snaury at gmail.com>
 Amrut Joshi <amrut.joshi at gmail.com>
 Andrei Vieru <euvieru at gmail.com>
+Andrew Balholm <andybalholm at gmail.com>
 Andrew Skiba <skibaa at gmail.com>
 Andrey Mirtchovski <mirtchovski at gmail.com>
 Andy Davis <andy at bigandian.com>
@@ -60,6 +61,7 @@ Fazlul Shahriar <fshahriar at gmail.com>
 Firmansyah Adiputra <frm.adiputra at gmail.com>
 Florian Uekermann <florian at uekermann-online.de>
 Gary Burd <gary at beagledreams.com>
+Gideon Jan-Wessel Redelinghuys <gjredelinghuys at gmail.com>
 Giles Lean <giles.lean at pobox.com>
 Google Inc.
 Graham Miller <graham.miller at gmail.com>
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index e503775..8bb57f9 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -40,6 +40,7 @@ Alexander Orlov <alexander.orlov at loxal.net>
 Alexey Borzenkov <snaury at gmail.com>
 Amrut Joshi <amrut.joshi at gmail.com>
 Andrei Vieru <euvieru at gmail.com>
+Andrew Balholm <andybalholm at gmail.com>
 Andrew Gerrand <adg at golang.org>
 Andrew Skiba <skibaa at gmail.com>
 Andrey Mirtchovski <mirtchovski at gmail.com>
@@ -100,6 +101,7 @@ Firmansyah Adiputra <frm.adiputra at gmail.com>
 Florian Uekermann <florian at uekermann-online.de> <f1 at uekermann-online.de>
 Fumitoshi Ukai <ukai at google.com>
 Gary Burd <gary at beagledreams.com> <gary.burd at gmail.com>
+Gideon Jan-Wessel Redelinghuys <gjredelinghuys at gmail.com>
 Giles Lean <giles.lean at pobox.com>
 Graham Miller <graham.miller at gmail.com>
 Gustavo Niemeyer <gustavo at niemeyer.net> <n13m3y3r at gmail.com>
@@ -141,12 +143,13 @@ Ken Thompson <ken at golang.org>
 Kevin Ballard <kevin at sb.org>
 Kirklin McDonald <kirklin.mcdonald at gmail.com>
 Kyle Consalus <consalus at gmail.com>
-Kyle Lemons <kyle at kylelemons.net> <etherealflaim at gmail.com>
+Kyle Lemons <kyle at kylelemons.net> <kevlar at google.com>
 Larry Hosken <lahosken at golang.org>
 Lorenzo Stoakes <lstoakes at gmail.com>
 Lucio De Re <lucio.dere at gmail.com>
 Luit van Drongelen <luitvd at gmail.com>
 Luuk van Dijk <lvd at golang.org> <lvd at google.com>
+Marcel van Lohuizen <mpvl at golang.org>
 Mark Zavislak <zavislak at google.com>
 Markus Duft <markus.duft at salomon.at>
 Martin Neubauer <m.ne at gmx.net>
@@ -171,6 +174,7 @@ Padraig Kitterick <padraigkitterick at gmail.com>
 Paolo Giarrusso <p.giarrusso at gmail.com>
 Pascal S. de Kloe <pascal at quies.net>
 Patrick Gavlin <pgavlin at gmail.com>
+Paul Borman <borman at google.com>
 Petar Maymounkov <petarm at gmail.com>
 Peter Froehlich <peter.hans.froehlich at gmail.com>
 Peter McKenzie <petermck at google.com>
diff --git a/doc/devel/release.html b/doc/devel/release.html
index 84ca622..d632200 100644
--- a/doc/devel/release.html
+++ b/doc/devel/release.html
@@ -14,6 +14,78 @@ hg pull
 hg update release.r<i>NN</i>
 </pre>
 
+<h2 id="r58">r58 (released 2011/06/29)</h2>
+
+<p>
+The r58 release corresponds to 
+<code><a href="weekly.html#2011-06-09">weekly.2011-06-09</a></code>
+with additional bug fixes.
+This section highlights the most significant changes in this release.
+For a more detailed summary, see the
+<a href="weekly.html#2011-06-09">weekly release notes</a>.
+For complete information, see the
+<a href="http://code.google.com/p/go/source/list?r=release-branch.r58">Mercurial change list</a>.
+</p>
+
+<h3 id="r58.lang">Language</h3>
+
+<p>
+This release fixes a <a href="http://code.google.com/p/go/source/detail?r=b720749486e1">use of uninitialized memory in programs that misuse <code>goto</code></a>.
+</p>
+
+<h3 id="r58.pkg">Packages</h3>
+
+<p>
+As usual, <a href="/cmd/gofix/">gofix</a> will handle the bulk of the rewrites
+necessary for these changes to package APIs.
+</p>
+
+<p>
+<a href="/pkg/http/">Package http</a> drops the <code>finalURL</code> return
+value from the <a href="/pkg/http/#Client.Get">Client.Get</a> method. The value
+is now available via the new <code>Request</code> field on <a
+href="/pkg/http/#Response">http.Response</a>.
+Most instances of the type map[string][]string in have been
+replaced with the new <a href="/pkg/http/#Values">Values</a> type.
+</p>
+
+<p>
+<a href="/pkg/exec/">Package exec</a> has been redesigned with a more
+convenient and succinct API.
+</p>
+
+<p>
+<a href="/pkg/strconv/">Package strconv</a>'s <a href="/pkg/strconv/#Quote">Quote</a>
+function now escapes only those Unicode code points not classified as printable
+by <a href="/pkg/unicode/#IsPrint">unicode.IsPrint</a>.
+Previously Quote would escape all non-ASCII characters.
+This also affects the <a href="/pkg/fmt/">fmt</a> package's <code>"%q"</code>
+formatting directive. The previous quoting behavior is still available via
+strconv's new <a href="/pkg/strconv/#QuoteToASCII">QuoteToASCII</a> function.   
+</p>
+
+<p>
+<a href="/pkg/os/signal/">Package os/signal</a>'s
+<a href="/pkg/os/#Signal">Signal</a> and 
+<a href="/pkg/os/#UnixSignal">UnixSignal</a> types have been moved to the
+<a href="/pkg/os/">os</a> package.
+</p>
+
+<p>
+<a href="/pkg/image/draw/">Package image/draw</a> is the new name for
+<code>exp/draw</code>. The GUI-related code from <code>exp/draw</code> is now
+located in the <a href="/pkg/exp/gui/">exp/gui</a> package.
+</p>
+
+<h3 id="r58.cmd">Tools</h3>
+
+<p>
+<a href="/cmd/goinstall/">Goinstall</a> now observes the GOPATH environment
+variable to build and install your own code and external libraries outside of
+the Go tree (and avoid writing Makefiles).
+</p>
+
+
 <h2 id="r57">r57 (released 2011/05/03)</h2>
 
 <p>
diff --git a/doc/devel/weekly.html b/doc/devel/weekly.html
index 0a043d4..bf16c83 100644
--- a/doc/devel/weekly.html
+++ b/doc/devel/weekly.html
@@ -14,6 +14,112 @@ hg pull
 hg update weekly.<i>YYYY-MM-DD</i>
 </pre>
 
+<h2 id="2011-07-07">2011-07-07</h2>
+
+<pre>
+This weekly snapshot includes changes to the strings, http, reflect, json, and
+xml packages. Code that uses these packages will need changes. Most of these
+changes can be made automatically with gofix.
+
+The strings package's Split function has itself been split into Split and
+SplitN. SplitN is the same as the old Split. The new Split is equivalent to
+SplitN with a final argument of -1.
+
+The http package has a new FileSystem interface that provides access to files.
+The FileServer helper now takes a FileSystem argument instead of an explicit
+file system root. By implementing your own FileSystem you can use the
+FileServer to serve arbitrary data.
+
+The reflect package supports a new struct tag scheme that enables sharing of
+struct tags between multiple packages.
+In this scheme, the tags must be of the form:
+        key:"value" key2:"value2"
+reflect.StructField's Tag field now has type StructTag (a string type), which
+has method Get(key string) string that returns the associated value.
+Clients of json and xml will need to be updated. Code that says
+        type T struct {
+                X int "name"
+        }
+should become
+        type T struct {
+                X int `json:"name"`  // or `xml:"name"`
+        }
+Use govet to identify struct tags that need to be changed to use the new syntax.
+
+Other changes:
+* 5l, 6l, 8l: drop use of ed during build.
+* asn1: support T61 and UTF8 string.
+* bufio: do not cache Read errors (thanks Graham Miller).
+* build: make version.bash aware of branches.
+* cgi: don't depend on CGI.pm for tests.
+* codereview: make --ignore_hgpatch_failure work again,
+	restrict sync to default branch.
+* crypto/openpgp: add ability to reserialize keys,
+	bug fix (thanks Gideon Jan-Wessel Redelinghuys).
+* crypto/tls: fix generate_cert.go.
+* crypto/x509: prevent chain cycles in Verify.
+* csv: new package.
+* doc: remove ed from apt-get package list.
+* docs: fold the prog.sh scripting from makehtml into htmlgen itself.
+* ebnflint: better handling of stdin.
+* exp/regexp/syntax: new experimental RE2-based regexp implementation.
+* exp/template: a new experimental templating package.
+* fmt: add SkipSpace to fmt's ScanState interface.
+* fmt: rename errno and error to err for doc consistency.
+* gc: avoid package name ambiguity in error messages,
+	fix package quoting logic,
+	fixes for Plan 9 (thanks Lucio De Re).
+* go/build: evaluate symlinks before comparing path to GOPATH.
+* gob: use exported fields in structs in the package documentation.
+* godoc: ignore directories that begin with '.',
+	search GOPATH for documentation.
+* gofix: os/signal, path/filepath, and sort fixes (thanks Robert Hencke),
+* goinstall: add support for generic hosts (thanks Julian Phillips),
+	only report successfully-installed packages to the dashboard,
+	try to access via https (thanks Yasuhiro Matsumoto).
+* gotest: add -test.benchtime and -test.cpu flags.
+* html: fixes and improvements (thanks Yasuhiro Matsumoto).
+* http/cgi: add Handler.Dir to specify working directory (thanks Yasuhiro Matsumoto).
+* http: add StripPrefix handler wrapper,
+	assume ContentLength 0 on GET requests,
+	better handling of 0-length Request.Body,
+	do TLS handshake explicitly before copying TLS state,
+	document that ServerConn and ClientConn are low-level,
+	make NewChunkedReader public (thanks Andrew Balholm),
+	respect Handlers setting Connection: close in their response.
+* image: more tests, Paletted.Opaque optimization.
+* io.WriteString: if the object has a WriteString method, use it (thanks Evan Shaw).
+* ld: elide the Go symbol table when using -s (thanks Anthony Martin).
+* ld: fix ELF strip by removing overlap of sections (thanks Gustavo Niemeyer).
+* mime/multipart: parse LF-delimited messages, not just CRLF.
+* mime: permit lower-case media type parameters (thanks Pascal S. de Kloe).
+* misc/dashboard: new features and improvements (not yet deployed).
+* misc/emacs: update list of builtins (thanks Quan Yong Zhai).
+* misc/vim: allow only utf-8 for file encoding (thanks Yasuhiro Matsumoto).
+* os: fix documentation for FileInfo.Name,
+	simplify WriteString,
+	use a different symbol from syscall in mkunixsignals.sh.
+* path/filepath: enable TestWalk to run on windows (thanks Alex Brainman).
+* reflect: add MethodByName,
+	allow Len on String values.
+* regexp: document that Regexp is thread-safe.
+* runtime/cgo: check for errors from pthread_create (thanks Albert Strasheim).
+* runtime: add Semacquire/Semrelease benchmarks,
+	improved Semacquire/Semrelease implementation,
+	windows/amd64 port (thanks Wei Guangjing).
+* sync: add fast path to Once,
+	improve Mutex to allow successive acquisitions,
+	new and improved benchmarks.
+* syscall: regenerate zerrors for darwin/linux/freebsd,
+	support for tty options in StartProcess (thanks Ken Rockot).
+* testing: make ResetTimer not start/stop the timer,
+	scale benchmark precision to 0.01ns if needed.
+* time: zero-pad two-digit years.
+* unicode/maketables: update debugging data.
+* windows: define and use syscall.Handle (thanks Wei Guangjing).
+* xml: add Marshal and MarshalIndent.
+</pre>
+
 <h2 id="2011-06-23">2011-06-23</h2>
 
 <pre>
@@ -128,7 +234,7 @@ Other changes:
 * xml: handle non-string attribute fields (thanks Maxim Ushakov).
 </pre>
 
-<h2 id="2011-06-09">2011-06-09</h2>
+<h2 id="2011-06-09">2011-06-09 (<a href="release.html#r58">base for r58</a>)</h2>
 
 <pre>
 This release includes changes to the strconv, http, and exp/draw packages.
diff --git a/doc/go_tutorial.html b/doc/go_tutorial.html
index 4f3f6b9..822f962 100644
--- a/doc/go_tutorial.html
+++ b/doc/go_tutorial.html
@@ -26,14 +26,14 @@ cleanliness, blank lines remain blank.
 <p>
 Let's start in the usual way:
 <p>
-<pre> <!-- progs/helloworld.go /package/ END -->
-05    package main
+<pre><!-- progs/helloworld.go /package/ $
+-->package main
 
-07    import fmt "fmt"  // Package implementing formatted I/O.
+import fmt "fmt"  // Package implementing formatted I/O.
 
-09    func main() {
-10        fmt.Printf("Hello, world; or Καλημέρα κόσμε; or こんにちは 世界\n")
-11    }
+func main() {
+    fmt.Printf("Hello, world; or Καλημέρα κόσμε; or こんにちは 世界\n")
+}
 </pre>
 <p>
 Every Go source file declares, using a <code>package</code> statement, which package it's part of.
@@ -51,8 +51,8 @@ String constants can contain Unicode characters, encoded in UTF-8.
 The comment convention is the same as in C++:
 <p>
 <pre>
-    /* ... */
-    // ...
+/* ... */
+// ...
 </pre>
 <p>
 Later we'll have much more to say about printing.
@@ -96,67 +96,67 @@ a more robust run-time system although <code>gccgo</code> is catching up.
 Here's how to compile and run our program.  With <code>6g</code>, say,
 <p>
 <pre>
-    $ 6g helloworld.go  # compile; object goes into helloworld.6
-    $ 6l helloworld.6   # link; output goes into 6.out
-    $ 6.out
-    Hello, world; or Καλημέρα κόσμε; or こんにちは 世界
-    $
+$ 6g helloworld.go  # compile; object goes into helloworld.6
+$ 6l helloworld.6   # link; output goes into 6.out
+$ 6.out
+Hello, world; or Καλημέρα κόσμε; or こんにちは 世界
+$
 </pre>
 <p>
 With <code>gccgo</code> it looks a little more traditional.
 <p>
 <pre>
-    $ gccgo helloworld.go
-    $ a.out
-    Hello, world; or Καλημέρα κόσμε; or こんにちは 世界
-    $
+$ gccgo helloworld.go
+$ a.out
+Hello, world; or Καλημέρα κόσμε; or こんにちは 世界
+$
 </pre>
 <p>
 <h2>Echo</h2>
 <p>
 Next up, here's a version of the Unix utility <code>echo(1)</code>:
 <p>
-<pre> <!-- progs/echo.go /package/ END -->
-05    package main
+<pre><!-- progs/echo.go /package/ $
+-->package main
 
-07    import (
-08        "os"
-09        "flag"  // command line option parser
-10    )
+import (
+    "os"
+    "flag"  // command line option parser
+)
 
-12    var omitNewline = flag.Bool("n", false, "don't print final newline")
+var omitNewline = flag.Bool("n", false, "don't print final newline")
 
-14    const (
-15        Space = " "
-16        Newline = "\n"
-17    )
+const (
+    Space = " "
+    Newline = "\n"
+)
 
-19    func main() {
-20        flag.Parse()   // Scans the arg list and sets up flags
-21        var s string = ""
-22        for i := 0; i < flag.NArg(); i++ {
-23            if i > 0 {
-24                s += Space
-25            }
-26            s += flag.Arg(i)
-27        }
-28        if !*omitNewline {
-29            s += Newline
-30        }
-31        os.Stdout.WriteString(s)
-32    }
+func main() {
+    flag.Parse()   // Scans the arg list and sets up flags
+    var s string = ""
+    for i := 0; i < flag.NArg(); i++ {
+        if i > 0 {
+            s += Space
+        }
+        s += flag.Arg(i)
+    }
+    if !*omitNewline {
+        s += Newline
+    }
+    os.Stdout.WriteString(s)
+}
 </pre>
 <p>
 This program is small but it's doing a number of new things.  In the last example,
 we saw <code>func</code> introduce a function.  The keywords <code>var</code>, <code>const</code>, and <code>type</code>
 (not used yet) also introduce declarations, as does <code>import</code>.
 Notice that we can group declarations of the same sort into
-parenthesized lists, one item per line, as on lines 7-10 and 14-17.
+parenthesized lists, one item per line, as in the <code>import</code> and <code>const</code> clauses here.
 But it's not necessary to do so; we could have said
 <p>
 <pre>
-    const Space = " "
-    const Newline = "\n"
+const Space = " "
+const Newline = "\n"
 </pre>
 <p>
 This program imports the <code>"os"</code> package to access its <code>Stdout</code> variable, of type
@@ -186,7 +186,7 @@ string variable we will use to build the output.
 The declaration statement has the form
 <p>
 <pre>
-    var s string = ""
+var s string = ""
 </pre>
 <p>
 This is the <code>var</code> keyword, followed by the name of the variable, followed by
@@ -197,20 +197,20 @@ string constant is of type string, we don't have to tell the compiler that.
 We could write
 <p>
 <pre>
-    var s = ""
+var s = ""
 </pre>
 <p>
 or we could go even shorter and write the idiom
 <p>
 <pre>
-    s := ""
+s := ""
 </pre>
 <p>
 The <code>:=</code> operator is used a lot in Go to represent an initializing declaration.
 There's one in the <code>for</code> clause on the next line:
 <p>
-<pre> <!-- progs/echo.go /for/ -->
-22        for i := 0; i < flag.NArg(); i++ {
+<pre><!--  progs/echo.go /for/
+-->    for i := 0; i < flag.NArg(); i++ {
 </pre>
 <p>
 The <code>flag</code> package has parsed the arguments and left the non-flag arguments
@@ -231,7 +231,7 @@ It's defined that way.  Falling off the end of <code>main.main</code> means
 ''success''; if you want to signal an erroneous return, call
 <p>
 <pre>
-    os.Exit(1)
+os.Exit(1)
 </pre>
 <p>
 The <code>os</code> package contains other essentials for getting
@@ -259,20 +259,20 @@ Once you've built a string <i>value</i>, you can't change it, although
 of course you can change a string <i>variable</i> simply by
 reassigning it.  This snippet from <code>strings.go</code> is legal code:
 <p>
-<pre> <!-- progs/strings.go /hello/ /ciao/ -->
-10        s := "hello"
-11        if s[1] != 'e' { os.Exit(1) }
-12        s = "good bye"
-13        var p *string = &s
-14        *p = "ciao"
+<pre><!-- progs/strings.go /hello/ /ciao/
+-->    s := "hello"
+    if s[1] != 'e' { os.Exit(1) }
+    s = "good bye"
+    var p *string = &s
+    *p = "ciao"
 </pre>
 <p>
 However the following statements are illegal because they would modify
 a <code>string</code> value:
 <p>
 <pre>
-    s[0] = 'x'
-    (*p)[1] = 'y'
+s[0] = 'x'
+(*p)[1] = 'y'
 </pre>
 <p>
 In C++ terms, Go strings are a bit like <code>const strings</code>, while pointers
@@ -284,7 +284,7 @@ read on.
 Arrays are declared like this:
 <p>
 <pre>
-    var arrayOfInt [10]int
+var arrayOfInt [10]int
 </pre>
 <p>
 Arrays, like strings, are values, but they are mutable. This differs
@@ -315,7 +315,7 @@ expression formed
 from a type followed by a brace-bounded expression like this:
 <p>
 <pre>
-    [3]int{1,2,3}
+[3]int{1,2,3}
 </pre>
 <p>
 In this case the constructor builds an array of 3 <code>ints</code>.
@@ -330,14 +330,14 @@ will slice the whole array.
 <p>
 Using slices one can write this function (from <code>sum.go</code>):
 <p>
-<pre> <!-- progs/sum.go /sum/ /^}/ -->
-09    func sum(a []int) int { // returns an int
-10        s := 0
-11        for i := 0; i < len(a); i++ {
-12            s += a[i]
-13        }
-14        return s
-15    }
+<pre><!-- progs/sum.go /sum/ /^}/
+-->func sum(a []int) int { // returns an int
+    s := 0
+    for i := 0; i < len(a); i++ {
+        s += a[i]
+    }
+    return s
+}
 </pre>
 <p>
 Note how the return type (<code>int</code>) is defined for <code>sum</code> by stating it
@@ -348,14 +348,14 @@ a simpler way in a moment) constructs
 an array and slices it:
 <p>
 <pre>
-    s := sum([3]int{1,2,3}[:])
+s := sum([3]int{1,2,3}[:])
 </pre>
 <p>
 If you are creating a regular array but want the compiler to count the
 elements for you, use <code>...</code> as the array size:
 <p>
 <pre>
-    s := sum([...]int{1,2,3}[:])
+s := sum([...]int{1,2,3}[:])
 </pre>
 <p>
 That's fussier than necessary, though.
@@ -363,13 +363,13 @@ In practice, unless you're meticulous about storage layout within a
 data structure, a slice itself—using empty brackets with no size—is all you need:
 <p>
 <pre>
-    s := sum([]int{1,2,3})
+s := sum([]int{1,2,3})
 </pre>
 <p>
 There are also maps, which you can initialize like this:
 <p>
 <pre>
-    m := map[string]int{"one":1 , "two":2}
+m := map[string]int{"one":1 , "two":2}
 </pre>
 <p>
 The built-in function <code>len</code>, which returns number of elements,
@@ -380,13 +380,13 @@ By the way, another thing that works on strings, arrays, slices, maps
 and channels is the <code>range</code> clause on <code>for</code> loops.  Instead of writing
 <p>
 <pre>
-    for i := 0; i < len(a); i++ { ... }
+for i := 0; i < len(a); i++ { ... }
 </pre>
 <p>
 to loop over the elements of a slice (or map or ...) , we could write
 <p>
 <pre>
-    for i, v := range a { ... }
+for i, v := range a { ... }
 </pre>
 <p>
 This assigns <code>i</code> to the index and <code>v</code> to the value of the successive
@@ -404,14 +404,14 @@ To allocate a new variable, use the built-in function <code>new</code>, which
 returns a pointer to the allocated storage.
 <p>
 <pre>
-    type T struct { a, b int }
-    var t *T = new(T)
+type T struct { a, b int }
+var t *T = new(T)
 </pre>
 <p>
 or the more idiomatic
 <p>
 <pre>
-    t := new(T)
+t := new(T)
 </pre>
 <p>
 Some types—maps, slices, and channels (see below)—have reference semantics.
@@ -420,14 +420,14 @@ referencing the same underlying data will see the modification.  For these three
 types you want to use the built-in function <code>make</code>:
 <p>
 <pre>
-    m := make(map[string]int)
+m := make(map[string]int)
 </pre>
 <p>
 This statement initializes a new map ready to store entries.
 If you just declare the map, as in
 <p>
 <pre>
-    var m map[string]int
+var m map[string]int
 </pre>
 <p>
 it creates a <code>nil</code> reference that cannot hold anything. To use the map,
@@ -448,20 +448,20 @@ can overflow only when they are assigned to an integer variable with
 too little precision to represent the value.
 <p>
 <pre>
-    const hardEight = (1 << 100) >> 97  // legal
+const hardEight = (1 << 100) >> 97  // legal
 </pre>
 <p>
 There are nuances that deserve redirection to the legalese of the
 language specification but here are some illustrative examples:
 <p>
 <pre>
-    var a uint64 = 0  // a has type uint64, value 0
-    a := uint64(0)    // equivalent; uses a "conversion"
-    i := 0x1234       // i gets default type: int
-    var j int = 1e6   // legal - 1000000 is representable in an int
-    x := 1.5          // a float64, the default type for floating constants
-    i3div2 := 3/2     // integer division - result is 1
-    f3div2 := 3./2.   // floating-point division - result is 1.5
+var a uint64 = 0  // a has type uint64, value 0
+a := uint64(0)    // equivalent; uses a "conversion"
+i := 0x1234       // i gets default type: int
+var j int = 1e6   // legal - 1000000 is representable in an int
+x := 1.5          // a float64, the default type for floating constants
+i3div2 := 3/2     // integer division - result is 1
+f3div2 := 3./2.   // floating-point division - result is 1.5
 </pre>
 <p>
 Conversions only work for simple cases such as converting <code>ints</code> of one
@@ -476,18 +476,18 @@ assigned to a variable.
 Next we'll look at a simple package for doing file I/O with an
 open/close/read/write interface.  Here's the start of <code>file.go</code>:
 <p>
-<pre> <!-- progs/file.go /package/ /^}/ -->
-05    package file
+<pre><!-- progs/file.go /package/ /^}/
+-->package file
 
-07    import (
-08        "os"
-09        "syscall"
-10    )
+import (
+    "os"
+    "syscall"
+)
 
-12    type File struct {
-13        fd   int    // file descriptor number
-14        name string // file name at Open time
-15    }
+type File struct {
+    fd   int    // file descriptor number
+    name string // file name at Open time
+}
 </pre>
 <p>
 The first few lines declare the name of the
@@ -518,13 +518,13 @@ will soon give it some exported, upper-case methods.
 <p>
 First, though, here is a factory to create a <code>File</code>:
 <p>
-<pre> <!-- progs/file.go /newFile/ /^}/ -->
-17    func newFile(fd int, name string) *File {
-18        if fd < 0 {
-19            return nil
-20        }
-21        return &File{fd, name}
-22    }
+<pre><!-- progs/file.go /newFile/ /^}/
+-->func newFile(fd int, name string) *File {
+    if fd < 0 {
+        return nil
+    }
+    return &File{fd, name}
+}
 </pre>
 <p>
 This returns a pointer to a new <code>File</code> structure with the file descriptor and name
@@ -533,10 +533,10 @@ the ones used to build maps and arrays, to construct a new heap-allocated
 object.  We could write
 <p>
 <pre>
-    n := new(File)
-    n.fd = fd
-    n.name = name
-    return n
+n := new(File)
+n.fd = fd
+n.name = name
+return n
 </pre>
 <p>
 but for simple structures like <code>File</code> it's easier to return the address of a 
@@ -544,25 +544,26 @@ composite literal, as is done here on line 21.
 <p>
 We can use the factory to construct some familiar, exported variables of type <code>*File</code>:
 <p>
-<pre> <!-- progs/file.go /var/ /^.$/ -->
-24    var (
-25        Stdin  = newFile(syscall.Stdin, "/dev/stdin")
-26        Stdout = newFile(syscall.Stdout, "/dev/stdout")
-27        Stderr = newFile(syscall.Stderr, "/dev/stderr")
-28    )
+<pre><!-- progs/file.go /var/ /^.$/
+-->var (
+    Stdin  = newFile(syscall.Stdin, "/dev/stdin")
+    Stdout = newFile(syscall.Stdout, "/dev/stdout")
+    Stderr = newFile(syscall.Stderr, "/dev/stderr")
+)
+
 </pre>
 <p>
 The <code>newFile</code> function was not exported because it's internal. The proper,
 exported factory to use is <code>OpenFile</code> (we'll explain that name in a moment):
 <p>
-<pre> <!-- progs/file.go /func.OpenFile/ /^}/ -->
-30    func OpenFile(name string, mode int, perm uint32) (file *File, err os.Error) {
-31        r, e := syscall.Open(name, mode, perm)
-32        if e != 0 {
-33            err = os.Errno(e)
-34        }
-35        return newFile(r, name), err
-36    }
+<pre><!-- progs/file.go /func.OpenFile/ /^}/
+-->func OpenFile(name string, mode int, perm uint32) (file *File, err os.Error) {
+    r, e := syscall.Open(name, mode, perm)
+    if e != 0 {
+        err = os.Errno(e)
+    }
+    return newFile(r, name), err
+}
 </pre>
 <p>
 There are a number of new things in these few lines.  First, <code>OpenFile</code> returns
@@ -593,23 +594,23 @@ the implementation of our <code>Open</code> and <code>Create</code>; they're tri
 wrappers that eliminate common errors by capturing
 the tricky standard arguments to open and, especially, to create a file:
 <p>
-<pre> <!-- progs/file.go /^const/ /^}/ -->
-38    const (
-39        O_RDONLY = syscall.O_RDONLY
-40        O_RDWR   = syscall.O_RDWR
-41        O_CREATE = syscall.O_CREAT
-42        O_TRUNC  = syscall.O_TRUNC
-43    )
+<pre><!-- progs/file.go /^const/ /^}/
+-->const (
+    O_RDONLY = syscall.O_RDONLY
+    O_RDWR   = syscall.O_RDWR
+    O_CREATE = syscall.O_CREAT
+    O_TRUNC  = syscall.O_TRUNC
+)
 
-45    func Open(name string) (file *File, err os.Error) {
-46        return OpenFile(name, O_RDONLY, 0)
-47    }
+func Open(name string) (file *File, err os.Error) {
+    return OpenFile(name, O_RDONLY, 0)
+}
 </pre>
 <p>
-<pre> <!-- progs/file.go /func.Create/ /^}/ -->
-49    func Create(name string) (file *File, err os.Error) {
-50        return OpenFile(name, O_RDWR|O_CREATE|O_TRUNC, 0666)
-51    }
+<pre><!-- progs/file.go /func.Create/ /^}/
+-->func Create(name string) (file *File, err os.Error) {
+    return OpenFile(name, O_RDWR|O_CREATE|O_TRUNC, 0666)
+}
 </pre>
 <p>
 Back to our main story.
@@ -619,44 +620,44 @@ of that type, placed
 in parentheses before the function name. Here are some methods for <code>*File</code>,
 each of which declares a receiver variable <code>file</code>.
 <p>
-<pre> <!-- progs/file.go /Close/ END -->
-53    func (file *File) Close() os.Error {
-54        if file == nil {
-55            return os.EINVAL
-56        }
-57        e := syscall.Close(file.fd)
-58        file.fd = -1 // so it can't be closed again
-59        if e != 0 {
-60            return os.Errno(e)
-61        }
-62        return nil
-63    }
+<pre><!-- progs/file.go /Close/ $
+-->func (file *File) Close() os.Error {
+    if file == nil {
+        return os.EINVAL
+    }
+    e := syscall.Close(file.fd)
+    file.fd = -1 // so it can't be closed again
+    if e != 0 {
+        return os.Errno(e)
+    }
+    return nil
+}
 
-65    func (file *File) Read(b []byte) (ret int, err os.Error) {
-66        if file == nil {
-67            return -1, os.EINVAL
-68        }
-69        r, e := syscall.Read(file.fd, b)
-70        if e != 0 {
-71            err = os.Errno(e)
-72        }
-73        return int(r), err
-74    }
+func (file *File) Read(b []byte) (ret int, err os.Error) {
+    if file == nil {
+        return -1, os.EINVAL
+    }
+    r, e := syscall.Read(file.fd, b)
+    if e != 0 {
+        err = os.Errno(e)
+    }
+    return int(r), err
+}
 
-76    func (file *File) Write(b []byte) (ret int, err os.Error) {
-77        if file == nil {
-78            return -1, os.EINVAL
-79        }
-80        r, e := syscall.Write(file.fd, b)
-81        if e != 0 {
-82            err = os.Errno(e)
-83        }
-84        return int(r), err
-85    }
+func (file *File) Write(b []byte) (ret int, err os.Error) {
+    if file == nil {
+        return -1, os.EINVAL
+    }
+    r, e := syscall.Write(file.fd, b)
+    if e != 0 {
+        err = os.Errno(e)
+    }
+    return int(r), err
+}
 
-87    func (file *File) String() string {
-88        return file.name
-89    }
+func (file *File) String() string {
+    return file.name
+}
 </pre>
 <p>
 There is no implicit <code>this</code> and the receiver variable must be used to access
@@ -674,24 +675,24 @@ set of such error values.
 <p>
 We can now use our new package:
 <p>
-<pre> <!-- progs/helloworld3.go /package/ END -->
-05    package main
+<pre><!-- progs/helloworld3.go /package/ $
+-->package main
 
-07    import (
-08        "./file"
-09        "fmt"
-10        "os"
-11    )
+import (
+    "./file"
+    "fmt"
+    "os"
+)
 
-13    func main() {
-14        hello := []byte("hello, world\n")
-15        file.Stdout.Write(hello)
-16        f, err := file.Open("/does/not/exist")
-17        if f == nil {
-18            fmt.Printf("can't open file; err=%s\n",  err.String())
-19            os.Exit(1)
-20        }
-21    }
+func main() {
+    hello := []byte("hello, world\n")
+    file.Stdout.Write(hello)
+    f, err := file.Open("/does/not/exist")
+    if f == nil {
+        fmt.Printf("can't open file; err=%s\n",  err.String())
+        os.Exit(1)
+    }
+}
 </pre>
 <p>
 The ''<code>./</code>'' in the import of ''<code>./file</code>'' tells the compiler
@@ -703,13 +704,13 @@ package.)
 Now we can compile and run the program. On Unix, this would be the result:
 <p>
 <pre>
-    $ 6g file.go                       # compile file package
-    $ 6g helloworld3.go                # compile main package
-    $ 6l -o helloworld3 helloworld3.6  # link - no need to mention "file"
-    $ helloworld3
-    hello, world
-    can't open file; err=No such file or directory
-    $
+$ 6g file.go                       # compile file package
+$ 6g helloworld3.go                # compile main package
+$ 6l -o helloworld3 helloworld3.6  # link - no need to mention "file"
+$ helloworld3
+hello, world
+can't open file; err=No such file or directory
+$
 </pre>
 <p>
 <h2>Rotting cats</h2>
@@ -717,56 +718,56 @@ Now we can compile and run the program. On Unix, this would be the result:
 Building on the <code>file</code> package, here's a simple version of the Unix utility <code>cat(1)</code>,
 <code>progs/cat.go</code>:
 <p>
-<pre> <!-- progs/cat.go /package/ END -->
-05    package main
+<pre><!-- progs/cat.go /package/ $
+-->package main
 
-07    import (
-08        "./file"
-09        "flag"
-10        "fmt"
-11        "os"
-12    )
+import (
+    "./file"
+    "flag"
+    "fmt"
+    "os"
+)
 
-14    func cat(f *file.File) {
-15        const NBUF = 512
-16        var buf [NBUF]byte
-17        for {
-18            switch nr, er := f.Read(buf[:]); true {
-19            case nr < 0:
-20                fmt.Fprintf(os.Stderr, "cat: error reading from %s: %s\n", f.String(), er.String())
-21                os.Exit(1)
-22            case nr == 0: // EOF
-23                return
-24            case nr > 0:
-25                if nw, ew := file.Stdout.Write(buf[0:nr]); nw != nr {
-26                    fmt.Fprintf(os.Stderr, "cat: error writing from %s: %s\n", f.String(), ew.String())
-27                    os.Exit(1)
-28                }
-29            }
-30        }
-31    }
+func cat(f *file.File) {
+    const NBUF = 512
+    var buf [NBUF]byte
+    for {
+        switch nr, er := f.Read(buf[:]); true {
+        case nr < 0:
+            fmt.Fprintf(os.Stderr, "cat: error reading from %s: %s\n", f.String(), er.String())
+            os.Exit(1)
+        case nr == 0: // EOF
+            return
+        case nr > 0:
+            if nw, ew := file.Stdout.Write(buf[0:nr]); nw != nr {
+                fmt.Fprintf(os.Stderr, "cat: error writing from %s: %s\n", f.String(), ew.String())
+                os.Exit(1)
+            }
+        }
+    }
+}
 
-33    func main() {
-34        flag.Parse() // Scans the arg list and sets up flags
-35        if flag.NArg() == 0 {
-36            cat(file.Stdin)
-37        }
-38        for i := 0; i < flag.NArg(); i++ {
-39            f, err := file.Open(flag.Arg(i))
-40            if f == nil {
-41                fmt.Fprintf(os.Stderr, "cat: can't open %s: error %s\n", flag.Arg(i), err)
-42                os.Exit(1)
-43            }
-44            cat(f)
-45            f.Close()
-46        }
-47    }
+func main() {
+    flag.Parse() // Scans the arg list and sets up flags
+    if flag.NArg() == 0 {
+        cat(file.Stdin)
+    }
+    for i := 0; i < flag.NArg(); i++ {
+        f, err := file.Open(flag.Arg(i))
+        if f == nil {
+            fmt.Fprintf(os.Stderr, "cat: can't open %s: error %s\n", flag.Arg(i), err)
+            os.Exit(1)
+        }
+        cat(f)
+        f.Close()
+    }
+}
 </pre>
 <p>
 By now this should be easy to follow, but the <code>switch</code> statement introduces some
 new features.  Like a <code>for</code> loop, an <code>if</code> or <code>switch</code> can include an
-initialization statement.  The <code>switch</code> on line 18 uses one to create variables
-<code>nr</code> and <code>er</code> to hold the return values from the call to <code>f.Read</code>.  (The <code>if</code> on line 25
+initialization statement.  The <code>switch</code> statement in <code>cat</code> uses one to create variables
+<code>nr</code> and <code>er</code> to hold the return values from the call to <code>f.Read</code>.  (The <code>if</code> a few lines later
 has the same idea.)  The <code>switch</code> statement is general: it evaluates the cases
 from  top to bottom looking for the first case that matches the value; the
 case expressions don't need to be constants or even integers, as long as
@@ -778,7 +779,7 @@ in a <code>for</code> statement, a missing value means <code>true</code>.  In fa
 is a form of <code>if-else</code> chain. While we're here, it should be mentioned that in
 <code>switch</code> statements each <code>case</code> has an implicit <code>break</code>.
 <p>
-Line 25 calls <code>Write</code> by slicing the incoming buffer, which is itself a slice.
+The argument to <code>file.Stdout.Write</code> is created by slicing the array <code>buf</code>.
 Slices provide the standard Go way to handle I/O buffers.
 <p>
 Now let's make a variant of <code>cat</code> that optionally does <code>rot13</code> on its input.
@@ -789,11 +790,11 @@ The <code>cat</code> subroutine uses only two methods of <code>f</code>: <code>R
 so let's start by defining an interface that has exactly those two methods.
 Here is code from <code>progs/cat_rot13.go</code>:
 <p>
-<pre> <!-- progs/cat_rot13.go /type.reader/ /^}/ -->
-26    type reader interface {
-27        Read(b []byte) (ret int, err os.Error)
-28        String() string
-29    }
+<pre><!-- progs/cat_rot13.go /type.reader/ /^}/
+-->type reader interface {
+    Read(b []byte) (ret int, err os.Error)
+    String() string
+}
 </pre>
 <p>
 Any type that has the two methods of <code>reader</code>—regardless of whatever
@@ -806,68 +807,68 @@ existing <code>reader</code> and does <code>rot13</code> on the data. To do this
 the type and implement the methods and with no other bookkeeping,
 we have a second implementation of the <code>reader</code> interface.
 <p>
-<pre> <!-- progs/cat_rot13.go /type.rotate13/ /end.of.rotate13/ -->
-31    type rotate13 struct {
-32        source reader
-33    }
+<pre><!-- progs/cat_rot13.go /type.rotate13/ /end.of.rotate13/
+-->type rotate13 struct {
+    source reader
+}
 
-35    func newRotate13(source reader) *rotate13 {
-36        return &rotate13{source}
-37    }
+func newRotate13(source reader) *rotate13 {
+    return &rotate13{source}
+}
 
-39    func (r13 *rotate13) Read(b []byte) (ret int, err os.Error) {
-40        r, e := r13.source.Read(b)
-41        for i := 0; i < r; i++ {
-42            b[i] = rot13(b[i])
-43        }
-44        return r, e
-45    }
+func (r13 *rotate13) Read(b []byte) (ret int, err os.Error) {
+    r, e := r13.source.Read(b)
+    for i := 0; i < r; i++ {
+        b[i] = rot13(b[i])
+    }
+    return r, e
+}
 
-47    func (r13 *rotate13) String() string {
-48        return r13.source.String()
-49    }
-50    // end of rotate13 implementation
+func (r13 *rotate13) String() string {
+    return r13.source.String()
+}
+// end of rotate13 implementation
 </pre>
 <p>
-(The <code>rot13</code> function called on line 42 is trivial and not worth reproducing here.)
+(The <code>rot13</code> function called in <code>Read</code> is trivial and not worth reproducing here.)
 <p>
 To use the new feature, we define a flag:
 <p>
-<pre> <!-- progs/cat_rot13.go /rot13Flag/ -->
-14    var rot13Flag = flag.Bool("rot13", false, "rot13 the input")
+<pre><!-- progs/cat_rot13.go /rot13Flag/
+-->var rot13Flag = flag.Bool("rot13", false, "rot13 the input")
 </pre>
 <p>
 and use it from within a mostly unchanged <code>cat</code> function:
 <p>
-<pre> <!-- progs/cat_rot13.go /func.cat/ /^}/ -->
-52    func cat(r reader) {
-53        const NBUF = 512
-54        var buf [NBUF]byte
+<pre><!-- progs/cat_rot13.go /func.cat/ /^}/
+-->func cat(r reader) {
+    const NBUF = 512
+    var buf [NBUF]byte
 
-56        if *rot13Flag {
-57            r = newRotate13(r)
-58        }
-59        for {
-60            switch nr, er := r.Read(buf[:]); {
-61            case nr < 0:
-62                fmt.Fprintf(os.Stderr, "cat: error reading from %s: %s\n", r.String(), er.String())
-63                os.Exit(1)
-64            case nr == 0: // EOF
-65                return
-66            case nr > 0:
-67                nw, ew := file.Stdout.Write(buf[0:nr])
-68                if nw != nr {
-69                    fmt.Fprintf(os.Stderr, "cat: error writing from %s: %s\n", r.String(), ew.String())
-70                    os.Exit(1)
-71                }
-72            }
-73        }
-74    }
+    if *rot13Flag {
+        r = newRotate13(r)
+    }
+    for {
+        switch nr, er := r.Read(buf[:]); {
+        case nr < 0:
+            fmt.Fprintf(os.Stderr, "cat: error reading from %s: %s\n", r.String(), er.String())
+            os.Exit(1)
+        case nr == 0: // EOF
+            return
+        case nr > 0:
+            nw, ew := file.Stdout.Write(buf[0:nr])
+            if nw != nr {
+                fmt.Fprintf(os.Stderr, "cat: error writing from %s: %s\n", r.String(), ew.String())
+                os.Exit(1)
+            }
+        }
+    }
+}
 </pre>
 <p>
 (We could also do the wrapping in <code>main</code> and leave <code>cat</code> mostly alone, except
 for changing the type of the argument; consider that an exercise.)
-Lines 56 through 58 set it all up: If the <code>rot13</code> flag is true, wrap the <code>reader</code>
+The <code>if</code> at the top of <code>cat</code> sets it all up: If the <code>rot13</code> flag is true, wrap the <code>reader</code>
 we received into a <code>rotate13</code> and proceed.  Note that the interface variables
 are values, not pointers: the argument is of type <code>reader</code>, not <code>*reader</code>,
 even though under the covers it holds a pointer to a <code>struct</code>.
@@ -875,11 +876,11 @@ even though under the covers it holds a pointer to a <code>struct</code>.
 Here it is in action:
 <p>
 <pre>
-    $ echo abcdefghijklmnopqrstuvwxyz | ./cat
-    abcdefghijklmnopqrstuvwxyz
-    $ echo abcdefghijklmnopqrstuvwxyz | ./cat --rot13
-    nopqrstuvwxyzabcdefghijklm
-    $
+$ echo abcdefghijklmnopqrstuvwxyz | ./cat
+abcdefghijklmnopqrstuvwxyz
+$ echo abcdefghijklmnopqrstuvwxyz | ./cat --rot13
+nopqrstuvwxyzabcdefghijklm
+$
 </pre>
 <p>
 Fans of dependency injection may take cheer from how easily interfaces
@@ -895,7 +896,7 @@ implement a <code>writer</code>, or any other interface built from its methods t
 fits the current situation. Consider the <i>empty interface</i>
 <p>
 <pre>
-    type Empty interface {}
+type Empty interface {}
 </pre>
 <p>
 <i>Every</i> type implements the empty interface, which makes it
@@ -910,36 +911,36 @@ same interface variable.
 <p>
 As an example, consider this simple sort algorithm taken from <code>progs/sort.go</code>:
 <p>
-<pre> <!-- progs/sort.go /func.Sort/ /^}/ -->
-13    func Sort(data Interface) {
-14        for i := 1; i < data.Len(); i++ {
-15            for j := i; j > 0 && data.Less(j, j-1); j-- {
-16                data.Swap(j, j-1)
-17            }
-18        }
-19    }
+<pre><!-- progs/sort.go /func.Sort/ /^}/
+-->func Sort(data Interface) {
+    for i := 1; i < data.Len(); i++ {
+        for j := i; j > 0 && data.Less(j, j-1); j-- {
+            data.Swap(j, j-1)
+        }
+    }
+}
 </pre>
 <p>
 The code needs only three methods, which we wrap into sort's <code>Interface</code>:
 <p>
-<pre> <!-- progs/sort.go /interface/ /^}/ -->
-07    type Interface interface {
-08        Len() int
-09        Less(i, j int) bool
-10        Swap(i, j int)
-11    }
+<pre><!-- progs/sort.go /interface/ /^}/
+-->type Interface interface {
+    Len() int
+    Less(i, j int) bool
+    Swap(i, j int)
+}
 </pre>
 <p>
 We can apply <code>Sort</code> to any type that implements <code>Len</code>, <code>Less</code>, and <code>Swap</code>.
 The <code>sort</code> package includes the necessary methods to allow sorting of
 arrays of integers, strings, etc.; here's the code for arrays of <code>int</code>
 <p>
-<pre> <!-- progs/sort.go /type.*IntSlice/ /Swap/ -->
-33    type IntSlice []int
+<pre><!-- progs/sort.go /type.*IntSlice/ /Swap/
+-->type IntSlice []int
 
-35    func (p IntSlice) Len() int            { return len(p) }
-36    func (p IntSlice) Less(i, j int) bool  { return p[i] < p[j] }
-37    func (p IntSlice) Swap(i, j int)       { p[i], p[j] = p[j], p[i] }
+func (p IntSlice) Len() int            { return len(p) }
+func (p IntSlice) Less(i, j int) bool  { return p[i] < p[j] }
+func (p IntSlice) Swap(i, j int)       { p[i], p[j] = p[j], p[i] }
 </pre>
 <p>
 Here we see methods defined for non-<code>struct</code> types.  You can define methods
@@ -949,34 +950,34 @@ And now a routine to test it out, from <code>progs/sortmain.go</code>.  This
 uses a function in the <code>sort</code> package, omitted here for brevity,
 to test that the result is sorted.
 <p>
-<pre> <!-- progs/sortmain.go /func.ints/ /^}/ -->
-12    func ints() {
-13        data := []int{74, 59, 238, -784, 9845, 959, 905, 0, 0, 42, 7586, -5467984, 7586}
-14        a := sort.IntSlice(data)
-15        sort.Sort(a)
-16        if !sort.IsSorted(a) {
-17            panic("fail")
-18        }
-19    }
+<pre><!-- progs/sortmain.go /func.ints/ /^}/
+-->func ints() {
+    data := []int{74, 59, 238, -784, 9845, 959, 905, 0, 0, 42, 7586, -5467984, 7586}
+    a := sort.IntSlice(data)
+    sort.Sort(a)
+    if !sort.IsSorted(a) {
+        panic("fail")
+    }
+}
 </pre>
 <p>
 If we have a new type we want to be able to sort, all we need to do is
 to implement the three methods for that type, like this:
 <p>
-<pre> <!-- progs/sortmain.go /type.day/ /Swap/ -->
-30    type day struct {
-31        num        int
-32        shortName  string
-33        longName   string
-34    }
+<pre><!-- progs/sortmain.go /type.day/ /Swap/
+-->type day struct {
+    num        int
+    shortName  string
+    longName   string
+}
 
-36    type dayArray struct {
-37        data []*day
-38    }
+type dayArray struct {
+    data []*day
+}
 
-40    func (p *dayArray) Len() int            { return len(p.data) }
-41    func (p *dayArray) Less(i, j int) bool  { return p.data[i].num < p.data[j].num }
-42    func (p *dayArray) Swap(i, j int)       { p.data[i], p.data[j] = p.data[j], p.data[i] }
+func (p *dayArray) Len() int            { return len(p.data) }
+func (p *dayArray) Less(i, j int) bool  { return p.data[i].num < p.data[j].num }
+func (p *dayArray) Swap(i, j int)       { p.data[i], p.data[j] = p.data[j], p.data[i] }
 </pre>
 <p>
 <p>
@@ -990,7 +991,7 @@ implements <code>Printf</code>, <code>Fprintf</code>, and so on.
 Within the <code>fmt</code> package, <code>Printf</code> is declared with this signature:
 <p>
 <pre>
-    Printf(format string, v ...interface{}) (n int, errno os.Error)
+Printf(format string, v ...interface{}) (n int, errno os.Error)
 </pre>
 <p>
 The token <code>...</code> introduces a variable-length argument list that in C would
@@ -1011,34 +1012,34 @@ argument.  It's easier in many cases in Go.  Instead of <code>%llud</code> you
 can just say <code>%d</code>; <code>Printf</code> knows the size and signedness of the
 integer and can do the right thing for you.  The snippet
 <p>
-<pre> <!-- progs/print.go NR==10 NR==11 -->
-10        var u64 uint64 = 1<<64-1
-11        fmt.Printf("%d %d\n", u64, int64(u64))
+<pre><!-- progs/print.go 10 11
+-->    var u64 uint64 = 1<<64-1
+    fmt.Printf("%d %d\n", u64, int64(u64))
 </pre>
 <p>
 prints
 <p>
 <pre>
-    18446744073709551615 -1
+18446744073709551615 -1
 </pre>
 <p>
 In fact, if you're lazy the format <code>%v</code> will print, in a simple
 appropriate style, any value, even an array or structure.  The output of
 <p>
-<pre> <!-- progs/print.go NR==14 NR==20 -->
-14        type T struct {
-15            a int
-16            b string
-17        }
-18        t := T{77, "Sunset Strip"}
-19        a := []int{1, 2, 3, 4}
-20        fmt.Printf("%v %v %v\n", u64, t, a)
+<pre><!-- progs/print.go 14 20
+-->    type T struct {
+        a int
+        b string
+    }
+    t := T{77, "Sunset Strip"}
+    a := []int{1, 2, 3, 4}
+    fmt.Printf("%v %v %v\n", u64, t, a)
 </pre>
 <p>
 is
 <p>
 <pre>
-    18446744073709551615 {77 Sunset Strip} [1 2 3 4]
+18446744073709551615 {77 Sunset Strip} [1 2 3 4]
 </pre>
 <p>
 You can drop the formatting altogether if you use <code>Print</code> or <code>Println</code>
@@ -1048,9 +1049,9 @@ of <code>%v</code> while <code>Println</code> inserts spaces between arguments
 and adds a newline.  The output of each of these two lines is identical
 to that of the <code>Printf</code> call above.
 <p>
-<pre> <!-- progs/print.go NR==21 NR==22 -->
-21        fmt.Print(u64, " ", t, " ", a, "\n")
-22        fmt.Println(u64, t, a)
+<pre><!-- progs/print.go 21 22
+-->    fmt.Print(u64, " ", t, " ", a, "\n")
+    fmt.Println(u64, t, a)
 </pre>
 <p>
 If you have your own type you'd like <code>Printf</code> or <code>Print</code> to format,
@@ -1059,27 +1060,27 @@ routines will examine the value to inquire whether it implements
 the method and if so, use it rather than some other formatting.
 Here's a simple example.
 <p>
-<pre> <!-- progs/print_string.go NR==9 END -->
-09    type testType struct {
-10        a int
-11        b string
-12    }
+<pre><!-- progs/print_string.go 9 $
+-->type testType struct {
+    a int
+    b string
+}
 
-14    func (t *testType) String() string {
-15        return fmt.Sprint(t.a) + " " + t.b
-16    }
+func (t *testType) String() string {
+    return fmt.Sprint(t.a) + " " + t.b
+}
 
-18    func main() {
-19        t := &testType{77, "Sunset Strip"}
-20        fmt.Println(t)
-21    }
+func main() {
+    t := &testType{77, "Sunset Strip"}
+    fmt.Println(t)
+}
 </pre>
 <p>
 Since <code>*testType</code> has a <code>String</code> method, the
 default formatter for that type will use it and produce the output
 <p>
 <pre>
-    77 Sunset Strip
+77 Sunset Strip
 </pre>
 <p>
 Observe that the <code>String</code> method calls <code>Sprint</code> (the obvious Go
@@ -1101,18 +1102,18 @@ Schematically, given a value <code>v</code>, it does this:
 <p>
 <p>
 <pre>
-    type Stringer interface {
-        String() string
-    }
+type Stringer interface {
+    String() string
+}
 </pre>
 <p>
 <pre>
-    s, ok := v.(Stringer)  // Test whether v implements "String()"
-    if ok {
-        result = s.String()
-    } else {
-        result = defaultOutput(v)
-    }
+s, ok := v.(Stringer)  // Test whether v implements "String()"
+if ok {
+    result = s.String()
+} else {
+    result = defaultOutput(v)
+}
 </pre>
 <p>
 The code uses a ``type assertion'' (<code>v.(Stringer)</code>) to test if the value stored in
@@ -1133,9 +1134,9 @@ not a file.  Instead, it is a variable of type <code>io.Writer</code>, which is
 interface type defined in the <code>io</code> library:
 <p>
 <pre>
-    type Writer interface {
-        Write(p []byte) (n int, err os.Error)
-    }
+type Writer interface {
+    Write(p []byte) (n int, err os.Error)
+}
 </pre>
 <p>
 (This interface is another conventional name, this time for <code>Write</code>; there are also
@@ -1178,13 +1179,13 @@ coordinates the communication; as with maps and slices, use
 <p>
 Here is the first function in <code>progs/sieve.go</code>:
 <p>
-<pre> <!-- progs/sieve.go /Send/ /^}/ -->
-09    // Send the sequence 2, 3, 4, ... to channel 'ch'.
-10    func generate(ch chan int) {
-11        for i := 2; ; i++ {
-12            ch <- i  // Send 'i' to channel 'ch'.
-13        }
-14    }
+<pre><!-- progs/sieve.go /Send/ /^}/
+-->// Send the sequence 2, 3, 4, ... to channel 'ch'.
+func generate(ch chan int) {
+    for i := 2; ; i++ {
+        ch <- i  // Send 'i' to channel 'ch'.
+    }
+}
 </pre>
 <p>
 The <code>generate</code> function sends the sequence 2, 3, 4, 5, ... to its
@@ -1197,17 +1198,17 @@ channel, and a prime number.  It copies values from the input to the
 output, discarding anything divisible by the prime.  The unary communications
 operator <code><-</code> (receive) retrieves the next value on the channel.
 <p>
-<pre> <!-- progs/sieve.go /Copy.the/ /^}/ -->
-16    // Copy the values from channel 'in' to channel 'out',
-17    // removing those divisible by 'prime'.
-18    func filter(in, out chan int, prime int) {
-19        for {
-20            i := <-in  // Receive value of new variable 'i' from 'in'.
-21            if i % prime != 0 {
-22                out <- i  // Send 'i' to channel 'out'.
-23            }
-24        }
-25    }
+<pre><!-- progs/sieve.go /Copy.the/ /^}/
+-->// Copy the values from channel 'in' to channel 'out',
+// removing those divisible by 'prime'.
+func filter(in, out chan int, prime int) {
+    for {
+        i := <-in  // Receive value of new variable 'i' from 'in'.
+        if i % prime != 0 {
+            out <- i  // Send 'i' to channel 'out'.
+        }
+    }
+}
 </pre>
 <p>
 The generator and filters execute concurrently.  Go has
@@ -1219,37 +1220,37 @@ this starts the function running in parallel with the current
 computation but in the same address space:
 <p>
 <pre>
-    go sum(hugeArray) // calculate sum in the background
+go sum(hugeArray) // calculate sum in the background
 </pre>
 <p>
 If you want to know when the calculation is done, pass a channel
 on which it can report back:
 <p>
 <pre>
-    ch := make(chan int)
-    go sum(hugeArray, ch)
-    // ... do something else for a while
-    result := <-ch  // wait for, and retrieve, result
+ch := make(chan int)
+go sum(hugeArray, ch)
+// ... do something else for a while
+result := <-ch  // wait for, and retrieve, result
 </pre>
 <p>
 Back to our prime sieve.  Here's how the sieve pipeline is stitched
 together:
 <p>
-<pre> <!-- progs/sieve.go /func.main/ /^}/ -->
-28    func main() {
-29        ch := make(chan int)  // Create a new channel.
-30        go generate(ch)  // Start generate() as a goroutine.
-31        for i := 0; i < 100; i++ { // Print the first hundred primes.
-32            prime := <-ch
-33            fmt.Println(prime)
-34            ch1 := make(chan int)
-35            go filter(ch, ch1, prime)
-36            ch = ch1
-37        }
-38    }
-</pre>
-<p>
-Line 29 creates the initial channel to pass to <code>generate</code>, which it
+<pre><!-- progs/sieve.go /func.main/ /^}/
+-->func main() {
+    ch := make(chan int)  // Create a new channel.
+    go generate(ch)  // Start generate() as a goroutine.
+    for i := 0; i < 100; i++ { // Print the first hundred primes.
+        prime := <-ch
+        fmt.Println(prime)
+        ch1 := make(chan int)
+        go filter(ch, ch1, prime)
+        ch = ch1
+    }
+}
+</pre>
+<p>
+The first line of <code>main</code> creates the initial channel to pass to <code>generate</code>, which it
 then starts up.  As each prime pops out of the channel, a new <code>filter</code>
 is added to the pipeline and <i>its</i> output becomes the new value
 of <code>ch</code>.
@@ -1258,16 +1259,16 @@ The sieve program can be tweaked to use a pattern common
 in this style of programming.  Here is a variant version
 of <code>generate</code>, from <code>progs/sieve1.go</code>:
 <p>
-<pre> <!-- progs/sieve1.go /func.generate/ /^}/ -->
-10    func generate() chan int {
-11        ch := make(chan int)
-12        go func(){
-13            for i := 2; ; i++ {
-14                ch <- i
-15            }
-16        }()
-17        return ch
-18    }
+<pre><!-- progs/sieve1.go /func.generate/ /^}/
+-->func generate() chan int {
+    ch := make(chan int)
+    go func(){
+        for i := 2; ; i++ {
+            ch <- i
+        }
+    }()
+    return ch
+}
 </pre>
 <p>
 This version does all the setup internally. It creates the output
@@ -1275,54 +1276,54 @@ channel, launches a goroutine running a function literal, and
 returns the channel to the caller.  It is a factory for concurrent
 execution, starting the goroutine and returning its connection.
 <p>
-The function literal notation (lines 12-16) allows us to construct an
+The function literal notation used in the <code>go</code> statement allows us to construct an
 anonymous function and invoke it on the spot. Notice that the local
 variable <code>ch</code> is available to the function literal and lives on even
 after <code>generate</code> returns.
 <p>
 The same change can be made to <code>filter</code>:
 <p>
-<pre> <!-- progs/sieve1.go /func.filter/ /^}/ -->
-21    func filter(in chan int, prime int) chan int {
-22        out := make(chan int)
-23        go func() {
-24            for {
-25                if i := <-in; i % prime != 0 {
-26                    out <- i
-27                }
-28            }
-29        }()
-30        return out
-31    }
+<pre><!-- progs/sieve1.go /func.filter/ /^}/
+-->func filter(in chan int, prime int) chan int {
+    out := make(chan int)
+    go func() {
+        for {
+            if i := <-in; i % prime != 0 {
+                out <- i
+            }
+        }
+    }()
+    return out
+}
 </pre>
 <p>
 The <code>sieve</code> function's main loop becomes simpler and clearer as a
 result, and while we're at it let's turn it into a factory too:
 <p>
-<pre> <!-- progs/sieve1.go /func.sieve/ /^}/ -->
-33    func sieve() chan int {
-34        out := make(chan int)
-35        go func() {
-36            ch := generate()
-37            for {
-38                prime := <-ch
-39                out <- prime
-40                ch = filter(ch, prime)
-41            }
-42        }()
-43        return out
-44    }
+<pre><!-- progs/sieve1.go /func.sieve/ /^}/
+-->func sieve() chan int {
+    out := make(chan int)
+    go func() {
+        ch := generate()
+        for {
+            prime := <-ch
+            out <- prime
+            ch = filter(ch, prime)
+        }
+    }()
+    return out
+}
 </pre>
 <p>
 Now <code>main</code>'s interface to the prime sieve is a channel of primes:
 <p>
-<pre> <!-- progs/sieve1.go /func.main/ /^}/ -->
-46    func main() {
-47        primes := sieve()
-48        for i := 0; i < 100; i++ { // Print the first hundred primes.
-49            fmt.Println(<-primes)
-50        }
-51    }
+<pre><!-- progs/sieve1.go /func.main/ /^}/
+-->func main() {
+    primes := sieve()
+    for i := 0; i < 100; i++ { // Print the first hundred primes.
+        fmt.Println(<-primes)
+    }
+}
 </pre>
 <p>
 <h2>Multiplexing</h2>
@@ -1334,102 +1335,102 @@ A realistic client-server program is a lot of code, so here is a very simple sub
 to illustrate the idea.  It starts by defining a <code>request</code> type, which embeds a channel
 that will be used for the reply.
 <p>
-<pre> <!-- progs/server.go /type.request/ /^}/ -->
-09    type request struct {
-10        a, b    int
-11        replyc  chan int
-12    }
+<pre><!-- progs/server.go /type.request/ /^}/
+-->type request struct {
+    a, b    int
+    replyc  chan int
+}
 </pre>
 <p>
 The server will be trivial: it will do simple binary operations on integers.  Here's the
 code that invokes the operation and responds to the request:
 <p>
-<pre> <!-- progs/server.go /type.binOp/ /^}/ -->
-14    type binOp func(a, b int) int
+<pre><!-- progs/server.go /type.binOp/ /^}/
+-->type binOp func(a, b int) int
 
-16    func run(op binOp, req *request) {
-17        reply := op(req.a, req.b)
-18        req.replyc <- reply
-19    }
+func run(op binOp, req *request) {
+    reply := op(req.a, req.b)
+    req.replyc <- reply
+}
 </pre>
 <p>
-Line 14 defines the name <code>binOp</code> to be a function taking two integers and
+The type declaration makes <code>binOp</code> represent a function taking two integers and
 returning a third.
 <p>
 The <code>server</code> routine loops forever, receiving requests and, to avoid blocking due to
 a long-running operation, starting a goroutine to do the actual work.
 <p>
-<pre> <!-- progs/server.go /func.server/ /^}/ -->
-21    func server(op binOp, service chan *request) {
-22        for {
-23            req := <-service
-24            go run(op, req)  // don't wait for it
-25        }
-26    }
+<pre><!-- progs/server.go /func.server/ /^}/
+-->func server(op binOp, service chan *request) {
+    for {
+        req := <-service
+        go run(op, req)  // don't wait for it
+    }
+}
 </pre>
 <p>
 We construct a server in a familiar way, starting it and returning a channel
 connected to it:
 <p>
-<pre> <!-- progs/server.go /func.startServer/ /^}/ -->
-28    func startServer(op binOp) chan *request {
-29        req := make(chan *request)
-30        go server(op, req)
-31        return req
-32    }
+<pre><!-- progs/server.go /func.startServer/ /^}/
+-->func startServer(op binOp) chan *request {
+    req := make(chan *request)
+    go server(op, req)
+    return req
+}
 </pre>
 <p>
 Here's a simple test.  It starts a server with an addition operator and sends out
 <code>N</code> requests without waiting for the replies.  Only after all the requests are sent
 does it check the results.
 <p>
-<pre> <!-- progs/server.go /func.main/ /^}/ -->
-34    func main() {
-35        adder := startServer(func(a, b int) int { return a + b })
-36        const N = 100
-37        var reqs [N]request
-38        for i := 0; i < N; i++ {
-39            req := &reqs[i]
-40            req.a = i
-41            req.b = i + N
-42            req.replyc = make(chan int)
-43            adder <- req
-44        }
-45        for i := N-1; i >= 0; i-- {   // doesn't matter what order
-46            if <-reqs[i].replyc != N + 2*i {
-47                fmt.Println("fail at", i)
-48            }
-49        }
-50        fmt.Println("done")
-51    }
+<pre><!-- progs/server.go /func.main/ /^}/
+-->func main() {
+    adder := startServer(func(a, b int) int { return a + b })
+    const N = 100
+    var reqs [N]request
+    for i := 0; i < N; i++ {
+        req := &reqs[i]
+        req.a = i
+        req.b = i + N
+        req.replyc = make(chan int)
+        adder <- req
+    }
+    for i := N-1; i >= 0; i-- {   // doesn't matter what order
+        if <-reqs[i].replyc != N + 2*i {
+            fmt.Println("fail at", i)
+        }
+    }
+    fmt.Println("done")
+}
 </pre>
 <p>
 One annoyance with this program is that it doesn't shut down the server cleanly; when <code>main</code> returns
 there are a number of lingering goroutines blocked on communication.  To solve this,
 we can provide a second, <code>quit</code> channel to the server:
 <p>
-<pre> <!-- progs/server1.go /func.startServer/ /^}/ -->
-32    func startServer(op binOp) (service chan *request, quit chan bool) {
-33        service = make(chan *request)
-34        quit = make(chan bool)
-35        go server(op, service, quit)
-36        return service, quit
-37    }
+<pre><!-- progs/server1.go /func.startServer/ /^}/
+-->func startServer(op binOp) (service chan *request, quit chan bool) {
+    service = make(chan *request)
+    quit = make(chan bool)
+    go server(op, service, quit)
+    return service, quit
+}
 </pre>
 <p>
 It passes the quit channel to the <code>server</code> function, which uses it like this:
 <p>
-<pre> <!-- progs/server1.go /func.server/ /^}/ -->
-21    func server(op binOp, service chan *request, quit chan bool) {
-22        for {
-23            select {
-24            case req := <-service:
-25                go run(op, req)  // don't wait for it
-26            case <-quit:
-27                return
-28            }
-29        }
-30    }
+<pre><!-- progs/server1.go /func.server/ /^}/
+-->func server(op binOp, service chan *request, quit chan bool) {
+    for {
+        select {
+        case req := <-service:
+            go run(op, req)  // don't wait for it
+        case <-quit:
+            return
+        }
+    }
+}
 </pre>
 <p>
 Inside <code>server</code>, the <code>select</code> statement chooses which of the multiple communications
@@ -1442,12 +1443,12 @@ returns, terminating its execution.
 All that's left is to strobe the <code>quit</code> channel
 at the end of main:
 <p>
-<pre> <!-- progs/server1.go /adder,.quit/ -->
-40        adder, quit := startServer(func(a, b int) int { return a + b })
+<pre><!-- progs/server1.go /adder,.quit/
+-->    adder, quit := startServer(func(a, b int) int { return a + b })
 </pre>
 ...
-<pre> <!-- progs/server1.go /quit....true/ -->
-55        quit <- true
+<pre><!-- progs/server1.go /quit....true/
+-->    quit <- true
 </pre>
 <p>
 There's a lot more to Go programming and concurrent programming in general but this
diff --git a/doc/go_tutorial.txt b/doc/go_tutorial.txt
index 7e2bc7c..17ef6ee 100644
--- a/doc/go_tutorial.txt
+++ b/doc/go_tutorial.txt
@@ -28,7 +28,7 @@ Hello, World
 
 Let's start in the usual way:
 
---PROG progs/helloworld.go /package/ END
+!src progs/helloworld.go /package/ $
 
 Every Go source file declares, using a "package" statement, which package it's part of.
 It may also import other packages to use their facilities.
@@ -107,13 +107,13 @@ Echo
 
 Next up, here's a version of the Unix utility "echo(1)":
 
---PROG progs/echo.go /package/ END
+!src progs/echo.go /package/ $
 
 This program is small but it's doing a number of new things.  In the last example,
 we saw "func" introduce a function.  The keywords "var", "const", and "type"
 (not used yet) also introduce declarations, as does "import".
 Notice that we can group declarations of the same sort into
-parenthesized lists, one item per line, as on lines 7-10 and 14-17.
+parenthesized lists, one item per line, as in the "import" and "const" clauses here.
 But it's not necessary to do so; we could have said
 
 	const Space = " "
@@ -163,7 +163,7 @@ or we could go even shorter and write the idiom
 The ":=" operator is used a lot in Go to represent an initializing declaration.
 There's one in the "for" clause on the next line:
 
---PROG  progs/echo.go /for/
+!src  progs/echo.go /for/
 
 The "flag" package has parsed the arguments and left the non-flag arguments
 in a list that can be iterated over in the obvious way.
@@ -210,7 +210,7 @@ Once you've built a string <i>value</i>, you can't change it, although
 of course you can change a string <i>variable</i> simply by
 reassigning it.  This snippet from "strings.go" is legal code:
 
---PROG progs/strings.go /hello/ /ciao/
+!src progs/strings.go /hello/ /ciao/
 
 However the following statements are illegal because they would modify
 a "string" value:
@@ -269,7 +269,7 @@ will slice the whole array.
 
 Using slices one can write this function (from "sum.go"):
 
---PROG progs/sum.go /sum/ /^}/
+!src progs/sum.go /sum/ /^}/
 
 Note how the return type ("int") is defined for "sum" by stating it
 after the parameter list.
@@ -386,7 +386,7 @@ An I/O Package
 Next we'll look at a simple package for doing file I/O with an
 open/close/read/write interface.  Here's the start of "file.go":
 
---PROG progs/file.go /package/ /^}/
+!src progs/file.go /package/ /^}/
 
 The first few lines declare the name of the
 package—"file"—and then import two packages.  The "os"
@@ -416,7 +416,7 @@ will soon give it some exported, upper-case methods.
 
 First, though, here is a factory to create a "File":
 
---PROG progs/file.go /newFile/ /^}/
+!src progs/file.go /newFile/ /^}/
 
 This returns a pointer to a new "File" structure with the file descriptor and name
 filled in.  This code uses Go's notion of a ''composite literal'', analogous to
@@ -433,12 +433,12 @@ composite literal, as is done here on line 21.
 
 We can use the factory to construct some familiar, exported variables of type "*File":
 
---PROG progs/file.go /var/ /^.$/
+!src progs/file.go /var/ /^.$/
 
 The "newFile" function was not exported because it's internal. The proper,
 exported factory to use is "OpenFile" (we'll explain that name in a moment):
 
---PROG progs/file.go /func.OpenFile/ /^}/
+!src progs/file.go /func.OpenFile/ /^}/
 
 There are a number of new things in these few lines.  First, "OpenFile" returns
 multiple values, a "File" and an error (more about errors in a moment).
@@ -468,9 +468,9 @@ the implementation of our "Open" and "Create"; they're trivial
 wrappers that eliminate common errors by capturing
 the tricky standard arguments to open and, especially, to create a file:
 
---PROG progs/file.go /^const/ /^}/
+!src progs/file.go /^const/ /^}/
 
---PROG progs/file.go /func.Create/ /^}/
+!src progs/file.go /func.Create/ /^}/
 
 Back to our main story.
 Now that we can build "Files", we can write methods for them. To declare
@@ -479,7 +479,7 @@ of that type, placed
 in parentheses before the function name. Here are some methods for "*File",
 each of which declares a receiver variable "file".
 
---PROG progs/file.go /Close/ END
+!src progs/file.go /Close/ $
 
 There is no implicit "this" and the receiver variable must be used to access
 members of the structure.  Methods are not declared within
@@ -496,7 +496,7 @@ set of such error values.
 
 We can now use our new package:
 
---PROG progs/helloworld3.go /package/ END
+!src progs/helloworld3.go /package/ $
 
 The ''"./"'' in the import of ''"./file"'' tells the compiler
 to use our own package rather than
@@ -520,12 +520,12 @@ Rotting cats
 Building on the "file" package, here's a simple version of the Unix utility "cat(1)",
 "progs/cat.go":
 
---PROG progs/cat.go /package/ END
+!src progs/cat.go /package/ $
 
 By now this should be easy to follow, but the "switch" statement introduces some
 new features.  Like a "for" loop, an "if" or "switch" can include an
-initialization statement.  The "switch" on line 18 uses one to create variables
-"nr" and "er" to hold the return values from the call to "f.Read".  (The "if" on line 25
+initialization statement.  The "switch" statement in "cat" uses one to create variables
+"nr" and "er" to hold the return values from the call to "f.Read".  (The "if" a few lines later
 has the same idea.)  The "switch" statement is general: it evaluates the cases
 from  top to bottom looking for the first case that matches the value; the
 case expressions don't need to be constants or even integers, as long as
@@ -537,7 +537,7 @@ in a "for" statement, a missing value means "true".  In fact, such a "switch"
 is a form of "if-else" chain. While we're here, it should be mentioned that in
 "switch" statements each "case" has an implicit "break".
 
-Line 25 calls "Write" by slicing the incoming buffer, which is itself a slice.
+The argument to "file.Stdout.Write" is created by slicing the array "buf".
 Slices provide the standard Go way to handle I/O buffers.
 
 Now let's make a variant of "cat" that optionally does "rot13" on its input.
@@ -548,7 +548,7 @@ The "cat" subroutine uses only two methods of "f": "Read" and "String",
 so let's start by defining an interface that has exactly those two methods.
 Here is code from "progs/cat_rot13.go":
 
---PROG progs/cat_rot13.go /type.reader/ /^}/
+!src progs/cat_rot13.go /type.reader/ /^}/
 
 Any type that has the two methods of "reader"—regardless of whatever
 other methods the type may also have—is said to <i>implement</i> the
@@ -560,34 +560,32 @@ existing "reader" and does "rot13" on the data. To do this, we just define
 the type and implement the methods and with no other bookkeeping,
 we have a second implementation of the "reader" interface.
 
---PROG progs/cat_rot13.go /type.rotate13/ /end.of.rotate13/
+!src progs/cat_rot13.go /type.rotate13/ /end.of.rotate13/
 
-(The "rot13" function called on line 42 is trivial and not worth reproducing here.)
+(The "rot13" function called in "Read" is trivial and not worth reproducing here.)
 
 To use the new feature, we define a flag:
 
---PROG progs/cat_rot13.go /rot13Flag/
+!src progs/cat_rot13.go /rot13Flag/
 
 and use it from within a mostly unchanged "cat" function:
 
---PROG progs/cat_rot13.go /func.cat/ /^}/
+!src progs/cat_rot13.go /func.cat/ /^}/
 
 (We could also do the wrapping in "main" and leave "cat" mostly alone, except
 for changing the type of the argument; consider that an exercise.)
-Lines 56 through 58 set it all up: If the "rot13" flag is true, wrap the "reader"
+The "if" at the top of "cat" sets it all up: If the "rot13" flag is true, wrap the "reader"
 we received into a "rotate13" and proceed.  Note that the interface variables
 are values, not pointers: the argument is of type "reader", not "*reader",
 even though under the covers it holds a pointer to a "struct".
 
 Here it is in action:
 
-<pre>
 	$ echo abcdefghijklmnopqrstuvwxyz | ./cat
 	abcdefghijklmnopqrstuvwxyz
 	$ echo abcdefghijklmnopqrstuvwxyz | ./cat --rot13
 	nopqrstuvwxyzabcdefghijklm
 	$
-</pre>
 
 Fans of dependency injection may take cheer from how easily interfaces
 allow us to substitute the implementation of a file descriptor.
@@ -601,9 +599,7 @@ as we saw with "rot13".  The type "file.File" implements "reader"; it could also
 implement a "writer", or any other interface built from its methods that
 fits the current situation. Consider the <i>empty interface</i>
 
-<pre>
 	type Empty interface {}
-</pre>
 
 <i>Every</i> type implements the empty interface, which makes it
 useful for things like containers.
@@ -618,17 +614,17 @@ same interface variable.
 
 As an example, consider this simple sort algorithm taken from "progs/sort.go":
 
---PROG progs/sort.go /func.Sort/ /^}/
+!src progs/sort.go /func.Sort/ /^}/
 
 The code needs only three methods, which we wrap into sort's "Interface":
 
---PROG progs/sort.go /interface/ /^}/
+!src progs/sort.go /interface/ /^}/
 
 We can apply "Sort" to any type that implements "Len", "Less", and "Swap".
 The "sort" package includes the necessary methods to allow sorting of
 arrays of integers, strings, etc.; here's the code for arrays of "int"
 
---PROG progs/sort.go /type.*IntSlice/ /Swap/
+!src progs/sort.go /type.*IntSlice/ /Swap/
 
 Here we see methods defined for non-"struct" types.  You can define methods
 for any type you define and name in your package.
@@ -637,12 +633,12 @@ And now a routine to test it out, from "progs/sortmain.go".  This
 uses a function in the "sort" package, omitted here for brevity,
 to test that the result is sorted.
 
---PROG progs/sortmain.go /func.ints/ /^}/
+!src progs/sortmain.go /func.ints/ /^}/
 
 If we have a new type we want to be able to sort, all we need to do is
 to implement the three methods for that type, like this:
 
---PROG progs/sortmain.go /type.day/ /Swap/
+!src progs/sortmain.go /type.day/ /Swap/
 
 
 Printing
@@ -675,7 +671,7 @@ argument.  It's easier in many cases in Go.  Instead of "%llud" you
 can just say "%d"; "Printf" knows the size and signedness of the
 integer and can do the right thing for you.  The snippet
 
---PROG progs/print.go 'NR==10' 'NR==11'
+!src progs/print.go 10 11
 
 prints
 
@@ -684,7 +680,7 @@ prints
 In fact, if you're lazy the format "%v" will print, in a simple
 appropriate style, any value, even an array or structure.  The output of
 
---PROG progs/print.go 'NR==14' 'NR==20'
+!src progs/print.go 14 20
 
 is
 
@@ -697,7 +693,7 @@ of "%v" while "Println" inserts spaces between arguments
 and adds a newline.  The output of each of these two lines is identical
 to that of the "Printf" call above.
 
---PROG progs/print.go 'NR==21' 'NR==22'
+!src progs/print.go 21 22
 
 If you have your own type you'd like "Printf" or "Print" to format,
 just give it a "String" method that returns a string.  The print
@@ -705,7 +701,7 @@ routines will examine the value to inquire whether it implements
 the method and if so, use it rather than some other formatting.
 Here's a simple example.
 
---PROG progs/print_string.go 'NR==9' END
+!src progs/print_string.go 9 $
 
 Since "*testType" has a "String" method, the
 default formatter for that type will use it and produce the output
@@ -803,7 +799,7 @@ coordinates the communication; as with maps and slices, use
 
 Here is the first function in "progs/sieve.go":
 
---PROG progs/sieve.go /Send/ /^}/
+!src progs/sieve.go /Send/ /^}/
 
 The "generate" function sends the sequence 2, 3, 4, 5, ... to its
 argument channel, "ch", using the binary communications operator "<-".
@@ -815,7 +811,7 @@ channel, and a prime number.  It copies values from the input to the
 output, discarding anything divisible by the prime.  The unary communications
 operator "<-" (receive) retrieves the next value on the channel.
 
---PROG progs/sieve.go /Copy.the/ /^}/
+!src progs/sieve.go /Copy.the/ /^}/
 
 The generator and filters execute concurrently.  Go has
 its own model of process/threads/light-weight processes/coroutines,
@@ -838,9 +834,9 @@ on which it can report back:
 Back to our prime sieve.  Here's how the sieve pipeline is stitched
 together:
 
---PROG progs/sieve.go /func.main/ /^}/
+!src progs/sieve.go /func.main/ /^}/
 
-Line 29 creates the initial channel to pass to "generate", which it
+The first line of "main" creates the initial channel to pass to "generate", which it
 then starts up.  As each prime pops out of the channel, a new "filter"
 is added to the pipeline and <i>its</i> output becomes the new value
 of "ch".
@@ -849,30 +845,30 @@ The sieve program can be tweaked to use a pattern common
 in this style of programming.  Here is a variant version
 of "generate", from "progs/sieve1.go":
 
---PROG progs/sieve1.go /func.generate/ /^}/
+!src progs/sieve1.go /func.generate/ /^}/
 
 This version does all the setup internally. It creates the output
 channel, launches a goroutine running a function literal, and
 returns the channel to the caller.  It is a factory for concurrent
 execution, starting the goroutine and returning its connection.
 
-The function literal notation (lines 12-16) allows us to construct an
+The function literal notation used in the "go" statement allows us to construct an
 anonymous function and invoke it on the spot. Notice that the local
 variable "ch" is available to the function literal and lives on even
 after "generate" returns.
 
 The same change can be made to "filter":
 
---PROG progs/sieve1.go /func.filter/ /^}/
+!src progs/sieve1.go /func.filter/ /^}/
 
 The "sieve" function's main loop becomes simpler and clearer as a
 result, and while we're at it let's turn it into a factory too:
 
---PROG progs/sieve1.go /func.sieve/ /^}/
+!src progs/sieve1.go /func.sieve/ /^}/
 
 Now "main"'s interface to the prime sieve is a channel of primes:
 
---PROG progs/sieve1.go /func.main/ /^}/
+!src progs/sieve1.go /func.main/ /^}/
 
 Multiplexing
 ----
@@ -884,41 +880,41 @@ A realistic client-server program is a lot of code, so here is a very simple sub
 to illustrate the idea.  It starts by defining a "request" type, which embeds a channel
 that will be used for the reply.
 
---PROG progs/server.go /type.request/ /^}/
+!src progs/server.go /type.request/ /^}/
 
 The server will be trivial: it will do simple binary operations on integers.  Here's the
 code that invokes the operation and responds to the request:
 
---PROG progs/server.go /type.binOp/ /^}/
+!src progs/server.go /type.binOp/ /^}/
 
-Line 14 defines the name "binOp" to be a function taking two integers and
+The type declaration makes "binOp" represent a function taking two integers and
 returning a third.
 
 The "server" routine loops forever, receiving requests and, to avoid blocking due to
 a long-running operation, starting a goroutine to do the actual work.
 
---PROG progs/server.go /func.server/ /^}/
+!src progs/server.go /func.server/ /^}/
 
 We construct a server in a familiar way, starting it and returning a channel
 connected to it:
 
---PROG progs/server.go /func.startServer/ /^}/
+!src progs/server.go /func.startServer/ /^}/
 
 Here's a simple test.  It starts a server with an addition operator and sends out
 "N" requests without waiting for the replies.  Only after all the requests are sent
 does it check the results.
 
---PROG progs/server.go /func.main/ /^}/
+!src progs/server.go /func.main/ /^}/
 
 One annoyance with this program is that it doesn't shut down the server cleanly; when "main" returns
 there are a number of lingering goroutines blocked on communication.  To solve this,
 we can provide a second, "quit" channel to the server:
 
---PROG progs/server1.go /func.startServer/ /^}/
+!src progs/server1.go /func.startServer/ /^}/
 
 It passes the quit channel to the "server" function, which uses it like this:
 
---PROG progs/server1.go /func.server/ /^}/
+!src progs/server1.go /func.server/ /^}/
 
 Inside "server", the "select" statement chooses which of the multiple communications
 listed by its cases can proceed.  If all are blocked, it waits until one can proceed; if
@@ -930,9 +926,9 @@ returns, terminating its execution.
 All that's left is to strobe the "quit" channel
 at the end of main:
 
---PROG progs/server1.go /adder,.quit/
+!src progs/server1.go /adder,.quit/
 ...
---PROG progs/server1.go /quit....true/
+!src progs/server1.go /quit....true/
 
 There's a lot more to Go programming and concurrent programming in general but this
 quick tour should give you some of the basics.
diff --git a/doc/htmlgen.go b/doc/htmlgen.go
index 3a8feb8..5318a07 100644
--- a/doc/htmlgen.go
+++ b/doc/htmlgen.go
@@ -2,46 +2,80 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Process plain text into HTML.
+// If --html is set, process plain text into HTML.
 //	- h2's are made from lines followed by a line "----\n"
-//	- tab-indented blocks become <pre> blocks
+//	- tab-indented blocks become <pre> blocks with the first tab deleted
 //	- blank lines become <p> marks (except inside <pre> tags)
 //	- "quoted strings" become <code>quoted strings</code>
 
+// Lines beginning !src define pieces of program source to be
+// extracted from other files and injected as <pre> blocks.
+// The syntax is simple: 1, 2, or 3 space-separated arguments:
+//
+// Whole file:
+//	!src foo.go
+// One line (here the signature of main):
+//	!src foo.go /^func.main/
+// Block of text, determined by start and end (here the body of main):
+// !src foo.go /^func.main/ /^}/
+//
+// Patterns can be /regular.expression/, a decimal number, or $
+// to signify the end of the file.
+// TODO: the regular expression cannot contain spaces; does this matter?
+
 package main
 
 import (
 	"bufio"
 	"bytes"
+	"flag"
+	"fmt"
+	"io/ioutil"
 	"log"
 	"os"
+	"regexp"
+	"strconv"
+	"strings"
+	"template"
 )
 
 var (
-	lines = make([][]byte, 0, 2000) // probably big enough; grows if not
+	html = flag.Bool("html", true, "process text into HTML")
+)
+
+var (
+	// lines holds the input and is reworked in place during processing.
+	lines = make([][]byte, 0, 20000)
 
 	empty   = []byte("")
 	newline = []byte("\n")
 	tab     = []byte("\t")
 	quote   = []byte(`"`)
-	indent  = []byte{' ', ' ', ' ', ' '}
+	indent  = []byte("    ")
 
 	sectionMarker = []byte("----\n")
 	preStart      = []byte("<pre>")
 	preEnd        = []byte("</pre>\n")
 	pp            = []byte("<p>\n")
+
+	srcPrefix = []byte("!src")
 )
 
 func main() {
+	flag.Parse()
 	read()
-	headings()
-	coalesce(preStart, foldPre)
-	coalesce(tab, foldTabs)
-	paragraphs()
-	quotes()
+	programs()
+	if *html {
+		headings()
+		coalesce(preStart, foldPre)
+		coalesce(tab, foldTabs)
+		paragraphs()
+		quotes()
+	}
 	write()
 }
 
+// read turns standard input into a slice of lines.
 func read() {
 	b := bufio.NewReader(os.Stdin)
 	for {
@@ -56,6 +90,7 @@ func read() {
 	}
 }
 
+// write puts the result on standard output.
 func write() {
 	b := bufio.NewWriter(os.Stdout)
 	for _, line := range lines {
@@ -64,8 +99,104 @@ func write() {
 	b.Flush()
 }
 
-// each time prefix is found on a line, call fold and replace
-// line with return value from fold.
+// programs injects source code from !src invocations.
+func programs() {
+	nlines := make([][]byte, 0, len(lines)*3/2)
+	for _, line := range lines {
+		if bytes.HasPrefix(line, srcPrefix) {
+			line = trim(line)[len(srcPrefix):]
+			prog := srcCommand(string(line))
+			if *html {
+				nlines = append(nlines, []byte(fmt.Sprintf("<pre><!--%s\n-->", line)))
+			}
+			for _, l := range prog {
+				nlines = append(nlines, htmlEscape(l))
+			}
+			if *html {
+				nlines = append(nlines, preEnd)
+			}
+		} else {
+			nlines = append(nlines, line)
+		}
+	}
+	lines = nlines
+}
+
+// srcCommand processes one !src invocation.
+func srcCommand(command string) [][]byte {
+	// TODO: quoted args so we can have 'a b'?
+	args := strings.Fields(command)
+	if len(args) == 0 || len(args) > 3 {
+		log.Fatal("bad syntax for src command: %s", command)
+	}
+	file := args[0]
+	lines := bytes.SplitAfter(readFile(file), newline)
+	// File plus zero args: whole file:
+	//	!src file.go
+	if len(args) == 1 {
+		return lines
+	}
+	start := match(file, 0, lines, string(args[1]))
+	// File plus one arg: one line:
+	//	!src file.go /foo/
+	if len(args) == 2 {
+		return [][]byte{lines[start]}
+	}
+	// File plus two args: range:
+	//	!src file.go /foo/ /^}/
+	end := match(file, start, lines, string(args[2]))
+	return lines[start : end+1] // +1 to include matched line.
+}
+
+// htmlEscape makes sure input is HTML clean, if necessary.
+func htmlEscape(input []byte) []byte {
+	if !*html || bytes.IndexAny(input, `&"<>`) < 0 {
+		return input
+	}
+	var b bytes.Buffer
+	template.HTMLEscape(&b, input)
+	return b.Bytes()
+}
+
+// readFile reads and returns a file as part of !src processing.
+func readFile(name string) []byte {
+	file, err := ioutil.ReadFile(name)
+	if err != nil {
+		log.Fatal(err)
+	}
+	return file
+}
+
+// match identifies the input line that matches the pattern in a !src invocation.
+// If start>0, match lines starting there rather than at the beginning.
+func match(file string, start int, lines [][]byte, pattern string) int {
+	// $ matches the end of the file.
+	if pattern == "$" {
+		return len(lines) - 1
+	}
+	// Number matches the line.
+	if i, err := strconv.Atoi(pattern); err == nil {
+		return i - 1 // Lines are 1-indexed.
+	}
+	// /regexp/ matches the line that matches the regexp.
+	if len(pattern) > 2 && pattern[0] == '/' && pattern[len(pattern)-1] == '/' {
+		re, err := regexp.Compile(pattern[1 : len(pattern)-1])
+		if err != nil {
+			log.Fatal(err)
+		}
+		for i := start; i < len(lines); i++ {
+			if re.Match(lines[i]) {
+				return i
+			}
+		}
+		log.Fatalf("%s: no match for %s", file, pattern)
+	}
+	log.Fatalf("unrecognized pattern: %s", pattern)
+	return 0
+}
+
+// coalesce combines lines. Each time prefix is found on a line,
+// it calls fold and replaces the line with return value from fold.
 func coalesce(prefix []byte, fold func(i int) (n int, line []byte)) {
 	j := 0 // output line number goes up by one each loop
 	for i := 0; i < len(lines); {
@@ -82,7 +213,7 @@ func coalesce(prefix []byte, fold func(i int) (n int, line []byte)) {
 	lines = lines[0:j]
 }
 
-// return the <pre> block as a single slice
+// foldPre returns the <pre> block as a single slice.
 func foldPre(i int) (n int, line []byte) {
 	buf := new(bytes.Buffer)
 	for i < len(lines) {
@@ -96,7 +227,7 @@ func foldPre(i int) (n int, line []byte) {
 	return n, buf.Bytes()
 }
 
-// return the tab-indented block as a single <pre>-bounded slice
+// foldTabs returns the tab-indented block as a single <pre>-bounded slice.
 func foldTabs(i int) (n int, line []byte) {
 	buf := new(bytes.Buffer)
 	buf.WriteString("<pre>\n")
@@ -104,7 +235,7 @@ func foldTabs(i int) (n int, line []byte) {
 		if !bytes.HasPrefix(lines[i], tab) {
 			break
 		}
-		buf.Write(lines[i])
+		buf.Write(lines[i][1:]) // delete leading tab.
 		n++
 		i++
 	}
@@ -112,6 +243,7 @@ func foldTabs(i int) (n int, line []byte) {
 	return n, buf.Bytes()
 }
 
+// headings turns sections into HTML sections.
 func headings() {
 	b := bufio.NewWriter(os.Stdout)
 	for i, l := range lines {
@@ -123,6 +255,7 @@ func headings() {
 	b.Flush()
 }
 
+// paragraphs turns blank lines into paragraph marks.
 func paragraphs() {
 	for i, l := range lines {
 		if bytes.Equal(l, newline) {
@@ -131,12 +264,14 @@ func paragraphs() {
 	}
 }
 
+// quotes turns "x" in the file into <code>x</code>.
 func quotes() {
 	for i, l := range lines {
 		lines[i] = codeQuotes(l)
 	}
 }
 
+// quotes turns "x" in the line into <code>x</code>.
 func codeQuotes(l []byte) []byte {
 	if bytes.HasPrefix(l, preStart) {
 		return l
@@ -162,7 +297,7 @@ func codeQuotes(l []byte) []byte {
 	return buf.Bytes()
 }
 
-// drop trailing newline
+// trim drops the trailing newline, if present.
 func trim(l []byte) []byte {
 	n := len(l)
 	if n > 0 && l[n-1] == '\n' {
@@ -171,7 +306,7 @@ func trim(l []byte) []byte {
 	return l
 }
 
-// expand tabs to spaces. don't worry about columns.
+// expandTabs expands tabs to spaces. It doesn't worry about columns.
 func expandTabs(l []byte) []byte {
 	return bytes.Replace(l, tab, indent, -1)
 }
diff --git a/doc/install.html b/doc/install.html
index 2256123..a1bc899 100644
--- a/doc/install.html
+++ b/doc/install.html
@@ -81,8 +81,8 @@ To build it, you need these programs installed:
 <li>the standard C libraries, 
 <li>the parser generator Bison,
 <li>GNU <tt>make</tt> (version 3.81 or later),
-<li><tt>awk</tt>, and 
-<li>the text editor <tt>ed</tt>.
+and
+<li><tt>awk</tt>.
 </ul>
 </p>
 
@@ -91,7 +91,7 @@ installed as part of
 <a href="http://developer.apple.com/TOOLS/Xcode/">Xcode</a>. 
 </p>
 
-<p>On Ubuntu/Debian, use <code>sudo apt-get install bison ed gawk gcc libc6-dev
+<p>On Ubuntu/Debian, use <code>sudo apt-get install bison gawk gcc libc6-dev
 make</code>. If you want to build 32-bit binaries on a 64-bit system you'll
 also need the <code>libc6-dev-i386</code> package.
 </p>
diff --git a/doc/makehtml b/doc/makehtml
index c9ac0c8..1b8caed 100755
--- a/doc/makehtml
+++ b/doc/makehtml
@@ -7,7 +7,6 @@ set -e
 
 TXT=${1:-go_tutorial.txt}		# input file
 HTML=$(basename $TXT .txt).html		# output file (basename)
-TMP=TEMP.txt				# input to htmlgen
 
 if ! test -w $HTML
 then
@@ -15,17 +14,4 @@ then
 	exit 1
 fi
 
-if grep -q '^--PROG' $TXT
-then
-	echo >&2 makehtml: processing PROG sections
-	<$TXT >$TMP awk '
-		/^--PROG/ { system("sh ./prog.sh "$2" "$3" "$4" "); getline }
-		/^/ {print}
-	'
-else
-	cp $TXT $TMP
-fi
-
-make htmlgen && ./htmlgen < $TMP > $HTML
-
-rm -f $TMP
+make htmlgen && ./htmlgen < $TXT > $HTML
diff --git a/doc/prog.sh b/doc/prog.sh
deleted file mode 100755
index 6a54098..0000000
--- a/doc/prog.sh
+++ /dev/null
@@ -1,72 +0,0 @@
-#!/bin/sh
-# Copyright 2009 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-# generate HTML for a program excerpt.
-# first arg is file name
-# second arg is awk pattern to match start line
-# third arg is awk pattern to stop processing
-#
-# missing third arg means print one line
-# third arg "END" means proces rest of file
-# missing second arg means process whole file
-#
-# examples:
-#
-#	prog.sh foo.go                       # whole file
-#	prog.sh foo.go "/^func.main/"        # signature of main
-#	prog.sh foo.go "/^func.main/" "/^}/  # body of main
-#
-# non-blank lines are annotated with line number in file
-
-# line numbers are printed %.2d to make them equal-width for nice formatting.
-# the format gives a leading 0.  the format %2d gives a leading space but
-# that appears to confuse sanjay's makehtml formatter into bungling quotes
-# because it makes some lines look indented.
-
-echo "<pre> <!-- $* -->"
-
-case $# in
-3)
-	if test "$3" = "END"  # $2 to end of file
-	then
-		awk '
-			function LINE() { printf("%.2d\t%s\n", NR, $0) }
-			BEGIN { printing = 0 }
-			'$2' { printing = 1; LINE(); getline }
-			printing { if($0 ~ /./) { LINE() } else { print "" } }
-		'
-	else	# $2 through $3
-		awk '
-			function LINE() { printf("%.2d\t%s\n", NR, $0) }
-			BEGIN { printing = 0 }
-			'$2' { printing = 1; LINE(); getline }
-			'$3' && printing { if(printing) {printing = 0; LINE(); exit} }
-			printing { if($0 ~ /./) { LINE() } else { print "" } }
-		'
-	fi
-	;;
-2)	# one line
-	awk '
-		function LINE() { printf("%.2d\t%s\n", NR, $0) }
-		'$2' { LINE(); getline; exit }
-	'
-	;;
-1)	# whole file
-	awk '
-		function LINE() { printf("%.2d\t%s\n", NR, $0) }
-		{ if($0 ~ /./) { LINE() } else { print "" } }
-	'
-	;;
-*)
-	echo >&2 usage: prog.sh file.go /func.main/ /^}/
-esac <$1 |
-sed '
-	s/&/\&/g
-	s/"/\"/g
-	s/</\</g
-	s/>/\>/g
-'
-
-echo '</pre>'
diff --git a/doc/progs/file_windows.go b/doc/progs/file_windows.go
new file mode 100644
index 0000000..d5e7c00
--- /dev/null
+++ b/doc/progs/file_windows.go
@@ -0,0 +1,89 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package file
+
+import (
+	"os"
+	"syscall"
+)
+
+type File struct {
+	fd   syscall.Handle    // file descriptor number
+	name string // file name at Open time
+}
+
+func newFile(fd syscall.Handle, name string) *File {
+	if fd < 0 {
+		return nil
+	}
+	return &File{fd, name}
+}
+
+var (
+	Stdin  = newFile(syscall.Stdin, "/dev/stdin")
+	Stdout = newFile(syscall.Stdout, "/dev/stdout")
+	Stderr = newFile(syscall.Stderr, "/dev/stderr")
+)
+
+func OpenFile(name string, mode int, perm uint32) (file *File, err os.Error) {
+	r, e := syscall.Open(name, mode, perm)
+	if e != 0 {
+		err = os.Errno(e)
+	}
+	return newFile(r, name), err
+}
+
+const (
+	O_RDONLY = syscall.O_RDONLY
+	O_RDWR   = syscall.O_RDWR
+	O_CREATE = syscall.O_CREAT
+	O_TRUNC  = syscall.O_TRUNC
+)
+
+func Open(name string) (file *File, err os.Error) {
+	return OpenFile(name, O_RDONLY, 0)
+}
+
+func Create(name string) (file *File, err os.Error) {
+	return OpenFile(name, O_RDWR|O_CREATE|O_TRUNC, 0666)
+}
+
+func (file *File) Close() os.Error {
+	if file == nil {
+		return os.EINVAL
+	}
+	e := syscall.Close(file.fd)
+	file.fd = syscall.InvalidHandle // so it can't be closed again
+	if e != 0 {
+		return os.Errno(e)
+	}
+	return nil
+}
+
+func (file *File) Read(b []byte) (ret int, err os.Error) {
+	if file == nil {
+		return -1, os.EINVAL
+	}
+	r, e := syscall.Read(file.fd, b)
+	if e != 0 {
+		err = os.Errno(e)
+	}
+	return int(r), err
+}
+
+func (file *File) Write(b []byte) (ret int, err os.Error) {
+	if file == nil {
+		return -1, os.EINVAL
+	}
+	r, e := syscall.Write(file.fd, b)
+	if e != 0 {
+		err = os.Errno(e)
+	}
+	return int(r), err
+}
+
+func (file *File) String() string {
+	return file.name
+}
diff --git a/doc/progs/run b/doc/progs/run
index 241e65d..81781c9 100755
--- a/doc/progs/run
+++ b/doc/progs/run
@@ -14,8 +14,13 @@ fi
 
 rm -f *.$O
 
+if [ "$GOOS" = "windows" ];then
+	$GC -o file.8 file_windows.go
+else
+	$GC file.go
+fi
+
 for i in \
-	file.go \
 	helloworld.go \
 	helloworld3.go \
 	echo.go \
diff --git a/lib/codereview/codereview.py b/lib/codereview/codereview.py
index a222919..385ac2c 100644
--- a/lib/codereview/codereview.py
+++ b/lib/codereview/codereview.py
@@ -1316,7 +1316,7 @@ def clpatch_or_undo(ui, repo, clname, opts, mode):
 		# Create fresh CL and start with patch that would reverse the change.
 		vers = short(rev.node())
 		cl = CL("new")
-		desc = rev.description()
+		desc = str(rev.description())
 		if mode == "undo":
 			cl.desc = (undoHeader % (clname, vers)) + desc + undoFooter
 		else:
@@ -1352,10 +1352,12 @@ def clpatch_or_undo(ui, repo, clname, opts, mode):
 			repo[vers].description()
 		except:
 			return "local repository is out of date; sync to get %s" % (vers)
-		patch, err = portPatch(repo, patch, vers, id)
+		patch1, err = portPatch(repo, patch, vers, id)
 		if err != "":
-			return "codereview issue %s is out of date: %s (%s->%s)" % (clname, err, vers, id)
-
+			if not opts["ignore_hgpatch_failure"]:
+				return "codereview issue %s is out of date: %s (%s->%s)" % (clname, err, vers, id)
+		else:
+			patch = patch1
 	argv = ["hgpatch"]
 	if opts["no_incoming"] or mode == "backport":
 		argv += ["--checksync=false"]
@@ -1369,7 +1371,7 @@ def clpatch_or_undo(ui, repo, clname, opts, mode):
 		return "hgpatch failed"
 	cl.local = True
 	cl.files = out.strip().split()
-	if not cl.files:
+	if not cl.files and not opts["ignore_hgpatch_failure"]:
 		return "codereview issue %s has no changed files" % clname
 	files = ChangedFiles(ui, repo, [], opts)
 	extra = Sub(cl.files, files)
@@ -1781,7 +1783,7 @@ def sync(ui, repo, **opts):
 		err = commands.postincoming(ui, repo, modheads, True, "tip")
 		if err:
 			return err
-	commands.update(ui, repo)
+	commands.update(ui, repo, rev="default")
 	sync_changes(ui, repo)
 
 def sync_note(msg):
diff --git a/misc/dashboard/builder/http.go b/misc/dashboard/builder/http.go
index 5e1da0c..98400c5 100644
--- a/misc/dashboard/builder/http.go
+++ b/misc/dashboard/builder/http.go
@@ -112,16 +112,15 @@ func packages() (pkgs []string, err os.Error) {
 	return
 }
 
-// updatePackage sends package build results and info to the dashboard
-func (b *Builder) updatePackage(pkg string, state bool, buildLog, info string, hash string) os.Error {
+// updatePackage sends package build results and info dashboard
+func (b *Builder) updatePackage(pkg string, ok bool, buildLog, info string) os.Error {
 	return dash("POST", "package", nil, param{
 		"builder": b.name,
 		"key":     b.key,
 		"path":    pkg,
-		"state":   strconv.Btoa(state),
+		"ok":      strconv.Btoa(ok),
 		"log":     buildLog,
 		"info":    info,
-		"go_rev":  hash[:12],
 	})
 }
 
diff --git a/misc/dashboard/builder/main.go b/misc/dashboard/builder/main.go
index 9a714fe..989965b 100644
--- a/misc/dashboard/builder/main.go
+++ b/misc/dashboard/builder/main.go
@@ -60,8 +60,9 @@ var (
 )
 
 var (
-	goroot        string
-	releaseRegexp = regexp.MustCompile(`^(release|weekly)\.[0-9\-.]+`)
+	goroot      string
+	binaryTagRe = regexp.MustCompile(`^(release\.r|weekly\.)[0-9\-.]+`)
+	releaseRe   = regexp.MustCompile(`^release\.r[0-9\-.]+`)
 )
 
 func main() {
@@ -161,7 +162,7 @@ func NewBuilder(builder string) (*Builder, os.Error) {
 	b := &Builder{name: builder}
 
 	// get goos/goarch from builder string
-	s := strings.Split(builder, "-", 3)
+	s := strings.SplitN(builder, "-", 3)
 	if len(s) >= 2 {
 		b.goos, b.goarch = s[0], s[1]
 	} else {
@@ -177,7 +178,7 @@ func NewBuilder(builder string) (*Builder, os.Error) {
 	if err != nil {
 		return nil, fmt.Errorf("readKeys %s (%s): %s", b.name, fn, err)
 	}
-	v := strings.Split(string(c), "\n", -1)
+	v := strings.Split(string(c), "\n")
 	b.key = v[0]
 	if len(v) >= 3 {
 		b.codeUsername, b.codePassword = v[1], v[2]
@@ -200,7 +201,7 @@ func (b *Builder) buildExternal() {
 			log.Println("hg pull failed:", err)
 			continue
 		}
-		hash, tag, err := firstTag(releaseRegexp)
+		hash, tag, err := firstTag(releaseRe)
 		if err != nil {
 			log.Println(err)
 			continue
@@ -321,7 +322,7 @@ func (b *Builder) buildHash(hash string) (err os.Error) {
 	}
 
 	// if this is a release, create tgz and upload to google code
-	releaseHash, release, err := firstTag(releaseRegexp)
+	releaseHash, release, err := firstTag(binaryTagRe)
 	if hash == releaseHash {
 		// clean out build state
 		err = run(b.envv(), srcDir, "./clean.bash", "--nopkg")
@@ -392,7 +393,7 @@ func (b *Builder) envvWindows() []string {
 		skip[name] = true
 	}
 	for _, kv := range os.Environ() {
-		s := strings.Split(kv, "=", 2)
+		s := strings.SplitN(kv, "=", 2)
 		name := strings.ToUpper(s[0])
 		switch {
 		case name == "":
@@ -591,7 +592,7 @@ func fullHash(rev string) (hash string, err os.Error) {
 	if s == "" {
 		return "", fmt.Errorf("cannot find revision")
 	}
-	if len(s) != 20 {
+	if len(s) != 40 {
 		return "", fmt.Errorf("hg returned invalid hash " + s)
 	}
 	return s, nil
@@ -602,7 +603,7 @@ var revisionRe = regexp.MustCompile(`^([^ ]+) +[0-9]+:([0-9a-f]+)$`)
 // firstTag returns the hash and tag of the most recent tag matching re.
 func firstTag(re *regexp.Regexp) (hash string, tag string, err os.Error) {
 	o, _, err := runLog(nil, "", goroot, "hg", "tags")
-	for _, l := range strings.Split(o, "\n", -1) {
+	for _, l := range strings.Split(o, "\n") {
 		if l == "" {
 			continue
 		}
@@ -615,7 +616,7 @@ func firstTag(re *regexp.Regexp) (hash string, tag string, err os.Error) {
 			continue
 		}
 		tag = s[1]
-		hash, err = fullHash(s[3])
+		hash, err = fullHash(s[2])
 		return
 	}
 	err = os.NewError("no matching tag found")
diff --git a/misc/dashboard/builder/package.go b/misc/dashboard/builder/package.go
index ee65d76..b667442 100644
--- a/misc/dashboard/builder/package.go
+++ b/misc/dashboard/builder/package.go
@@ -10,35 +10,47 @@ import (
 	"go/token"
 	"log"
 	"os"
-	"path"
+	"path/filepath"
+	"strings"
 )
 
+const MaxCommentLength = 500 // App Engine won't store more in a StringProperty.
+
 func (b *Builder) buildPackages(workpath string, hash string) os.Error {
 	pkgs, err := packages()
 	if err != nil {
 		return err
 	}
 	for _, p := range pkgs {
-		goroot := path.Join(workpath, "go")
-		goinstall := path.Join(goroot, "bin", "goinstall")
+		goroot := filepath.Join(workpath, "go")
+		gobin := filepath.Join(goroot, "bin")
+		goinstall := filepath.Join(gobin, "goinstall")
 		envv := append(b.envv(), "GOROOT="+goroot)
 
+		// add GOBIN to path
+		for i, v := range envv {
+			if strings.HasPrefix(v, "PATH=") {
+				p := filepath.SplitList(v[5:])
+				p = append([]string{gobin}, p...)
+				s := strings.Join(p, string(filepath.ListSeparator))
+				envv[i] = "PATH=" + s
+			}
+		}
+
 		// goinstall
-		buildLog, code, err := runLog(envv, "", goroot, goinstall, p)
+		buildLog, code, err := runLog(envv, "", goroot, goinstall, "-log=false", p)
 		if err != nil {
 			log.Printf("goinstall %v: %v", p, err)
-			continue
 		}
-		built := code != 0
 
 		// get doc comment from package source
-		info, err := packageComment(p, path.Join(goroot, "pkg", p))
+		info, err := packageComment(p, filepath.Join(goroot, "src", "pkg", p))
 		if err != nil {
-			log.Printf("goinstall %v: %v", p, err)
+			log.Printf("packageComment %v: %v", p, err)
 		}
 
 		// update dashboard with build state + info
-		err = b.updatePackage(p, built, buildLog, info, hash)
+		err = b.updatePackage(p, code == 0, buildLog, info)
 		if err != nil {
 			log.Printf("updatePackage %v: %v", p, err)
 		}
@@ -46,9 +58,15 @@ func (b *Builder) buildPackages(workpath string, hash string) os.Error {
 	return nil
 }
 
+func isGoFile(fi *os.FileInfo) bool {
+	return fi.IsRegular() && // exclude directories
+		!strings.HasPrefix(fi.Name, ".") && // ignore .files
+		filepath.Ext(fi.Name) == ".go"
+}
+
 func packageComment(pkg, pkgpath string) (info string, err os.Error) {
 	fset := token.NewFileSet()
-	pkgs, err := parser.ParseDir(fset, pkgpath, nil, parser.PackageClauseOnly|parser.ParseComments)
+	pkgs, err := parser.ParseDir(fset, pkgpath, isGoFile, parser.PackageClauseOnly|parser.ParseComments)
 	if err != nil {
 		return
 	}
@@ -62,5 +80,15 @@ func packageComment(pkg, pkgpath string) (info string, err os.Error) {
 		pdoc := doc.NewPackageDoc(pkgs[name], pkg)
 		info = pdoc.Doc
 	}
+	// grab only first paragraph
+	if parts := strings.SplitN(info, "\n\n", 2); len(parts) > 1 {
+		info = parts[0]
+	}
+	// replace newlines with spaces
+	info = strings.Replace(info, "\n", " ", -1)
+	// truncate
+	if len(info) > MaxCommentLength {
+		info = info[:MaxCommentLength]
+	}
 	return
 }
diff --git a/misc/dashboard/godashboard/auth.py b/misc/dashboard/godashboard/auth.py
new file mode 100644
index 0000000..73a54c0
--- /dev/null
+++ b/misc/dashboard/godashboard/auth.py
@@ -0,0 +1,13 @@
+# 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.
+
+import hmac
+
+# local imports
+import key
+
+def auth(req):
+    k = req.get('key')
+    return k == hmac.new(key.accessKey, req.get('builder')).hexdigest() or k == key.accessKey
+
diff --git a/misc/dashboard/godashboard/gobuild.py b/misc/dashboard/godashboard/gobuild.py
index 5678f2e..685dc83 100644
--- a/misc/dashboard/godashboard/gobuild.py
+++ b/misc/dashboard/godashboard/gobuild.py
@@ -14,14 +14,13 @@ from google.appengine.ext.webapp import template
 from google.appengine.ext.webapp.util import run_wsgi_app
 import datetime
 import hashlib
-import hmac
 import logging
 import os
 import re
 import bz2
 
 # local imports
-import key
+from auth import auth
 import const
 
 # The majority of our state are commit objects. One of these exists for each of
@@ -142,10 +141,6 @@ class DashboardHandler(webapp.RequestHandler):
         simplejson.dump(obj, self.response.out)
         return
 
-def auth(req):
-    k = req.get('key')
-    return k == hmac.new(key.accessKey, req.get('builder')).hexdigest() or k == key.accessKey
-
 # Todo serves /todo.  It tells the builder which commits need to be built.
 class Todo(DashboardHandler):
     def get(self):
diff --git a/misc/dashboard/godashboard/index.yaml b/misc/dashboard/godashboard/index.yaml
index 4a00c4a..f39299d 100644
--- a/misc/dashboard/godashboard/index.yaml
+++ b/misc/dashboard/godashboard/index.yaml
@@ -49,4 +49,3 @@ indexes:
 # manually, move them above the marker line.  The index.yaml file is
 # automatically uploaded to the admin console when you next deploy
 # your application using appcfg.py.
-
diff --git a/misc/dashboard/godashboard/package.html b/misc/dashboard/godashboard/package.html
index 9332b5a..043080b 100644
--- a/misc/dashboard/godashboard/package.html
+++ b/misc/dashboard/godashboard/package.html
@@ -19,37 +19,43 @@
     Packages listed on this page are written by third parties and 
     may or may not build or be safe to use.
     </p>
+
+    <p>
+    An "ok" in the <b>build</b> column indicates that the package is
+    <a href="http://golang.org/cmd/goinstall/">goinstallable</a>
+    with the latest
+    <a href="http://golang.org/doc/devel/release.html">release</a> of Go.
+    </p>
+
+    <p>
+    The <b>info</b> column shows the first paragraph from the
+    <a href="http://blog.golang.org/2011/03/godoc-documenting-go-code.html">package doc comment</a>.
+    </p>
     
     <h2>Recently Installed Packages</h2>
     <table class="alternate" cellpadding="0" cellspacing="0">
-      <tr><th>last install</th><th>count</th><th>path</th><th>project</th></tr>
+      <tr><th>last install</th><th>count</th><th>build</th><th>path</th><th>info</th></tr>
       {% for r in by_time %}
         <tr>
           <td class="time">{{r.last_install|date:"Y-M-d H:i"}}</td>
           <td class="count">{{r.count}}</td>
+          <td class="ok">{% if r.ok %}<a title="{{r.last_ok|date:"Y-M-d H:i"}}">ok</a>{% else %} {% endif %}</td>
           <td class="path"><a href="{{r.web_url}}">{{r.path}}</a></td>
-	  <td class="project">
-	  {% for p in r.project_set %}
-		<a href="{{p.web_url}}">{{p.name}}</a> - {{p.descr}}
-	  {% endfor %}
-	  </td>
+	      <td class="info">{% if r.info %}{{r.info|escape}}{% endif %}</td>
         </tr>
       {% endfor %}
     </table>
 
     <h2>Most Installed Packages</h2>
     <table class="alternate" cellpadding="0" cellspacing="0">
-      <tr><th>last install</th><th>count</th><th>path</th><th>project</th></tr>
+      <tr><th>last install</th><th>count</th><th>build</th><th>path</th><th>info</th></tr>
       {% for r in by_count %}
         <tr>
           <td class="time">{{r.last_install|date:"Y-M-d H:i"}}</td>
           <td class="count">{{r.count}}</td>
+          <td class="ok">{% if r.ok %}<a title="{{r.last_ok|date:"Y-M-d H:i"}}">ok</a>{% else %} {% endif %}</td>
           <td class="path"><a href="{{r.web_url}}">{{r.path}}</a></td>
-	  <td class="project">
-	  {% for p in r.project_set %}
-		<a href="{{p.web_url}}">{{p.name}}</a> - {{p.descr}}
-	  {% endfor %}
-	  </td>
+	      <td class="info">{% if r.info %}{{r.info|escape}}{% endif %}</td>
         </tr>
       {% endfor %}
     </table>
diff --git a/misc/dashboard/godashboard/package.py b/misc/dashboard/godashboard/package.py
index dd09593..316f386 100644
--- a/misc/dashboard/godashboard/package.py
+++ b/misc/dashboard/godashboard/package.py
@@ -23,6 +23,7 @@ import sets
 # local imports
 import toutf8
 import const
+from auth import auth
 
 template.register_template_library('toutf8')
 
@@ -34,6 +35,11 @@ class Package(db.Model):
     count = db.IntegerProperty()
     last_install = db.DateTimeProperty()
 
+    # data contributed by gobuilder
+    info = db.StringProperty()  
+    ok = db.BooleanProperty()
+    last_ok = db.DateTimeProperty()
+
 class Project(db.Model):
     name = db.StringProperty(indexed=True)
     descr = db.StringProperty()
@@ -43,22 +49,25 @@ class Project(db.Model):
     tags = db.ListProperty(str)
     approved = db.BooleanProperty(indexed=True)
 
-re_bitbucket = re.compile(r'^bitbucket\.org/[a-z0-9A-Z_.\-]+/[a-z0-9A-Z_.\-]+$')
-re_googlecode = re.compile(r'^[a-z0-9\-]+\.googlecode\.com/(svn|hg)$')
+re_bitbucket = re.compile(r'^(bitbucket\.org/[a-z0-9A-Z_.\-]+/[a-zA-Z0-9_.\-]+)(/[a-z0-9A-Z_.\-/]+)?$')
+re_googlecode = re.compile(r'^[a-z0-9\-]+\.googlecode\.com/(svn|hg)(/[a-z0-9A-Z_.\-/]+)?$')
 re_github = re.compile(r'^github\.com/[a-z0-9A-Z_.\-]+(/[a-z0-9A-Z_.\-]+)+$')
 re_launchpad = re.compile(r'^launchpad\.net/([a-z0-9A-Z_.\-]+(/[a-z0-9A-Z_.\-]+)?|~[a-z0-9A-Z_.\-]+/(\+junk|[a-z0-9A-Z_.\-]+)/[a-z0-9A-Z_.\-]+)(/[a-z0-9A-Z_.\-/]+)?$')
 
-
 def vc_to_web(path):
     if re_bitbucket.match(path):
-        check_url = 'http://' + path + '/?cmd=heads'
-        web = 'http://' + path + '/'
+        m = re_bitbucket.match(path)
+        check_url = 'http://' + m.group(1) + '/?cmd=heads'
+        web = 'http://' + m.group(1) + '/'
     elif re_github.match(path):
         m = re_github_web.match(path)
         check_url = 'https://raw.github.com/' + m.group(1) + '/' + m.group(2) + '/master/'
-        web = 'http://github.com/' + m.group(1) + '/' + m.group(2)
+        web = 'http://github.com/' + m.group(1) + '/' + m.group(2) + '/'
     elif re_googlecode.match(path):
+        m = re_googlecode.match(path)
         check_url = 'http://'+path
+        if not m.group(2):  # append / after bare '/hg'
+            check_url += '/'
         web = 'http://code.google.com/p/' + path[:path.index('.')]
     elif re_launchpad.match(path):
         check_url = web = 'https://'+path
@@ -142,8 +151,7 @@ class PackagePage(webapp.RequestHandler):
 
     def can_get_url(self, url):
         try:
-            req = urllib2.Request(url)
-            response = urllib2.urlopen(req)
+            urllib2.urlopen(urllib2.Request(url))
             return True
         except:
             return False
@@ -173,15 +181,23 @@ class PackagePage(webapp.RequestHandler):
                 return False
             p = Package(key_name = key, path = path, count = 0, web_url = web)
 
+        # is this the builder updating package metadata?
+        if auth(self.request):
+            p.info = self.request.get('info')
+            p.ok = self.request.get('ok') == "true"
+            if p.ok:
+                p.last_ok = datetime.datetime.utcnow()
+        else:
+            p.count += 1
+            p.last_install = datetime.datetime.utcnow()
+
         # update package object
-        p.count += 1
-        p.last_install = datetime.datetime.utcnow()
         p.put()
         return True
 
     def post(self):
         path = self.request.get('path')
-        ok = self.record_pkg(path)
+        ok = db.run_in_transaction(self.record_pkg,  path)
         if ok:
             self.response.set_status(200)
             self.response.out.write('ok')
diff --git a/misc/dashboard/godashboard/static/style.css b/misc/dashboard/godashboard/static/style.css
index 481af36..a7e61dd 100644
--- a/misc/dashboard/godashboard/static/style.css
+++ b/misc/dashboard/godashboard/static/style.css
@@ -52,7 +52,7 @@ table.alternate tr td:last-child {
 	padding-right: 0;
 }
 table.alternate tr:nth-child(2n) {
-	background-color: #f8f8f8;
+	background-color: #f0f0f0;
 }
 span.hash {
 	font-family: monospace;
@@ -62,10 +62,19 @@ span.hash {
 td.date {
 	color: #aaa;
 }
-td.result {
+td.ok { 
 	text-align: center;
+	color: #060; 
+	font-weight: bold;
+}
+td.ok a {
+	cursor: help;
+}
+th {
+	text-align: left;
 }
 th.builder {
+	text-align: center;
 	font-weight: bold;
 }
 a.fail {
diff --git a/misc/emacs/go-mode.el b/misc/emacs/go-mode.el
index 03f0a2a..ba7f723 100644
--- a/misc/emacs/go-mode.el
+++ b/misc/emacs/go-mode.el
@@ -69,8 +69,8 @@
 some syntax analysis.")
 
 (defvar go-mode-font-lock-keywords
-  (let ((builtins '("cap" "close" "closed" "len" "make" "new"
-                    "panic" "panicln" "print" "println"))
+  (let ((builtins '("append" "cap" "close" "complex" "copy" "imag" "len"
+                    "make" "new" "panic" "print" "println" "real" "recover"))
         (constants '("nil" "true" "false" "iota"))
         (type-name "\\s *\\(?:[*(]\\s *\\)*\\(?:\\w+\\s *\\.\\s *\\)?\\(\\w+\\)")
         )
diff --git a/misc/vim/ftdetect/gofiletype.vim b/misc/vim/ftdetect/gofiletype.vim
index 8843121..f03a1d8 100644
--- a/misc/vim/ftdetect/gofiletype.vim
+++ b/misc/vim/ftdetect/gofiletype.vim
@@ -1 +1 @@
-au BufRead,BufNewFile *.go set filetype=go
+au BufReadPre,BufNewFile *.go set filetype=go fileencoding=utf-8 fileencodings=utf-8
diff --git a/src/cmd/5c/gc.h b/src/cmd/5c/gc.h
index 549e0c8..ff6d519 100644
--- a/src/cmd/5c/gc.h
+++ b/src/cmd/5c/gc.h
@@ -28,7 +28,7 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
-
+#include	<u.h>
 #include	"../cc/cc.h"
 #include	"../5l/5.out.h"
 
diff --git a/src/cmd/5l/asm.c b/src/cmd/5l/asm.c
index 4afed2b..2c9e50d 100644
--- a/src/cmd/5l/asm.c
+++ b/src/cmd/5l/asm.c
@@ -68,9 +68,6 @@ enum {
 	ElfStrText,
 	ElfStrData,
 	ElfStrBss,
-	ElfStrGosymcounts,
-	ElfStrGosymtab,
-	ElfStrGopclntab,
 	ElfStrSymtab,
 	ElfStrStrtab,
 	ElfStrShstrtab,
@@ -160,12 +157,11 @@ doelf(void)
 	elfstr[ElfStrEmpty] = addstring(shstrtab, "");
 	elfstr[ElfStrText] = addstring(shstrtab, ".text");
 	elfstr[ElfStrData] = addstring(shstrtab, ".data");
-	addstring(shstrtab, ".rodata");
 	elfstr[ElfStrBss] = addstring(shstrtab, ".bss");
+	addstring(shstrtab, ".rodata");
+	addstring(shstrtab, ".gosymtab");
+	addstring(shstrtab, ".gopclntab");
 	if(!debug['s']) {	
-		elfstr[ElfStrGosymcounts] = addstring(shstrtab, ".gosymcounts");
-		elfstr[ElfStrGosymtab] = addstring(shstrtab, ".gosymtab");
-		elfstr[ElfStrGopclntab] = addstring(shstrtab, ".gopclntab");
 		elfstr[ElfStrSymtab] = addstring(shstrtab, ".symtab");
 		elfstr[ElfStrStrtab] = addstring(shstrtab, ".strtab");
 	}
@@ -307,10 +303,11 @@ asmb(void)
 	seek(cout, sect->vaddr - segtext.vaddr + segtext.fileoff, 0);
 	codeblk(sect->vaddr, sect->len);
 
-	/* output read-only data in text segment */
-	sect = segtext.sect->next;
-	seek(cout, sect->vaddr - segtext.vaddr + segtext.fileoff, 0);
-	datblk(sect->vaddr, sect->len);
+	/* output read-only data in text segment (rodata, gosymtab and pclntab) */
+	for(sect = sect->next; sect != nil; sect = sect->next) {
+		seek(cout, sect->vaddr - segtext.vaddr + segtext.fileoff, 0);
+		datblk(sect->vaddr, sect->len);
+	}
 
 	if(debug['v'])
 		Bprint(&bso, "%5.2f datblk\n", cputime());
@@ -572,18 +569,6 @@ asmb(void)
 			elfshbits(sect);
 
 		if (!debug['s']) {
-			sh = newElfShdr(elfstr[ElfStrGosymtab]);
-			sh->type = SHT_PROGBITS;
-			sh->flags = SHF_ALLOC;
-			sh->addralign = 1;
-			shsym(sh, lookup("symtab", 0));
-
-			sh = newElfShdr(elfstr[ElfStrGopclntab]);
-			sh->type = SHT_PROGBITS;
-			sh->flags = SHF_ALLOC;
-			sh->addralign = 1;
-			shsym(sh, lookup("pclntab", 0));
-
 			sh = newElfShdr(elfstr[ElfStrSymtab]);
 			sh->type = SHT_SYMTAB;
 			sh->off = symo;
diff --git a/src/cmd/5l/mkenam b/src/cmd/5l/mkenam
index 265cb99..6cccb02 100644
--- a/src/cmd/5l/mkenam
+++ b/src/cmd/5l/mkenam
@@ -28,18 +28,18 @@
 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 # THE SOFTWARE.
 
-ed - ../5l/5.out.h <<'!'
-v/^	A/d
-,s/^	A/	"/
-g/ .*$/s///
-,s/,*$/",/
-1i
-char*	anames[] =
-{
-.
-$a
-};
-.
-w enam.c
-Q
-!
+awk '
+BEGIN {
+	print "char*	anames[] ="
+	print "{"
+}
+
+/^	A/ {
+	name=$1
+	sub(/,/, "", name)
+	sub(/^A/, "", name)
+	print "\t\"" name "\","
+}
+
+END { print "};" }
+' ../5l/5.out.h >enam.c
diff --git a/src/cmd/6c/gc.h b/src/cmd/6c/gc.h
index 735cd89..775d972 100644
--- a/src/cmd/6c/gc.h
+++ b/src/cmd/6c/gc.h
@@ -28,6 +28,7 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
+#include	<u.h>
 #include	"../cc/cc.h"
 #include	"../6l/6.out.h"
 
diff --git a/src/cmd/6l/asm.c b/src/cmd/6l/asm.c
index 4c04112..9136e03 100644
--- a/src/cmd/6l/asm.c
+++ b/src/cmd/6l/asm.c
@@ -87,9 +87,6 @@ enum {
 	ElfStrText,
 	ElfStrData,
 	ElfStrBss,
-	ElfStrGosymcounts,
-	ElfStrGosymtab,
-	ElfStrGopclntab,
 	ElfStrShstrtab,
 	ElfStrSymtab,
 	ElfStrStrtab,
@@ -571,10 +568,9 @@ doelf(void)
 	elfstr[ElfStrBss] = addstring(shstrtab, ".bss");
 	addstring(shstrtab, ".elfdata");
 	addstring(shstrtab, ".rodata");
+	addstring(shstrtab, ".gosymtab");
+	addstring(shstrtab, ".gopclntab");
 	if(!debug['s']) {
-		elfstr[ElfStrGosymcounts] = addstring(shstrtab, ".gosymcounts");
-		elfstr[ElfStrGosymtab] = addstring(shstrtab, ".gosymtab");
-		elfstr[ElfStrGopclntab] = addstring(shstrtab, ".gopclntab");
 		elfstr[ElfStrSymtab] = addstring(shstrtab, ".symtab");
 		elfstr[ElfStrStrtab] = addstring(shstrtab, ".strtab");
 		dwarfaddshstrings(shstrtab);
@@ -718,10 +714,11 @@ asmb(void)
 	seek(cout, sect->vaddr - segtext.vaddr + segtext.fileoff, 0);
 	codeblk(sect->vaddr, sect->len);
 
-	/* output read-only data in text segment */
-	sect = segtext.sect->next;
-	seek(cout, sect->vaddr - segtext.vaddr + segtext.fileoff, 0);
-	datblk(sect->vaddr, sect->len);
+	/* output read-only data in text segment (rodata, gosymtab and pclntab) */
+	for(sect = sect->next; sect != nil; sect = sect->next) {
+		seek(cout, sect->vaddr - segtext.vaddr + segtext.fileoff, 0);
+		datblk(sect->vaddr, sect->len);
+	}
 
 	if(debug['v'])
 		Bprint(&bso, "%5.2f datblk\n", cputime());
@@ -1013,18 +1010,6 @@ asmb(void)
 			elfshbits(sect);
 
 		if (!debug['s']) {
-			sh = newElfShdr(elfstr[ElfStrGosymtab]);
-			sh->type = SHT_PROGBITS;
-			sh->flags = SHF_ALLOC;
-			sh->addralign = 1;
-			shsym(sh, lookup("symtab", 0));
-
-			sh = newElfShdr(elfstr[ElfStrGopclntab]);
-			sh->type = SHT_PROGBITS;
-			sh->flags = SHF_ALLOC;
-			sh->addralign = 1;
-			shsym(sh, lookup("pclntab", 0));
-
 			sh = newElfShdr(elfstr[ElfStrSymtab]);
 			sh->type = SHT_SYMTAB;
 			sh->off = symo;
diff --git a/src/cmd/6l/mkenam b/src/cmd/6l/mkenam
index 5cabb26..3001dbe 100644
--- a/src/cmd/6l/mkenam
+++ b/src/cmd/6l/mkenam
@@ -28,18 +28,18 @@
 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 # THE SOFTWARE.
 
-/bin/ed - ../6l/6.out.h <<'!'
-v/^	A/d
-,s/^	A/	"/
-g/ .*$/s///
-,s/,*$/",/
-1i
-char*	anames[] =
-{
-.
-$a
-};
-.
-w enam.c
-Q
-!
+awk '
+BEGIN {
+	print "char*	anames[] ="
+	print "{"
+}
+
+/^	A/ {
+	name=$1
+	sub(/,/, "", name)
+	sub(/^A/, "", name)
+	print "\t\"" name "\","
+}
+
+END { print "};" }
+' ../6l/6.out.h >enam.c
diff --git a/src/cmd/8a/a.h b/src/cmd/8a/a.h
index 3cb30f4..c5c22d7 100644
--- a/src/cmd/8a/a.h
+++ b/src/cmd/8a/a.h
@@ -28,8 +28,6 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
-#include <u.h>
-#include <libc.h>
 #include <bio.h>
 #include "../8l/8.out.h"
 
@@ -57,7 +55,9 @@ typedef	struct	Gen2	Gen2;
 #define	NSYMB		500
 #define	BUFSIZ		8192
 #define	HISTSZ		20
+#ifndef	EOF
 #define	EOF		(-1)
+#endif
 #define	IGN		(-2)
 #define	GETC()		((--fi.c < 0)? filbuf(): *fi.p++ & 0xff)
 #define	NHASH		503
diff --git a/src/cmd/8a/a.y b/src/cmd/8a/a.y
index 04662f8..a8ac773 100644
--- a/src/cmd/8a/a.y
+++ b/src/cmd/8a/a.y
@@ -29,7 +29,9 @@
 // THE SOFTWARE.
 
 %{
+#include <u.h>
 #include <stdio.h>	/* if we don't, bison will, and a.h re-#defines getc */
+#include <libc.h>
 #include "a.h"
 %}
 %union	{
diff --git a/src/cmd/8a/lex.c b/src/cmd/8a/lex.c
index 0788618..ab4de41 100644
--- a/src/cmd/8a/lex.c
+++ b/src/cmd/8a/lex.c
@@ -29,9 +29,10 @@
 // THE SOFTWARE.
 
 #define	EXTERN
+#include <u.h>
+#include <libc.h>
 #include "a.h"
 #include "y.tab.h"
-#include <ctype.h>
 
 enum
 {
diff --git a/src/cmd/8c/gc.h b/src/cmd/8c/gc.h
index 9fead60..32b80e9 100644
--- a/src/cmd/8c/gc.h
+++ b/src/cmd/8c/gc.h
@@ -28,6 +28,7 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
+#include	<u.h>
 #include	"../cc/cc.h"
 #include	"../8l/8.out.h"
 
@@ -400,6 +401,7 @@ void	shiftit(Type*, Node*, Node*);
 #pragma	varargck	type	"A"	int
 #pragma	varargck	type	"B"	Bits
 #pragma	varargck	type	"D"	Adr*
+#pragma	varargck	type	"lD"	Adr*
 #pragma	varargck	type	"P"	Prog*
 #pragma	varargck	type	"R"	int
 #pragma	varargck	type	"S"	char*
diff --git a/src/cmd/8c/swt.c b/src/cmd/8c/swt.c
index d07a543..769ef2c 100644
--- a/src/cmd/8c/swt.c
+++ b/src/cmd/8c/swt.c
@@ -237,10 +237,10 @@ outcode(void)
 		Bprint(&b, "\n");
 		Bprint(&b, "$$  // exports\n\n");
 		Bprint(&b, "$$  // local types\n\n");
-		Bprint(&b, "$$  // dynimport\n", thestring);
+		Bprint(&b, "$$  // dynimport\n");
 		for(i=0; i<ndynimp; i++)
 			Bprint(&b, "dynimport %s %s %s\n", dynimp[i].local, dynimp[i].remote, dynimp[i].path);
-		Bprint(&b, "\n$$  // dynexport\n", thestring);
+		Bprint(&b, "\n$$  // dynexport\n");
 		for(i=0; i<ndynexp; i++)
 			Bprint(&b, "dynexport %s %s\n", dynexp[i].local, dynexp[i].remote);
 		Bprint(&b, "\n$$\n\n");
diff --git a/src/cmd/8l/asm.c b/src/cmd/8l/asm.c
index a9a720a..e1ccfb8 100644
--- a/src/cmd/8l/asm.c
+++ b/src/cmd/8l/asm.c
@@ -83,9 +83,6 @@ enum {
 	ElfStrText,
 	ElfStrData,
 	ElfStrBss,
-	ElfStrGosymcounts,
-	ElfStrGosymtab,
-	ElfStrGopclntab,
 	ElfStrShstrtab,
 	ElfStrSymtab,
 	ElfStrStrtab,
@@ -531,10 +528,9 @@ doelf(void)
 	elfstr[ElfStrBss] = addstring(shstrtab, ".bss");
 	addstring(shstrtab, ".elfdata");
 	addstring(shstrtab, ".rodata");
+	addstring(shstrtab, ".gosymtab");
+	addstring(shstrtab, ".gopclntab");
 	if(!debug['s']) {
-		elfstr[ElfStrGosymcounts] = addstring(shstrtab, ".gosymcounts");
-		elfstr[ElfStrGosymtab] = addstring(shstrtab, ".gosymtab");
-		elfstr[ElfStrGopclntab] = addstring(shstrtab, ".gopclntab");
 		elfstr[ElfStrSymtab] = addstring(shstrtab, ".symtab");
 		elfstr[ElfStrStrtab] = addstring(shstrtab, ".strtab");
 		dwarfaddshstrings(shstrtab);
@@ -679,10 +675,11 @@ asmb(void)
 	seek(cout, sect->vaddr - segtext.vaddr + segtext.fileoff, 0);
 	codeblk(sect->vaddr, sect->len);
 
-	/* output read-only data in text segment */
-	sect = segtext.sect->next;
-	seek(cout, sect->vaddr - segtext.vaddr + segtext.fileoff, 0);
-	datblk(sect->vaddr, sect->len);
+	/* output read-only data in text segment (rodata, gosymtab and pclntab) */
+	for(sect = sect->next; sect != nil; sect = sect->next) {
+		seek(cout, sect->vaddr - segtext.vaddr + segtext.fileoff, 0);
+		datblk(sect->vaddr, sect->len);
+	}
 
 	if(debug['v'])
 		Bprint(&bso, "%5.2f datblk\n", cputime());
@@ -1083,18 +1080,6 @@ asmb(void)
 			elfshbits(sect);
 
 		if (!debug['s']) {
-			sh = newElfShdr(elfstr[ElfStrGosymtab]);
-			sh->type = SHT_PROGBITS;
-			sh->flags = SHF_ALLOC;
-			sh->addralign = 1;
-			shsym(sh, lookup("symtab", 0));
-
-			sh = newElfShdr(elfstr[ElfStrGopclntab]);
-			sh->type = SHT_PROGBITS;
-			sh->flags = SHF_ALLOC;
-			sh->addralign = 1;
-			shsym(sh, lookup("pclntab", 0));
-
 			sh = newElfShdr(elfstr[ElfStrSymtab]);
 			sh->type = SHT_SYMTAB;
 			sh->off = symo;
diff --git a/src/cmd/8l/mkenam b/src/cmd/8l/mkenam
index b33fec7..992aa31 100644
--- a/src/cmd/8l/mkenam
+++ b/src/cmd/8l/mkenam
@@ -28,18 +28,18 @@
 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 # THE SOFTWARE.
 
-ed - ../8l/8.out.h <<'!'
-v/^	A/d
-,s/^	A/	"/
-g/ .*$/s///
-,s/,*$/",/
-1i
-char*	anames[] =
-{
-.
-$a
-};
-.
-w enam.c
-Q
-!
+awk '
+BEGIN {
+	print "char*	anames[] ="
+	print "{"
+}
+
+/^	A/ {
+	name=$1
+	sub(/,/, "", name)
+	sub(/^A/, "", name)
+	print "\t\"" name "\","
+}
+
+END { print "};" }
+' ../8l/8.out.h >enam.c
diff --git a/src/cmd/cc/acid.c b/src/cmd/cc/acid.c
index c6a6722..23147e5 100644
--- a/src/cmd/cc/acid.c
+++ b/src/cmd/cc/acid.c
@@ -28,6 +28,7 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
+#include <u.h>
 #include "cc.h"
 
 static char *kwd[] =
diff --git a/src/cmd/cc/bits.c b/src/cmd/cc/bits.c
index aef4449..4496d65 100644
--- a/src/cmd/cc/bits.c
+++ b/src/cmd/cc/bits.c
@@ -28,6 +28,7 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
+#include	<u.h>
 #include	"cc.h"
 
 Bits
diff --git a/src/cmd/cc/cc.h b/src/cmd/cc/cc.h
index 8e8f6af..a38e658 100644
--- a/src/cmd/cc/cc.h
+++ b/src/cmd/cc/cc.h
@@ -28,10 +28,8 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
-#include <u.h>
 #include <libc.h>
 #include <bio.h>
-#include <ctype.h>
 
 #pragma	lib	"../cc/cc.a$O"
 
@@ -816,7 +814,9 @@ int	machcap(Node*);
 #pragma	varargck	type	"L"	int32
 #pragma	varargck	type	"Q"	int32
 #pragma	varargck	type	"O"	int
+#pragma	varargck	type	"O"	uint
 #pragma	varargck	type	"T"	Type*
+#pragma	varargck	type	"U"	char*
 #pragma	varargck	type	"|"	int
 
 enum
diff --git a/src/cmd/cc/cc.y b/src/cmd/cc/cc.y
index 470fdae..515a803 100644
--- a/src/cmd/cc/cc.y
+++ b/src/cmd/cc/cc.y
@@ -29,6 +29,7 @@
 // THE SOFTWARE.
 
 %{
+#include <u.h>
 #include <stdio.h>	/* if we don't, bison will, and cc.h re-#defines getc */
 #include "cc.h"
 %}
diff --git a/src/cmd/cc/com.c b/src/cmd/cc/com.c
index b1a8a47..6e470ee 100644
--- a/src/cmd/cc/com.c
+++ b/src/cmd/cc/com.c
@@ -28,6 +28,7 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
+#include <u.h>
 #include "cc.h"
 
 int compar(Node*, int);
@@ -127,7 +128,7 @@ tcomo(Node *n, int f)
 	case ORETURN:
 		if(l == Z) {
 			if(n->type->etype != TVOID)
-				warn(n, "null return of a typed function");
+				diag(n, "null return of a typed function");
 			break;
 		}
 		if(tcom(l))
diff --git a/src/cmd/cc/com64.c b/src/cmd/cc/com64.c
index 8d6e07d..fb7a3f7 100644
--- a/src/cmd/cc/com64.c
+++ b/src/cmd/cc/com64.c
@@ -28,6 +28,7 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
+#include <u.h>
 #include "cc.h"
 
 /*
diff --git a/src/cmd/cc/dcl.c b/src/cmd/cc/dcl.c
index 6f1b8a9..d624bf2 100644
--- a/src/cmd/cc/dcl.c
+++ b/src/cmd/cc/dcl.c
@@ -28,6 +28,7 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
+#include <u.h>
 #include "cc.h"
 
 Node*
diff --git a/src/cmd/cc/dpchk.c b/src/cmd/cc/dpchk.c
index 0e51101..42c245b 100644
--- a/src/cmd/cc/dpchk.c
+++ b/src/cmd/cc/dpchk.c
@@ -28,6 +28,8 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
+#include	<u.h>
+#include	<ctype.h>
 #include	"cc.h"
 #include	"y.tab.h"
 
@@ -56,7 +58,9 @@ struct	Tname
 {
 	char*	name;
 	int	param;
+	int	count;
 	Tname*	link;
+	Tprot*	prot;
 };
 
 static	Type*	indchar;
@@ -131,8 +135,8 @@ getflag(char *s)
 	return flag;
 }
 
-void
-newprot(Sym *m, Type *t, char *s)
+static void
+newprot(Sym *m, Type *t, char *s, Tprot **prot)
 {
 	Bits flag;
 	Tprot *l;
@@ -142,32 +146,37 @@ newprot(Sym *m, Type *t, char *s)
 		return;
 	}
 	flag = getflag(s);
-	for(l=tprot; l; l=l->link)
+	for(l=*prot; l; l=l->link)
 		if(beq(flag, l->flag) && sametype(t, l->type))
 			return;
 	l = alloc(sizeof(*l));
 	l->type = t;
 	l->flag = flag;
-	l->link = tprot;
-	tprot = l;
+	l->link = *prot;
+	*prot = l;
 }
 
-void
-newname(char *s, int p)
+static Tname*
+newname(char *s, int p, int count)
 {
 	Tname *l;
 
 	for(l=tname; l; l=l->link)
 		if(strcmp(l->name, s) == 0) {
-			if(l->param != p)
+			if(p >= 0 && l->param != p)
 				yyerror("vargck %s already defined\n", s);
-			return;
+			return l;
 		}
+	if(p < 0)
+		return nil;
+
 	l = alloc(sizeof(*l));
 	l->name = s;
 	l->param = p;
 	l->link = tname;
+	l->count = count;
 	tname = l;
+	return l;
 }
 
 void
@@ -234,6 +243,7 @@ pragvararg(void)
 	int n, c;
 	char *t;
 	Type *ty;
+	Tname *l;
 
 	if(!debug['F'])
 		goto out;
@@ -244,6 +254,8 @@ pragvararg(void)
 		goto cktype;
 	if(s && strcmp(s->name, "flag") == 0)
 		goto ckflag;
+	if(s && strcmp(s->name, "countpos") == 0)
+		goto ckcount;
 	yyerror("syntax in #pragma varargck");
 	goto out;
 
@@ -255,7 +267,18 @@ ckpos:
 	n = getnsn();
 	if(n < 0)
 		goto bad;
-	newname(s->name, n);
+	newname(s->name, n, 0);
+	goto out;
+
+ckcount:
+/*#pragma	varargck	countpos	name 2*/
+	s = getsym();
+	if(s == S)
+		goto bad;
+	n = getnsn();
+	if(n < 0)
+		goto bad;
+	newname(s->name, 0, n);
 	goto out;
 
 ckflag:
@@ -276,6 +299,25 @@ ckflag:
 	goto out;
 
 cktype:
+	c = getnsc();
+	unget(c);
+	if(c != '"') {
+/*#pragma	varargck	type	name	int*/
+		s = getsym();
+		if(s == S)
+			goto bad;
+		l = newname(s->name, -1, -1);
+		s = getsym();
+		if(s == S)
+			goto bad;
+		ty = s->type;
+		while((c = getnsc()) == '*')
+			ty = typ(TIND, ty);
+		unget(c);
+		newprot(s, ty, "a", &l->prot);
+		goto out;
+	}
+
 /*#pragma	varargck	type	O	int*/
 	t = getquoted();
 	if(t == nil)
@@ -287,7 +329,7 @@ cktype:
 	while((c = getnsc()) == '*')
 		ty = typ(TIND, ty);
 	unget(c);
-	newprot(s, ty, t);
+	newprot(s, ty, t, &tprot);
 	goto out;
 
 bad:
@@ -384,7 +426,8 @@ dpcheck(Node *n)
 	char *s;
 	Node *a, *b;
 	Tname *l;
-	int i;
+	Tprot *tl;
+	int i, j;
 
 	if(n == Z)
 		return;
@@ -398,20 +441,76 @@ dpcheck(Node *n)
 	if(l == 0)
 		return;
 
+	if(l->count > 0) {
+		// fetch count, then check remaining length
+		i = l->count;
+		a = nil;
+		b = n->right;
+		while(i > 0) {
+			b = nextarg(b, &a);
+			i--;
+		}
+		if(a == Z) {
+			diag(n, "can't find count arg");
+			return;
+		}
+		if(a->op != OCONST || !typechl[a->type->etype]) {
+			diag(n, "count is invalid constant");
+			return;
+		}
+		j = a->vconst;
+		i = 0;
+		while(b != Z) {
+			b = nextarg(b, &a);
+			i++;
+		}
+		if(i != j)
+			diag(n, "found %d argument%s after count %d", i, i == 1 ? "" : "s", j);
+	}
+
+	if(l->prot != nil) {
+		// check that all arguments after param or count
+		// are listed in type list.
+		i = l->count;
+		if(i == 0)
+			i = l->param;
+		if(i == 0)
+			return;
+		a = nil;
+		b = n->right;
+		while(i > 0) {
+			b = nextarg(b, &a);
+			i--;
+		}
+		if(a == Z) {
+			diag(n, "can't find count/param arg");
+			return;
+		}
+		while(b != Z) {
+			b = nextarg(b, &a);
+			for(tl=l->prot; tl; tl=tl->link)
+				if(sametype(a->type, tl->type))
+					break;
+			if(tl == nil)
+				diag(a, "invalid type %T in call to %s", a->type, s);
+		}
+	}
+
+	if(l->param <= 0)
+		return;
 	i = l->param;
 	a = nil;
 	b = n->right;
-	a = Z;
 	while(i > 0) {
 		b = nextarg(b, &a);
 		i--;
 	}
 	if(a == Z) {
-		warn(n, "cant find format arg");
+		diag(n, "can't find format arg");
 		return;
 	}
 	if(!sametype(indchar, a->type)) {
-		warn(n, "format arg type %T", a->type);
+		diag(n, "format arg type %T", a->type);
 		return;
 	}
 	if(a->op != OADDR || a->left->op != ONAME || a->left->sym != symstring) {
diff --git a/src/cmd/cc/funct.c b/src/cmd/cc/funct.c
index 21d8625..99477b2 100644
--- a/src/cmd/cc/funct.c
+++ b/src/cmd/cc/funct.c
@@ -28,6 +28,7 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
+#include	<u.h>
 #include	"cc.h"
 
 typedef	struct	Ftab	Ftab;
diff --git a/src/cmd/cc/godefs.c b/src/cmd/cc/godefs.c
index 9503cb2..3ba979c 100644
--- a/src/cmd/cc/godefs.c
+++ b/src/cmd/cc/godefs.c
@@ -29,6 +29,7 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
+#include <u.h>
 #include "cc.h"
 
 static int upper;
@@ -238,7 +239,7 @@ printtypename(Type *t)
 			Bprint(&outbuf, "%U", n);
 		break;
 	case TFUNC:
-		Bprint(&outbuf, "func(", t);
+		Bprint(&outbuf, "func(");
 		for(t1 = t->down; t1 != T; t1 = t1->down) {
 			if(t1->etype == TVOID)
 				break;
diff --git a/src/cmd/cc/lex.c b/src/cmd/cc/lex.c
index 71cc89b..15f2d37 100644
--- a/src/cmd/cc/lex.c
+++ b/src/cmd/cc/lex.c
@@ -28,6 +28,8 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
+#include	<u.h>
+#include	<ctype.h>
 #include	"cc.h"
 #include	"y.tab.h"
 
@@ -384,7 +386,7 @@ lookup(void)
 		}else
 			*w++ = *r;
 	}
-	*w++ = '\0';
+	*w = '\0';
 
 	h = 0;
 	for(p=symb; *p;) {
@@ -1524,7 +1526,7 @@ alloc(int32 n)
 	p = malloc(n);
 	if(p == nil) {
 		print("alloc out of mem\n");
-		exit(1);
+		exits("alloc: out of mem");
 	}
 	memset(p, 0, n);
 	return p;
@@ -1538,7 +1540,7 @@ allocn(void *p, int32 n, int32 d)
 	p = realloc(p, n+d);
 	if(p == nil) {
 		print("allocn out of mem\n");
-		exit(1);
+		exits("allocn: out of mem");
 	}
 	if(d > 0)
 		memset((char*)p+n, 0, d);
diff --git a/src/cmd/cc/lexbody b/src/cmd/cc/lexbody
index 24f9bdc..f4cc19c 100644
--- a/src/cmd/cc/lexbody
+++ b/src/cmd/cc/lexbody
@@ -96,7 +96,7 @@ alloc(int32 n)
 	p = malloc(n);
 	if(p == nil) {
 		print("alloc out of mem\n");
-		exit(1);
+		exits("alloc: out of mem");
 	}
 	memset(p, 0, n);
 	return p;
@@ -110,7 +110,7 @@ allocn(void *p, int32 n, int32 d)
 	p = realloc(p, n+d);
 	if(p == nil) {
 		print("allocn out of mem\n");
-		exit(1);
+		exits("allocn: out of mem");
 	}
 	if(d > 0)
 		memset((char*)p+n, 0, d);
@@ -245,7 +245,7 @@ lookup(void)
 		}else
 			*w++ = *r;
 	}
-	*w++ = '\0';
+	*w = '\0';
 
 	h = 0;
 	for(p=symb; c = *p; p++)
diff --git a/src/cmd/cc/mac.c b/src/cmd/cc/mac.c
index c08cd9c..43ae214 100644
--- a/src/cmd/cc/mac.c
+++ b/src/cmd/cc/mac.c
@@ -28,6 +28,8 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
+#include	<u.h>
+#include	<ctype.h>
 #include	"cc.h"
 
 #include	"macbody"
diff --git a/src/cmd/cc/macbody b/src/cmd/cc/macbody
index ca8a54c..ed66361 100644
--- a/src/cmd/cc/macbody
+++ b/src/cmd/cc/macbody
@@ -830,11 +830,11 @@ linehist(char *f, int offset)
 	if(debug['f'])
 		if(f) {
 			if(offset)
-				print("%4ld: %s (#line %d)\n", lineno, f, offset);
+				print("%4d: %s (#line %d)\n", lineno, f, offset);
 			else
-				print("%4ld: %s\n", lineno, f);
+				print("%4d: %s\n", lineno, f);
 		} else
-			print("%4ld: <pop>\n", lineno);
+			print("%4d: <pop>\n", lineno);
 	newflag = 0;
 
 	h = alloc(sizeof(Hist));
diff --git a/src/cmd/cc/omachcap.c b/src/cmd/cc/omachcap.c
index ec5aa86..f8fc1d8 100644
--- a/src/cmd/cc/omachcap.c
+++ b/src/cmd/cc/omachcap.c
@@ -28,11 +28,13 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
+#include	<u.h>
 #include	"cc.h"
 
 /* default, like old cc */
 int
 machcap(Node *n)
 {
+	USED(n);
 	return 0;
 }
diff --git a/src/cmd/cc/pgen.c b/src/cmd/cc/pgen.c
index 5d17caf..0e5e8c0 100644
--- a/src/cmd/cc/pgen.c
+++ b/src/cmd/cc/pgen.c
@@ -112,7 +112,7 @@ codgen(Node *n, Node *nn)
 	warnreach = 1;
 	gen(n);
 	if(canreach && thisfn->link->etype != TVOID)
-		warn(Z, "no return at end of function: %s", n1->sym->name);
+		diag(Z, "no return at end of function: %s", n1->sym->name);
 	noretval(3);
 	gbranch(ORETURN);
 
diff --git a/src/cmd/cc/scon.c b/src/cmd/cc/scon.c
index 3047ca4..193331f 100644
--- a/src/cmd/cc/scon.c
+++ b/src/cmd/cc/scon.c
@@ -28,6 +28,7 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
+#include <u.h>
 #include "cc.h"
 
 static Node*
diff --git a/src/cmd/cc/sub.c b/src/cmd/cc/sub.c
index e0d5df7..e5992e2 100644
--- a/src/cmd/cc/sub.c
+++ b/src/cmd/cc/sub.c
@@ -28,6 +28,7 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
+#include	<u.h>
 #include	"cc.h"
 
 Node*
diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go
index 6b930f1..a4d83f1 100644
--- a/src/cmd/cgo/gcc.go
+++ b/src/cmd/cgo/gcc.go
@@ -66,7 +66,7 @@ func cname(s string) string {
 // preamble. Multiple occurrences are concatenated with a separating space,
 // even across files.
 func (p *Package) ParseFlags(f *File, srcfile string) {
-	linesIn := strings.Split(f.Preamble, "\n", -1)
+	linesIn := strings.Split(f.Preamble, "\n")
 	linesOut := make([]string, 0, len(linesIn))
 
 NextLine:
@@ -78,7 +78,7 @@ NextLine:
 		}
 
 		l = strings.TrimSpace(l[4:])
-		fields := strings.Split(l, ":", 2)
+		fields := strings.SplitN(l, ":", 2)
 		if len(fields) != 2 {
 			fatalf("%s: bad #cgo line: %s", srcfile, line)
 		}
@@ -275,7 +275,7 @@ func (p *Package) loadDefines(f *File) {
 	b.WriteString(f.Preamble)
 	stdout := p.gccDefines(b.Bytes())
 
-	for _, line := range strings.Split(stdout, "\n", -1) {
+	for _, line := range strings.Split(stdout, "\n") {
 		if len(line) < 9 || line[0:7] != "#define" {
 			continue
 		}
@@ -397,7 +397,7 @@ func (p *Package) guessKinds(f *File) []*Name {
 		isConst[i] = true // until proven otherwise
 	}
 
-	for _, line := range strings.Split(stderr, "\n", -1) {
+	for _, line := range strings.Split(stderr, "\n") {
 		if len(line) < 9 || line[0:9] != "cgo-test:" {
 			// the user will see any compiler errors when the code is compiled later.
 			continue
@@ -1188,7 +1188,7 @@ func (c *typeConv) Type(dtype dwarf.Type) *Type {
 			if ss, ok := dwarfToName[s]; ok {
 				s = ss
 			}
-			s = strings.Join(strings.Split(s, " ", -1), "") // strip spaces
+			s = strings.Join(strings.Split(s, " "), "") // strip spaces
 			name := c.Ident("_Ctype_" + s)
 			typedef[name.Name] = t.Go
 			t.Go = name
diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go
index 7eecb34..6802dd1 100644
--- a/src/cmd/cgo/out.go
+++ b/src/cmd/cgo/out.go
@@ -148,7 +148,7 @@ func dynimport(obj string) {
 			fatalf("cannot load imported symbols from PE file %s: %v", obj, err)
 		}
 		for _, s := range sym {
-			ss := strings.Split(s, ":", -1)
+			ss := strings.Split(s, ":")
 			fmt.Printf("#pragma dynimport %s %s %q\n", ss[0], ss[0], strings.ToLower(ss[1]))
 		}
 		return
diff --git a/src/cmd/ebnflint/ebnflint.go b/src/cmd/ebnflint/ebnflint.go
index cac3917..0b04431 100644
--- a/src/cmd/ebnflint/ebnflint.go
+++ b/src/cmd/ebnflint/ebnflint.go
@@ -35,6 +35,12 @@ var (
 )
 
 
+func report(err os.Error) {
+	scanner.PrintError(os.Stderr, err)
+	os.Exit(1)
+}
+
+
 func extractEBNF(src []byte) []byte {
 	var buf bytes.Buffer
 
@@ -75,34 +81,35 @@ func extractEBNF(src []byte) []byte {
 func main() {
 	flag.Parse()
 
-	var filename string
+	var (
+		filename string
+		src      []byte
+		err      os.Error
+	)
 	switch flag.NArg() {
 	case 0:
-		filename = "/dev/stdin"
+		filename = "<stdin>"
+		src, err = ioutil.ReadAll(os.Stdin)
 	case 1:
 		filename = flag.Arg(0)
+		src, err = ioutil.ReadFile(filename)
 	default:
 		usage()
 	}
-
-	src, err := ioutil.ReadFile(filename)
 	if err != nil {
-		scanner.PrintError(os.Stderr, err)
-		os.Exit(1)
+		report(err)
 	}
 
-	if filepath.Ext(filename) == ".html" {
+	if filepath.Ext(filename) == ".html" || bytes.Index(src, open) >= 0 {
 		src = extractEBNF(src)
 	}
 
 	grammar, err := ebnf.Parse(fset, filename, src)
 	if err != nil {
-		scanner.PrintError(os.Stderr, err)
-		os.Exit(1)
+		report(err)
 	}
 
 	if err = ebnf.Verify(fset, grammar, *start); err != nil {
-		scanner.PrintError(os.Stderr, err)
-		os.Exit(1)
+		report(err)
 	}
 }
diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h
index b687681..8ca086e 100644
--- a/src/cmd/gc/go.h
+++ b/src/cmd/gc/go.h
@@ -302,6 +302,7 @@ struct	Sym
 	uchar	flags;
 	uchar	sym;		// huffman encoding in object file
 	Sym*	link;
+	int32	npkg;	// number of imported packages with this name
 
 	// saved and restored by dcopy
 	Pkg*	pkg;
@@ -777,6 +778,7 @@ EXTERN	int32	nhunk;
 EXTERN	int32	thunk;
 
 EXTERN	int	exporting;
+EXTERN	int	erroring;
 EXTERN	int	noargnames;
 
 EXTERN	int	funcdepth;
diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y
index 5d28c0e..01a4e82 100644
--- a/src/cmd/gc/go.y
+++ b/src/cmd/gc/go.y
@@ -237,7 +237,11 @@ import_here:
 import_package:
 	LPACKAGE sym import_safety ';'
 	{
-		importpkg->name = $2->name;
+		if(importpkg->name == nil) {
+			importpkg->name = $2->name;
+			pkglookup($2->name, nil)->npkg++;
+		} else if(strcmp(importpkg->name, $2->name) != 0)
+			yyerror("conflicting names %s and %s for package %Z", importpkg->name, $2->name, importpkg->path);
 		importpkg->direct = 1;
 		
 		if(safemode && !curio.importsafe)
@@ -1657,7 +1661,11 @@ hidden_import:
 		Pkg *p;
 
 		p = mkpkg($3.u.sval);
-		p->name = $2->name;
+		if(p->name == nil) {
+			p->name = $2->name;
+			pkglookup($2->name, nil)->npkg++;
+		} else if(strcmp(p->name, $2->name) != 0)
+			yyerror("conflicting names %s and %s for package %Z", p->name, $2->name, p->path);
 	}
 |	LVAR hidden_pkg_importsym hidden_type ';'
 	{
diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c
index 8eb60de..40b0c4f 100644
--- a/src/cmd/gc/subr.c
+++ b/src/cmd/gc/subr.c
@@ -45,10 +45,12 @@ adderr(int line, char *fmt, va_list arg)
 	Fmt f;
 	Error *p;
 
+	erroring++;
 	fmtstrinit(&f);
 	fmtprint(&f, "%L: ", line);
 	fmtvprint(&f, fmt, arg);
 	fmtprint(&f, "\n");
+	erroring--;
 
 	if(nerr >= merr) {
 		if(merr == 0)
@@ -1122,7 +1124,14 @@ Sconv(Fmt *fp)
 		return 0;
 	}
 
-	if(s->pkg != localpkg || longsymnames || (fp->flags & FmtLong)) {
+	if(s->pkg && s->pkg != localpkg || longsymnames || (fp->flags & FmtLong)) {
+		// This one is for the user.  If the package name
+		// was used by multiple packages, give the full
+		// import path to disambiguate.
+		if(erroring && pkglookup(s->pkg->name, nil)->npkg > 1) {
+			fmtprint(fp, "\"%Z\".%s", s->pkg->path, s->name);
+			return 0;
+		}
 		fmtprint(fp, "%s.%s", s->pkg->name, s->name);
 		return 0;
 	}
diff --git a/src/cmd/godoc/codewalk.go b/src/cmd/godoc/codewalk.go
index 54bebe8..50043e2 100644
--- a/src/cmd/godoc/codewalk.go
+++ b/src/cmd/godoc/codewalk.go
@@ -74,7 +74,7 @@ func codewalk(w http.ResponseWriter, r *http.Request) {
 
 // A Codewalk represents a single codewalk read from an XML file.
 type Codewalk struct {
-	Title string "attr"
+	Title string `xml:"attr"`
 	File  []string
 	Step  []*Codestep
 }
@@ -83,9 +83,9 @@ type Codewalk struct {
 // A Codestep is a single step in a codewalk.
 type Codestep struct {
 	// Filled in from XML
-	Src   string "attr"
-	Title string "attr"
-	XML   string "innerxml"
+	Src   string `xml:"attr"`
+	Title string `xml:"attr"`
+	XML   string `xml:"innerxml"`
 
 	// Derived from Src; not in XML.
 	Err    os.Error
@@ -168,7 +168,7 @@ func loadCodewalk(filename string) (*Codewalk, os.Error) {
 		cw.File[i] = f
 		i++
 	}
-	sort.SortStrings(cw.File)
+	sort.Strings(cw.File)
 
 	return cw, nil
 }
diff --git a/src/cmd/godoc/dirtrees.go b/src/cmd/godoc/dirtrees.go
index af44fa1..e98e93a 100644
--- a/src/cmd/godoc/dirtrees.go
+++ b/src/cmd/godoc/dirtrees.go
@@ -30,7 +30,7 @@ type Directory struct {
 func isGoFile(fi FileInfo) bool {
 	name := fi.Name()
 	return fi.IsRegular() &&
-		!strings.HasPrefix(name, ".") && // ignore .files
+		len(name) > 0 && name[0] != '.' && // ignore .files
 		filepath.Ext(name) == ".go"
 }
 
@@ -43,7 +43,8 @@ func isPkgFile(fi FileInfo) bool {
 
 func isPkgDir(fi FileInfo) bool {
 	name := fi.Name()
-	return fi.IsDirectory() && len(name) > 0 && name[0] != '_'
+	return fi.IsDirectory() && len(name) > 0 &&
+		name[0] != '_' && name[0] != '.' // ignore _files and .files
 }
 
 
@@ -267,8 +268,8 @@ func (dir *Directory) lookupLocal(name string) *Directory {
 
 // lookup looks for the *Directory for a given path, relative to dir.
 func (dir *Directory) lookup(path string) *Directory {
-	d := strings.Split(dir.Path, string(filepath.Separator), -1)
-	p := strings.Split(path, string(filepath.Separator), -1)
+	d := strings.Split(dir.Path, string(filepath.Separator))
+	p := strings.Split(path, string(filepath.Separator))
 	i := 0
 	for i < len(d) {
 		if i >= len(p) || d[i] != p[i] {
diff --git a/src/cmd/godoc/godoc.go b/src/cmd/godoc/godoc.go
index 6987d91..20ebd31 100644
--- a/src/cmd/godoc/godoc.go
+++ b/src/cmd/godoc/godoc.go
@@ -9,6 +9,7 @@ import (
 	"flag"
 	"fmt"
 	"go/ast"
+	"go/build"
 	"go/doc"
 	"go/printer"
 	"go/token"
@@ -83,8 +84,16 @@ var (
 
 
 func initHandlers() {
-	fsMap.Init(*pkgPath)
-	fileServer = http.FileServer(*goroot, "")
+	paths := filepath.SplitList(*pkgPath)
+	for _, t := range build.Path {
+		if t.Goroot {
+			continue
+		}
+		paths = append(paths, t.SrcDir())
+	}
+	fsMap.Init(paths)
+
+	fileServer = http.FileServer(http.Dir(*goroot))
 	cmdHandler = httpHandler{"/cmd/", filepath.Join(*goroot, "src", "cmd"), false}
 	pkgHandler = httpHandler{"/pkg/", filepath.Join(*goroot, "src", "pkg"), true}
 }
@@ -160,7 +169,7 @@ func readDirList(filename string) ([]string, os.Error) {
 		}
 		return e == nil && isPkgDir(d)
 	}
-	list := canonicalizePaths(strings.Split(string(contents), "\n", -1), filter)
+	list := canonicalizePaths(strings.Split(string(contents), "\n"), filter)
 	// for each parent path, remove all it's children q
 	// (requirement for binary search to work when filtering)
 	i := 0
diff --git a/src/cmd/godoc/index.go b/src/cmd/godoc/index.go
index 61caee1..e0c89e7 100644
--- a/src/cmd/godoc/index.go
+++ b/src/cmd/godoc/index.go
@@ -901,7 +901,7 @@ func isIdentifier(s string) bool {
 // identifier, Lookup returns a LookupResult, and a list of alternative
 // spellings, if any. If the query syntax is wrong, an error is reported.
 func (x *Index) Lookup(query string) (match *LookupResult, alt *AltWords, err os.Error) {
-	ss := strings.Split(query, ".", -1)
+	ss := strings.Split(query, ".")
 
 	// check query syntax
 	for _, s := range ss {
@@ -954,7 +954,7 @@ func (list positionList) Swap(i, j int)      { list[i], list[j] = list[j], list[
 
 // unique returns the list sorted and with duplicate entries removed
 func unique(list []int) []int {
-	sort.SortInts(list)
+	sort.Ints(list)
 	var last int
 	i := 0
 	for _, x := range list {
diff --git a/src/cmd/godoc/main.go b/src/cmd/godoc/main.go
index 55f6031..51fcf8d 100644
--- a/src/cmd/godoc/main.go
+++ b/src/cmd/godoc/main.go
@@ -31,6 +31,7 @@ import (
 	"flag"
 	"fmt"
 	"go/ast"
+	"go/build"
 	"http"
 	_ "http/pprof" // to serve /debug/pprof/*
 	"io"
@@ -332,7 +333,10 @@ func main() {
 	}
 	relpath := path
 	abspath := path
-	if !filepath.IsAbs(path) {
+	if t, pkg, err := build.FindTree(path); err == nil {
+		relpath = pkg
+		abspath = filepath.Join(t.SrcDir(), pkg)
+	} else if !filepath.IsAbs(path) {
 		abspath = absolutePath(path, pkgHandler.fsRoot)
 	} else {
 		relpath = relativeURL(path)
diff --git a/src/cmd/godoc/mapping.go b/src/cmd/godoc/mapping.go
index 73f1881..92614e8 100644
--- a/src/cmd/godoc/mapping.go
+++ b/src/cmd/godoc/mapping.go
@@ -59,10 +59,10 @@ type mapping struct {
 }
 
 
-// Init initializes the Mapping from a list of paths separated by
-// filepath.ListSeparator. Empty paths are ignored; relative paths
-// are assumed to be relative to the current working directory and
-// converted to absolute paths. For each path of the form:
+// Init initializes the Mapping from a list of paths.
+// Empty paths are ignored; relative paths are assumed to be relative to
+// the current working directory and converted to absolute paths.
+// For each path of the form:
 //
 //	dirname/localname
 //
@@ -80,8 +80,8 @@ type mapping struct {
 //	user   -> /home/user
 //	public -> /home/build/public
 //
-func (m *Mapping) Init(paths string) {
-	pathlist := canonicalizePaths(filepath.SplitList(paths), nil)
+func (m *Mapping) Init(paths []string) {
+	pathlist := canonicalizePaths(paths, nil)
 	list := make([]mapping, len(pathlist))
 
 	// create mapping list
@@ -120,7 +120,7 @@ func (m *Mapping) PrefixList() []string {
 		}
 
 		// sort the list and remove duplicate entries
-		sort.SortStrings(list)
+		sort.Strings(list)
 		i := 0
 		prev := ""
 		for _, path := range list {
diff --git a/src/cmd/godoc/utils.go b/src/cmd/godoc/utils.go
index 660bf6d..e2637ab 100644
--- a/src/cmd/godoc/utils.go
+++ b/src/cmd/godoc/utils.go
@@ -80,7 +80,7 @@ func canonicalizePaths(list []string, filter func(path string) bool) []string {
 	list = list[0:i]
 
 	// sort the list and remove duplicate entries
-	sort.SortStrings(list)
+	sort.Strings(list)
 	i = 0
 	prev := ""
 	for _, path := range list {
diff --git a/src/cmd/gofix/Makefile b/src/cmd/gofix/Makefile
index b157649..7ce21e8 100644
--- a/src/cmd/gofix/Makefile
+++ b/src/cmd/gofix/Makefile
@@ -6,16 +6,22 @@ include ../../Make.inc
 
 TARG=gofix
 GOFILES=\
+	filepath.go\
 	fix.go\
-	netdial.go\
-	main.go\
-	oserrorstring.go\
-	osopen.go\
 	httpfinalurl.go\
+	httpfs.go\
 	httpheaders.go\
 	httpserver.go\
+	main.go\
+	netdial.go\
+	oserrorstring.go\
+	osopen.go\
 	procattr.go\
 	reflect.go\
+	signal.go\
+	sorthelpers.go\
+	sortslice.go\
+	stringssplit.go\
 	typecheck.go\
 
 include ../../Make.cmd
diff --git a/src/cmd/gofix/filepath.go b/src/cmd/gofix/filepath.go
new file mode 100644
index 0000000..1d0ad68
--- /dev/null
+++ b/src/cmd/gofix/filepath.go
@@ -0,0 +1,53 @@
+// 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 main
+
+import (
+	"go/ast"
+)
+
+func init() {
+	register(fix{
+		"filepath",
+		filepathFunc,
+		`Adapt code from filepath.[List]SeparatorString to string(filepath.[List]Separator).
+
+http://codereview.appspot.com/4527090
+`,
+	})
+}
+
+func filepathFunc(f *ast.File) (fixed bool) {
+	if !imports(f, "path/filepath") {
+		return
+	}
+
+	walk(f, func(n interface{}) {
+		e, ok := n.(*ast.Expr)
+		if !ok {
+			return
+		}
+
+		var ident string
+		switch {
+		case isPkgDot(*e, "filepath", "SeparatorString"):
+			ident = "filepath.Separator"
+		case isPkgDot(*e, "filepath", "ListSeparatorString"):
+			ident = "filepath.ListSeparator"
+		default:
+			return
+		}
+
+		// string(filepath.[List]Separator)
+		*e = &ast.CallExpr{
+			Fun:  ast.NewIdent("string"),
+			Args: []ast.Expr{ast.NewIdent(ident)},
+		}
+
+		fixed = true
+	})
+
+	return
+}
diff --git a/src/cmd/gofix/filepath_test.go b/src/cmd/gofix/filepath_test.go
new file mode 100644
index 0000000..d170c3a
--- /dev/null
+++ b/src/cmd/gofix/filepath_test.go
@@ -0,0 +1,33 @@
+// 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 main
+
+func init() {
+	addTestCases(filepathTests)
+}
+
+var filepathTests = []testCase{
+	{
+		Name: "filepath.0",
+		In: `package main
+
+import (
+	"path/filepath"
+)
+
+var _ = filepath.SeparatorString
+var _ = filepath.ListSeparatorString
+`,
+		Out: `package main
+
+import (
+	"path/filepath"
+)
+
+var _ = string(filepath.Separator)
+var _ = string(filepath.ListSeparator)
+`,
+	},
+}
diff --git a/src/cmd/gofix/fix.go b/src/cmd/gofix/fix.go
index 0852ce2..c1c5a74 100644
--- a/src/cmd/gofix/fix.go
+++ b/src/cmd/gofix/fix.go
@@ -10,6 +10,7 @@ import (
 	"go/token"
 	"os"
 	"strconv"
+	"strings"
 )
 
 type fix struct {
@@ -258,13 +259,28 @@ func walkBeforeAfter(x interface{}, before, after func(interface{})) {
 
 // imports returns true if f imports path.
 func imports(f *ast.File, path string) bool {
+	return importSpec(f, path) != nil
+}
+
+// importSpec returns the import spec if f imports path,
+// or nil otherwise.
+func importSpec(f *ast.File, path string) *ast.ImportSpec {
 	for _, s := range f.Imports {
-		t, err := strconv.Unquote(s.Path.Value)
-		if err == nil && t == path {
-			return true
+		if importPath(s) == path {
+			return s
 		}
 	}
-	return false
+	return nil
+}
+
+// importPath returns the unquoted import path of s,
+// or "" if the path is not properly quoted.
+func importPath(s *ast.ImportSpec) string {
+	t, err := strconv.Unquote(s.Path.Value)
+	if err == nil {
+		return t
+	}
+	return ""
 }
 
 // isPkgDot returns true if t is the expression "pkg.name"
@@ -420,3 +436,138 @@ func newPkgDot(pos token.Pos, pkg, name string) ast.Expr {
 		},
 	}
 }
+
+// addImport adds the import path to the file f, if absent.
+func addImport(f *ast.File, path string) {
+	if imports(f, path) {
+		return
+	}
+
+	newImport := &ast.ImportSpec{
+		Path: &ast.BasicLit{
+			Kind:  token.STRING,
+			Value: strconv.Quote(path),
+		},
+	}
+
+	var impdecl *ast.GenDecl
+
+	// Find an import decl to add to.
+	for _, decl := range f.Decls {
+		gen, ok := decl.(*ast.GenDecl)
+
+		if ok && gen.Tok == token.IMPORT {
+			impdecl = gen
+			break
+		}
+	}
+
+	// No import decl found.  Add one.
+	if impdecl == nil {
+		impdecl = &ast.GenDecl{
+			Tok: token.IMPORT,
+		}
+		f.Decls = append(f.Decls, nil)
+		copy(f.Decls[1:], f.Decls)
+		f.Decls[0] = impdecl
+	}
+
+	// Ensure the import decl has parentheses, if needed.
+	if len(impdecl.Specs) > 0 && !impdecl.Lparen.IsValid() {
+		impdecl.Lparen = impdecl.Pos()
+	}
+
+	// Assume the import paths are alphabetically ordered.
+	// If they are not, the result is ugly, but legal.
+	insertAt := len(impdecl.Specs) // default to end of specs
+	for i, spec := range impdecl.Specs {
+		impspec := spec.(*ast.ImportSpec)
+		if importPath(impspec) > path {
+			insertAt = i
+			break
+		}
+	}
+
+	impdecl.Specs = append(impdecl.Specs, nil)
+	copy(impdecl.Specs[insertAt+1:], impdecl.Specs[insertAt:])
+	impdecl.Specs[insertAt] = newImport
+
+	f.Imports = append(f.Imports, newImport)
+}
+
+// deleteImport deletes the import path from the file f, if present.
+func deleteImport(f *ast.File, path string) {
+	oldImport := importSpec(f, path)
+
+	// Find the import node that imports path, if any.
+	for i, decl := range f.Decls {
+		gen, ok := decl.(*ast.GenDecl)
+		if !ok || gen.Tok != token.IMPORT {
+			continue
+		}
+		for j, spec := range gen.Specs {
+			impspec := spec.(*ast.ImportSpec)
+
+			if oldImport != impspec {
+				continue
+			}
+
+			// We found an import spec that imports path.
+			// Delete it.
+			copy(gen.Specs[j:], gen.Specs[j+1:])
+			gen.Specs = gen.Specs[:len(gen.Specs)-1]
+
+			// If this was the last import spec in this decl,
+			// delete the decl, too.
+			if len(gen.Specs) == 0 {
+				copy(f.Decls[i:], f.Decls[i+1:])
+				f.Decls = f.Decls[:len(f.Decls)-1]
+			} else if len(gen.Specs) == 1 {
+				gen.Lparen = token.NoPos // drop parens
+			}
+
+			break
+		}
+	}
+
+	// Delete it from f.Imports.
+	for i, imp := range f.Imports {
+		if imp == oldImport {
+			copy(f.Imports[i:], f.Imports[i+1:])
+			f.Imports = f.Imports[:len(f.Imports)-1]
+			break
+		}
+	}
+}
+
+func usesImport(f *ast.File, path string) (used bool) {
+	spec := importSpec(f, path)
+	if spec == nil {
+		return
+	}
+
+	name := spec.Name.String()
+	switch name {
+	case "<nil>":
+		// If the package name is not explicitly specified,
+		// make an educated guess. This is not guaranteed to be correct.
+		lastSlash := strings.LastIndex(path, "/")
+		if lastSlash == -1 {
+			name = path
+		} else {
+			name = path[lastSlash+1:]
+		}
+	case "_", ".":
+		// Not sure if this import is used - err on the side of caution.
+		return true
+	}
+
+	walk(f, func(n interface{}) {
+		sel, ok := n.(*ast.SelectorExpr)
+		if ok && isTopName(sel.X, name) {
+			used = true
+		}
+	})
+
+	return
+}
diff --git a/src/cmd/gofix/httpfs.go b/src/cmd/gofix/httpfs.go
new file mode 100644
index 0000000..7f27656
--- /dev/null
+++ b/src/cmd/gofix/httpfs.go
@@ -0,0 +1,63 @@
+// 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 main
+
+import (
+	"go/ast"
+	"go/token"
+)
+
+var httpFileSystemFix = fix{
+	"httpfs",
+	httpfs,
+	`Adapt http FileServer to take a FileSystem.
+
+http://codereview.appspot.com/4629047  http FileSystem interface
+`,
+}
+
+func init() {
+	register(httpFileSystemFix)
+}
+
+func httpfs(f *ast.File) bool {
+	if !imports(f, "http") {
+		return false
+	}
+
+	fixed := false
+	walk(f, func(n interface{}) {
+		call, ok := n.(*ast.CallExpr)
+		if !ok || !isPkgDot(call.Fun, "http", "FileServer") {
+			return
+		}
+		if len(call.Args) != 2 {
+			return
+		}
+		dir, prefix := call.Args[0], call.Args[1]
+		call.Args = []ast.Expr{&ast.CallExpr{
+			Fun:  &ast.SelectorExpr{ast.NewIdent("http"), ast.NewIdent("Dir")},
+			Args: []ast.Expr{dir},
+		}}
+		wrapInStripHandler := true
+		if prefixLit, ok := prefix.(*ast.BasicLit); ok {
+			if prefixLit.Kind == token.STRING && (prefixLit.Value == `"/"` || prefixLit.Value == `""`) {
+				wrapInStripHandler = false
+			}
+		}
+		if wrapInStripHandler {
+			call.Fun.(*ast.SelectorExpr).Sel = ast.NewIdent("StripPrefix")
+			call.Args = []ast.Expr{
+				prefix,
+				&ast.CallExpr{
+					Fun:  &ast.SelectorExpr{ast.NewIdent("http"), ast.NewIdent("FileServer")},
+					Args: call.Args,
+				},
+			}
+		}
+		fixed = true
+	})
+	return fixed
+}
diff --git a/src/cmd/gofix/httpfs_test.go b/src/cmd/gofix/httpfs_test.go
new file mode 100644
index 0000000..d1804e9
--- /dev/null
+++ b/src/cmd/gofix/httpfs_test.go
@@ -0,0 +1,47 @@
+// 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 main
+
+func init() {
+	addTestCases(httpFileSystemTests)
+}
+
+var httpFileSystemTests = []testCase{
+	{
+		Name: "httpfs.0",
+		In: `package httpfs
+
+import (
+	"http"
+)
+
+func f() {
+	_ = http.FileServer("/var/www/foo", "/")
+	_ = http.FileServer("/var/www/foo", "")
+	_ = http.FileServer("/var/www/foo/bar", "/bar")
+	s := "/foo"
+	_ = http.FileServer(s, "/")
+	prefix := "/p"
+	_ = http.FileServer(s, prefix)
+}
+`,
+		Out: `package httpfs
+
+import (
+	"http"
+)
+
+func f() {
+	_ = http.FileServer(http.Dir("/var/www/foo"))
+	_ = http.FileServer(http.Dir("/var/www/foo"))
+	_ = http.StripPrefix("/bar", http.FileServer(http.Dir("/var/www/foo/bar")))
+	s := "/foo"
+	_ = http.FileServer(http.Dir(s))
+	prefix := "/p"
+	_ = http.StripPrefix(prefix, http.FileServer(http.Dir(s)))
+}
+`,
+	},
+}
diff --git a/src/cmd/gofix/main.go b/src/cmd/gofix/main.go
index 05495bc..e7e7013 100644
--- a/src/cmd/gofix/main.go
+++ b/src/cmd/gofix/main.go
@@ -53,7 +53,7 @@ func main() {
 
 	if *allowedRewrites != "" {
 		allowed = make(map[string]bool)
-		for _, f := range strings.Split(*allowedRewrites, ",", -1) {
+		for _, f := range strings.Split(*allowedRewrites, ",") {
 			allowed[f] = true
 		}
 	}
diff --git a/src/cmd/gofix/signal.go b/src/cmd/gofix/signal.go
new file mode 100644
index 0000000..53c3388
--- /dev/null
+++ b/src/cmd/gofix/signal.go
@@ -0,0 +1,49 @@
+// 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 main
+
+import (
+	"go/ast"
+	"strings"
+)
+
+func init() {
+	register(fix{
+		"signal",
+		signal,
+		`Adapt code to types moved from os/signal to signal.
+
+http://codereview.appspot.com/4437091
+`,
+	})
+}
+
+func signal(f *ast.File) (fixed bool) {
+	if !imports(f, "os/signal") {
+		return
+	}
+
+	walk(f, func(n interface{}) {
+		s, ok := n.(*ast.SelectorExpr)
+
+		if !ok || !isTopName(s.X, "signal") {
+			return
+		}
+
+		sel := s.Sel.String()
+		if sel == "Signal" || sel == "UnixSignal" || strings.HasPrefix(sel, "SIG") {
+			s.X = &ast.Ident{Name: "os"}
+			fixed = true
+		}
+	})
+
+	if fixed {
+		addImport(f, "os")
+		if !usesImport(f, "os/signal") {
+			deleteImport(f, "os/signal")
+		}
+	}
+	return
+}
diff --git a/src/cmd/gofix/signal_test.go b/src/cmd/gofix/signal_test.go
new file mode 100644
index 0000000..2500e9c
--- /dev/null
+++ b/src/cmd/gofix/signal_test.go
@@ -0,0 +1,96 @@
+// 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 main
+
+func init() {
+	addTestCases(signalTests)
+}
+
+var signalTests = []testCase{
+	{
+		Name: "signal.0",
+		In: `package main
+
+import (
+	_ "a"
+	"os/signal"
+	_ "z"
+)
+
+type T1 signal.UnixSignal
+type T2 signal.Signal
+
+func f() {
+	_ = signal.SIGHUP
+	_ = signal.Incoming
+}
+`,
+		Out: `package main
+
+import (
+	_ "a"
+	"os"
+	"os/signal"
+	_ "z"
+)
+
+type T1 os.UnixSignal
+type T2 os.Signal
+
+func f() {
+	_ = os.SIGHUP
+	_ = signal.Incoming
+}
+`,
+	},
+	{
+		Name: "signal.1",
+		In: `package main
+
+import (
+	"os"
+	"os/signal"
+)
+
+func f() {
+	var _ os.Error
+	_ = signal.SIGHUP
+}
+`,
+		Out: `package main
+
+import "os"
+
+
+func f() {
+	var _ os.Error
+	_ = os.SIGHUP
+}
+`,
+	},
+	{
+		Name: "signal.2",
+		In: `package main
+
+import "os"
+import "os/signal"
+
+func f() {
+	var _ os.Error
+	_ = signal.SIGHUP
+}
+`,
+		Out: `package main
+
+import "os"
+
+
+func f() {
+	var _ os.Error
+	_ = os.SIGHUP
+}
+`,
+	},
+}
diff --git a/src/cmd/gofix/sorthelpers.go b/src/cmd/gofix/sorthelpers.go
new file mode 100644
index 0000000..4d0bee6
--- /dev/null
+++ b/src/cmd/gofix/sorthelpers.go
@@ -0,0 +1,47 @@
+// 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 main
+
+import (
+	"go/ast"
+)
+
+func init() {
+	register(fix{
+		"sorthelpers",
+		sorthelpers,
+		`Adapt code from sort.Sort[Ints|Float64s|Strings] to sort.[Ints|Float64s|Strings].
+`,
+	})
+}
+
+
+func sorthelpers(f *ast.File) (fixed bool) {
+	if !imports(f, "sort") {
+		return
+	}
+
+	walk(f, func(n interface{}) {
+		s, ok := n.(*ast.SelectorExpr)
+		if !ok || !isTopName(s.X, "sort") {
+			return
+		}
+
+		switch s.Sel.String() {
+		case "SortFloat64s":
+			s.Sel.Name = "Float64s"
+		case "SortInts":
+			s.Sel.Name = "Ints"
+		case "SortStrings":
+			s.Sel.Name = "Strings"
+		default:
+			return
+		}
+
+		fixed = true
+	})
+
+	return
+}
diff --git a/src/cmd/gofix/sorthelpers_test.go b/src/cmd/gofix/sorthelpers_test.go
new file mode 100644
index 0000000..6c37858
--- /dev/null
+++ b/src/cmd/gofix/sorthelpers_test.go
@@ -0,0 +1,45 @@
+// 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 main
+
+func init() {
+	addTestCases(sorthelpersTests)
+}
+
+var sorthelpersTests = []testCase{
+	{
+		Name: "sortslice.0",
+		In: `package main
+
+import (
+	"sort"
+)
+
+func main() {
+	var s []string
+	sort.SortStrings(s)
+	var i []ints
+	sort.SortInts(i)
+	var f []float64
+	sort.SortFloat64s(f)
+}
+`,
+		Out: `package main
+
+import (
+	"sort"
+)
+
+func main() {
+	var s []string
+	sort.Strings(s)
+	var i []ints
+	sort.Ints(i)
+	var f []float64
+	sort.Float64s(f)
+}
+`,
+	},
+}
diff --git a/src/cmd/gofix/sortslice.go b/src/cmd/gofix/sortslice.go
new file mode 100644
index 0000000..b9c108b
--- /dev/null
+++ b/src/cmd/gofix/sortslice.go
@@ -0,0 +1,50 @@
+// 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 main
+
+import (
+	"go/ast"
+)
+
+func init() {
+	register(fix{
+		"sortslice",
+		sortslice,
+		`Adapt code from sort.[Float64|Int|String]Array to  sort.[Float64|Int|String]Slice.
+		
+http://codereview.appspot.com/4602054
+http://codereview.appspot.com/4639041
+`,
+	})
+}
+
+
+func sortslice(f *ast.File) (fixed bool) {
+	if !imports(f, "sort") {
+		return
+	}
+
+	walk(f, func(n interface{}) {
+		s, ok := n.(*ast.SelectorExpr)
+		if !ok || !isTopName(s.X, "sort") {
+			return
+		}
+
+		switch s.Sel.String() {
+		case "Float64Array":
+			s.Sel.Name = "Float64Slice"
+		case "IntArray":
+			s.Sel.Name = "IntSlice"
+		case "StringArray":
+			s.Sel.Name = "StringSlice"
+		default:
+			return
+		}
+
+		fixed = true
+	})
+
+	return
+}
diff --git a/src/cmd/gofix/sortslice_test.go b/src/cmd/gofix/sortslice_test.go
new file mode 100644
index 0000000..404feb2
--- /dev/null
+++ b/src/cmd/gofix/sortslice_test.go
@@ -0,0 +1,35 @@
+// 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 main
+
+func init() {
+	addTestCases(sortsliceTests)
+}
+
+var sortsliceTests = []testCase{
+	{
+		Name: "sortslice.0",
+		In: `package main
+
+import (
+	"sort"
+)
+
+var _ = sort.Float64Array
+var _ = sort.IntArray
+var _ = sort.StringArray
+`,
+		Out: `package main
+
+import (
+	"sort"
+)
+
+var _ = sort.Float64Slice
+var _ = sort.IntSlice
+var _ = sort.StringSlice
+`,
+	},
+}
diff --git a/src/cmd/gofix/stringssplit.go b/src/cmd/gofix/stringssplit.go
new file mode 100644
index 0000000..4a1fe93
--- /dev/null
+++ b/src/cmd/gofix/stringssplit.go
@@ -0,0 +1,71 @@
+// 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 main
+
+import (
+	"go/ast"
+	"go/token"
+)
+
+var stringssplitFix = fix{
+	"stringssplit",
+	stringssplit,
+	`Restore strings.Split to its original meaning and add strings.SplitN. Bytes too.
+
+http://codereview.appspot.com/4661051
+`,
+}
+
+func init() {
+	register(stringssplitFix)
+}
+
+func stringssplit(f *ast.File) bool {
+	if !imports(f, "bytes") && !imports(f, "strings") {
+		return false
+	}
+
+	fixed := false
+	walk(f, func(n interface{}) {
+		call, ok := n.(*ast.CallExpr)
+		// func Split(s, sep string, n int) []string
+		// func SplitAfter(s, sep string, n int) []string
+		if !ok || len(call.Args) != 3 {
+			return
+		}
+		// Is this our function?
+		switch {
+		case isPkgDot(call.Fun, "bytes", "Split"):
+		case isPkgDot(call.Fun, "bytes", "SplitAfter"):
+		case isPkgDot(call.Fun, "strings", "Split"):
+		case isPkgDot(call.Fun, "strings", "SplitAfter"):
+		default:
+			return
+		}
+
+		sel := call.Fun.(*ast.SelectorExpr)
+		args := call.Args
+		fixed = true // We're committed.
+
+		// Is the last argument -1? If so, drop the arg.
+		// (Actually we just look for a negative integer literal.)
+		// Otherwise, Split->SplitN and keep the arg.
+		final := args[2]
+		if unary, ok := final.(*ast.UnaryExpr); ok && unary.Op == token.SUB {
+			if lit, ok := unary.X.(*ast.BasicLit); ok {
+				// Is it an integer? If so, it's a negative integer and that's what we're after.
+				if lit.Kind == token.INT {
+					// drop the last arg.
+					call.Args = args[0:2]
+					return
+				}
+			}
+		}
+
+		// If not, rename and keep the argument list.
+		sel.Sel.Name += "N"
+	})
+	return fixed
+}
diff --git a/src/cmd/gofix/stringssplit_test.go b/src/cmd/gofix/stringssplit_test.go
new file mode 100644
index 0000000..b925722
--- /dev/null
+++ b/src/cmd/gofix/stringssplit_test.go
@@ -0,0 +1,51 @@
+// 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 main
+
+func init() {
+	addTestCases(stringssplitTests)
+}
+
+var stringssplitTests = []testCase{
+	{
+		Name: "stringssplit.0",
+		In: `package main
+
+import (
+	"bytes"
+	"strings"
+)
+
+func f() {
+	bytes.Split(a, b, c)
+	bytes.Split(a, b, -1)
+	bytes.SplitAfter(a, b, c)
+	bytes.SplitAfter(a, b, -1)
+	strings.Split(a, b, c)
+	strings.Split(a, b, -1)
+	strings.SplitAfter(a, b, c)
+	strings.SplitAfter(a, b, -1)
+}
+`,
+		Out: `package main
+
+import (
+	"bytes"
+	"strings"
+)
+
+func f() {
+	bytes.SplitN(a, b, c)
+	bytes.Split(a, b)
+	bytes.SplitAfterN(a, b, c)
+	bytes.SplitAfter(a, b)
+	strings.SplitN(a, b, c)
+	strings.Split(a, b)
+	strings.SplitAfterN(a, b, c)
+	strings.SplitAfter(a, b)
+}
+`,
+	},
+}
diff --git a/src/cmd/gofix/testdata/reflect.template.go.in b/src/cmd/gofix/testdata/reflect.template.go.in
index ba06de4..1f5a812 100644
--- a/src/cmd/gofix/testdata/reflect.template.go.in
+++ b/src/cmd/gofix/testdata/reflect.template.go.in
@@ -444,7 +444,7 @@ func (t *Template) newVariable(words []string) *variableElement {
 	bar := strings.IndexRune(lastWord, '|')
 	if bar >= 0 {
 		words[len(words)-1] = lastWord[0:bar]
-		formatters = strings.Split(lastWord[bar+1:], "|", -1)
+		formatters = strings.Split(lastWord[bar+1:], "|")
 	}
 
 	// We could remember the function address here and avoid the lookup later,
@@ -705,7 +705,7 @@ func (t *Template) findVar(st *state, s string) reflect.Value {
 	if s == "@" {
 		return indirectPtr(data, numStars)
 	}
-	for _, elem := range strings.Split(s, ".", -1) {
+	for _, elem := range strings.Split(s, ".") {
 		// Look up field; data must be a struct or map.
 		data = t.lookup(st, data, elem)
 		if data == nil {
diff --git a/src/cmd/gofix/testdata/reflect.template.go.out b/src/cmd/gofix/testdata/reflect.template.go.out
index c362884..f2f56ef 100644
--- a/src/cmd/gofix/testdata/reflect.template.go.out
+++ b/src/cmd/gofix/testdata/reflect.template.go.out
@@ -444,7 +444,7 @@ func (t *Template) newVariable(words []string) *variableElement {
 	bar := strings.IndexRune(lastWord, '|')
 	if bar >= 0 {
 		words[len(words)-1] = lastWord[0:bar]
-		formatters = strings.Split(lastWord[bar+1:], "|", -1)
+		formatters = strings.Split(lastWord[bar+1:], "|")
 	}
 
 	// We could remember the function address here and avoid the lookup later,
@@ -705,7 +705,7 @@ func (t *Template) findVar(st *state, s string) reflect.Value {
 	if s == "@" {
 		return indirectPtr(data, numStars)
 	}
-	for _, elem := range strings.Split(s, ".", -1) {
+	for _, elem := range strings.Split(s, ".") {
 		// Look up field; data must be a struct or map.
 		data = t.lookup(st, data, elem)
 		if !data.IsValid() {
diff --git a/src/cmd/gofmt/gofmt_test.go b/src/cmd/gofmt/gofmt_test.go
index a725303..7070055 100644
--- a/src/cmd/gofmt/gofmt_test.go
+++ b/src/cmd/gofmt/gofmt_test.go
@@ -20,8 +20,8 @@ func runTest(t *testing.T, dirname, in, out, flags string) {
 	// process flags
 	*simplifyAST = false
 	*rewriteRule = ""
-	for _, flag := range strings.Split(flags, " ", -1) {
-		elts := strings.Split(flag, "=", 2)
+	for _, flag := range strings.Split(flags, " ") {
+		elts := strings.SplitN(flag, "=", 2)
 		name := elts[0]
 		value := ""
 		if len(elts) == 2 {
diff --git a/src/cmd/gofmt/rewrite.go b/src/cmd/gofmt/rewrite.go
index 4c24282..f7f1fe8 100644
--- a/src/cmd/gofmt/rewrite.go
+++ b/src/cmd/gofmt/rewrite.go
@@ -22,7 +22,7 @@ func initRewrite() {
 		rewrite = nil // disable any previous rewrite
 		return
 	}
-	f := strings.Split(*rewriteRule, "->", -1)
+	f := strings.Split(*rewriteRule, "->")
 	if len(f) != 2 {
 		fmt.Fprintf(os.Stderr, "rewrite rule must be of the form 'pattern -> replacement'\n")
 		os.Exit(2)
diff --git a/src/cmd/goinstall/doc.go b/src/cmd/goinstall/doc.go
index 52b09d3..a5df7b3 100644
--- a/src/cmd/goinstall/doc.go
+++ b/src/cmd/goinstall/doc.go
@@ -5,7 +5,8 @@
 /*
 Goinstall is an experiment in automatic package installation.
 It installs packages, possibly downloading them from the internet.
-It maintains a list of public Go packages at http://godashboard.appspot.com/package.
+It maintains a list of public Go packages at
+http://godashboard.appspot.com/package.
 
 Usage:
 	goinstall [flags] importpath...
@@ -41,9 +42,22 @@ Another common idiom is to use
 to update, recompile, and reinstall all goinstalled packages.
 
 The source code for a package with import path foo/bar is expected
-to be in the directory $GOROOT/src/pkg/foo/bar/.  If the import
-path refers to a code hosting site, goinstall will download the code
-if necessary.  The recognized code hosting sites are:
+to be in the directory $GOROOT/src/pkg/foo/bar/ or $GOPATH/src/foo/bar/.
+See "The GOPATH Environment Variable" for more about GOPATH.
+
+By default, goinstall prints output only when it encounters an error.
+The -v flag causes goinstall to print information about packages
+being considered and installed.
+
+Goinstall ignores Makefiles.
+
+
+Remote Repositories
+
+If a package import path refers to a remote repository, goinstall will
+download the code if necessary.
+
+Goinstall recognizes packages from a few common code hosting sites:
 
 	BitBucket (Mercurial)
 
@@ -72,7 +86,6 @@ if necessary.  The recognized code hosting sites are:
 		import "launchpad.net/~user/project/branch"
 		import "launchpad.net/~user/project/branch/sub/directory"
 
-
 If the destination directory (e.g., $GOROOT/src/pkg/bitbucket.org/user/project)
 already exists and contains an appropriate checkout, goinstall will not
 attempt to fetch updates.  The -u flag changes this behavior,
@@ -84,19 +97,42 @@ named "release".  If there is one, it uses that version of the code.
 Otherwise it uses the default version selected by the version control
 system, typically HEAD for git, tip for Mercurial.
 
-After a successful download and installation of a publicly accessible
-remote package, goinstall reports the installation to godashboard.appspot.com,
-which increments a count associated with the package and the time
-of its most recent installation. This mechanism powers the package list
-at http://godashboard.appspot.com/package, allowing Go programmers
-to learn about popular packages that might be worth looking at.
+After a successful download and installation of one of these import paths,
+goinstall reports the installation to godashboard.appspot.com, which
+increments a count associated with the package and the time of its most
+recent installation. This mechanism powers the package list at
+http://godashboard.appspot.com/package, allowing Go programmers to learn about
+popular packages that might be worth looking at.	 
 The -dashboard=false flag disables this reporting.
 
-By default, goinstall prints output only when it encounters an error.
-The -v flag causes goinstall to print information about packages
-being considered and installed.
+For code hosted on other servers, goinstall recognizes the general form
+
+	repository.vcs/path
+
+as denoting the given repository, with or without the .vcs suffix, using
+the named version control system, and then the path inside that repository.
+The supported version control systems are:
+
+	Bazaar      .bzr
+	Git         .git
+	Mercurial   .hg
+	Subversion  .svn
+
+For example, 
+
+	import "example.org/user/foo.hg"
+
+denotes the root directory of the Mercurial repository at example.org/user/foo
+or foo.hg, and
+
+	import "example.org/repo.git/foo/bar"
+
+denotes the foo/bar directory of the Git repository at example.com/repo or
+repo.git.
 
-Goinstall does not use make. Makefiles are ignored by goinstall.
+When a version control system supports multiple protocols, goinstall tries each
+in turn.
+For example, for Git it tries git://, then https://, then http://.
 
 
 The GOPATH Environment Variable
diff --git a/src/cmd/goinstall/download.go b/src/cmd/goinstall/download.go
index d209fa8..da892a6 100644
--- a/src/cmd/goinstall/download.go
+++ b/src/cmd/goinstall/download.go
@@ -7,6 +7,8 @@
 package main
 
 import (
+	"exec"
+	"fmt"
 	"http"
 	"os"
 	"path/filepath"
@@ -31,11 +33,6 @@ func maybeReportToDashboard(path string) {
 	}
 }
 
-type host struct {
-	pattern  *regexp.Regexp
-	protocol string
-}
-
 // a vcs represents a version control system
 // like Mercurial, Git, or Subversion.
 type vcs struct {
@@ -57,9 +54,10 @@ type vcs struct {
 	defaultHosts      []host
 }
 
-type vcsMatch struct {
-	*vcs
-	prefix, repo string
+type host struct {
+	pattern  *regexp.Regexp
+	protocol string
+	suffix   string
 }
 
 var hg = vcs{
@@ -75,10 +73,11 @@ var hg = vcs{
 	logLimitFlag:      "-l1",
 	logReleaseFlag:    "-rrelease",
 	check:             "identify",
-	protocols:         []string{"http"},
+	protocols:         []string{"https", "http"},
+	suffix:            ".hg",
 	defaultHosts: []host{
-		{regexp.MustCompile(`^([a-z0-9\-]+\.googlecode\.com/hg)(/[a-z0-9A-Z_.\-/]*)?$`), "https"},
-		{regexp.MustCompile(`^(bitbucket\.org/[a-z0-9A-Z_.\-]+/[a-z0-9A-Z_.\-]+)(/[a-z0-9A-Z_.\-/]*)?$`), "http"},
+		{regexp.MustCompile(`^([a-z0-9\-]+\.googlecode\.com/hg)(/[a-z0-9A-Z_.\-/]*)?$`), "https", ""},
+		{regexp.MustCompile(`^(bitbucket\.org/[a-z0-9A-Z_.\-]+/[a-z0-9A-Z_.\-]+)(/[a-z0-9A-Z_.\-/]*)?$`), "http", ""},
 	},
 }
 
@@ -94,11 +93,11 @@ var git = vcs{
 	log:               "show-ref",
 	logLimitFlag:      "",
 	logReleaseFlag:    "release",
-	check:             "peek-remote",
-	protocols:         []string{"git", "http"},
+	check:             "ls-remote",
+	protocols:         []string{"git", "https", "http"},
 	suffix:            ".git",
 	defaultHosts: []host{
-		{regexp.MustCompile(`^(github\.com/[a-z0-9A-Z_.\-]+/[a-z0-9A-Z_.\-]+)(/[a-z0-9A-Z_.\-/]*)?$`), "http"},
+		{regexp.MustCompile(`^(github\.com/[a-z0-9A-Z_.\-]+/[a-z0-9A-Z_.\-]+)(/[a-z0-9A-Z_.\-/]*)?$`), "http", ".git"},
 	},
 }
 
@@ -114,9 +113,10 @@ var svn = vcs{
 	logLimitFlag:      "-l1",
 	logReleaseFlag:    "release",
 	check:             "info",
-	protocols:         []string{"http", "svn"},
+	protocols:         []string{"https", "http", "svn"},
+	suffix:            ".svn",
 	defaultHosts: []host{
-		{regexp.MustCompile(`^([a-z0-9\-]+\.googlecode\.com/svn)(/[a-z0-9A-Z_.\-/]*)?$`), "https"},
+		{regexp.MustCompile(`^([a-z0-9\-]+\.googlecode\.com/svn)(/[a-z0-9A-Z_.\-/]*)?$`), "https", ""},
 	},
 }
 
@@ -134,23 +134,79 @@ var bzr = vcs{
 	logLimitFlag:      "-l1",
 	logReleaseFlag:    "-rrelease",
 	check:             "info",
-	protocols:         []string{"http", "bzr"},
+	protocols:         []string{"https", "http", "bzr"},
+	suffix:            ".bzr",
 	defaultHosts: []host{
-		{regexp.MustCompile(`^(launchpad\.net/([a-z0-9A-Z_.\-]+(/[a-z0-9A-Z_.\-]+)?|~[a-z0-9A-Z_.\-]+/(\+junk|[a-z0-9A-Z_.\-]+)/[a-z0-9A-Z_.\-]+))(/[a-z0-9A-Z_.\-/]+)?$`), "https"},
+		{regexp.MustCompile(`^(launchpad\.net/([a-z0-9A-Z_.\-]+(/[a-z0-9A-Z_.\-]+)?|~[a-z0-9A-Z_.\-]+/(\+junk|[a-z0-9A-Z_.\-]+)/[a-z0-9A-Z_.\-]+))(/[a-z0-9A-Z_.\-/]+)?$`), "https", ""},
 	},
 }
 
 var vcsList = []*vcs{&git, &hg, &bzr, &svn}
 
+type vcsMatch struct {
+	*vcs
+	prefix, repo string
+}
+
+// findHostedRepo checks whether pkg is located at one of
+// the supported code hosting sites and, if so, returns a match.
+func findHostedRepo(pkg string) (*vcsMatch, os.Error) {
+	for _, v := range vcsList {
+		for _, host := range v.defaultHosts {
+			if hm := host.pattern.FindStringSubmatch(pkg); hm != nil {
+				if host.suffix != "" && strings.HasSuffix(hm[1], host.suffix) {
+					return nil, os.NewError("repository " + pkg + " should not have " + v.suffix + " suffix")
+				}
+				repo := host.protocol + "://" + hm[1] + host.suffix
+				return &vcsMatch{v, hm[1], repo}, nil
+			}
+		}
+	}
+	return nil, nil
+}
+
+// findAnyRepo looks for a vcs suffix in pkg (.git, etc) and returns a match.
+func findAnyRepo(pkg string) (*vcsMatch, os.Error) {
+	for _, v := range vcsList {
+		i := strings.Index(pkg+"/", v.suffix+"/")
+		if i < 0 {
+			continue
+		}
+		if !strings.Contains(pkg[:i], "/") {
+			continue // don't match vcs suffix in the host name
+		}
+		if m := v.find(pkg[:i]); m != nil {
+			return m, nil
+		}
+		return nil, fmt.Errorf("couldn't find %s repository", v.name)
+	}
+	return nil, nil
+}
+
+func (v *vcs) find(pkg string) *vcsMatch {
+	for _, proto := range v.protocols {
+		for _, suffix := range []string{"", v.suffix} {
+			repo := proto + "://" + pkg + suffix
+			out, err := exec.Command(v.cmd, v.check, repo).CombinedOutput()
+			if err == nil {
+				printf("find %s: found %s\n", pkg, repo)
+				return &vcsMatch{v, pkg + v.suffix, repo}
+			}
+			printf("find %s: %s %s %s: %v\n%s\n", pkg, v.cmd, v.check, repo, err, out)
+		}
+	}
+	return nil
+}
+
 // isRemote returns true if the first part of the package name looks like a
 // hostname - i.e. contains at least one '.' and the last part is at least 2
 // characters.
 func isRemote(pkg string) bool {
-	parts := strings.Split(pkg, "/", 2)
+	parts := strings.SplitN(pkg, "/", 2)
 	if len(parts) != 2 {
 		return false
 	}
-	parts = strings.Split(parts[0], ".", -1)
+	parts = strings.Split(parts[0], ".")
 	if len(parts) < 2 || len(parts[len(parts)-1]) < 2 {
 		return false
 	}
@@ -158,26 +214,35 @@ func isRemote(pkg string) bool {
 }
 
 // download checks out or updates pkg from the remote server.
-func download(pkg, srcDir string) os.Error {
+func download(pkg, srcDir string) (dashReport bool, err os.Error) {
 	if strings.Contains(pkg, "..") {
-		return os.NewError("invalid path (contains ..)")
+		err = os.NewError("invalid path (contains ..)")
+		return
 	}
-	var m *vcsMatch
-	for _, v := range vcsList {
-		for _, host := range v.defaultHosts {
-			if hm := host.pattern.FindStringSubmatch(pkg); hm != nil {
-				if v.suffix != "" && strings.HasSuffix(hm[1], v.suffix) {
-					return os.NewError("repository " + pkg + " should not have " + v.suffix + " suffix")
-				}
-				repo := host.protocol + "://" + hm[1] + v.suffix
-				m = &vcsMatch{v, hm[1], repo}
-			}
+	m, err := findHostedRepo(pkg)
+	if err != nil {
+		return
+	}
+	if m != nil {
+		dashReport = true // only report public code hosting sites
+	} else {
+		m, err = findAnyRepo(pkg)
+		if err != nil {
+			return
 		}
 	}
 	if m == nil {
-		return os.NewError("cannot download: " + pkg)
+		err = os.NewError("cannot download: " + pkg)
+		return
+	}
+	installed, err := m.checkoutRepo(srcDir, m.prefix, m.repo)
+	if err != nil {
+		return
+	}
+	if !installed {
+		dashReport = false
 	}
-	return vcsCheckout(m.vcs, srcDir, m.prefix, m.repo, pkg)
+	return
 }
 
 // Try to detect if a "release" tag exists.  If it does, update
@@ -196,47 +261,46 @@ func (v *vcs) updateRepo(dst string) os.Error {
 	return nil
 }
 
-// vcsCheckout checks out repo into dst using vcs.
+// checkoutRepo checks out repo into dst using vcs.
 // It tries to check out (or update, if the dst already
 // exists and -u was specified on the command line)
 // the repository at tag/branch "release".  If there is no
 // such tag or branch, it falls back to the repository tip.
-func vcsCheckout(vcs *vcs, srcDir, pkgprefix, repo, dashpath string) os.Error {
+func (vcs *vcs) checkoutRepo(srcDir, pkgprefix, repo string) (installed bool, err os.Error) {
 	dst := filepath.Join(srcDir, filepath.FromSlash(pkgprefix))
 	dir, err := os.Stat(filepath.Join(dst, vcs.metadir))
 	if err == nil && !dir.IsDirectory() {
-		return os.NewError("not a directory: " + dst)
+		err = os.NewError("not a directory: " + dst)
+		return
 	}
 	if err != nil {
 		parent, _ := filepath.Split(dst)
-		if err := os.MkdirAll(parent, 0777); err != nil {
-			return err
+		if err = os.MkdirAll(parent, 0777); err != nil {
+			return
 		}
-		if err := run(string(filepath.Separator), nil, vcs.cmd, vcs.clone, repo, dst); err != nil {
-			return err
+		if err = run(string(filepath.Separator), nil, vcs.cmd, vcs.clone, repo, dst); err != nil {
+			return
 		}
-		if err := vcs.updateRepo(dst); err != nil {
-			return err
+		if err = vcs.updateRepo(dst); err != nil {
+			return
 		}
-		// success on first installation - report
-		maybeReportToDashboard(dashpath)
+		installed = true
 	} else if *update {
 		// Retrieve new revisions from the remote branch, if the VCS
 		// supports this operation independently (e.g. svn doesn't)
 		if vcs.pull != "" {
 			if vcs.pullForceFlag != "" {
-				if err := run(dst, nil, vcs.cmd, vcs.pull, vcs.pullForceFlag); err != nil {
-					return err
+				if err = run(dst, nil, vcs.cmd, vcs.pull, vcs.pullForceFlag); err != nil {
+					return
 				}
-			} else if err := run(dst, nil, vcs.cmd, vcs.pull); err != nil {
-				return err
+			} else if err = run(dst, nil, vcs.cmd, vcs.pull); err != nil {
+				return
 			}
 		}
-
 		// Update to release or latest revision
-		if err := vcs.updateRepo(dst); err != nil {
-			return err
+		if err = vcs.updateRepo(dst); err != nil {
+			return
 		}
 	}
-	return nil
+	return
 }
diff --git a/src/cmd/goinstall/main.go b/src/cmd/goinstall/main.go
index bdf8469..5cdf0f1 100644
--- a/src/cmd/goinstall/main.go
+++ b/src/cmd/goinstall/main.go
@@ -182,9 +182,10 @@ func install(pkg, parent string) {
 	}
 	// Download remote packages if not found or forced with -u flag.
 	remote := isRemote(pkg)
+	dashReport := false
 	if remote && (err == build.ErrNotFound || (err == nil && *update)) {
 		printf("%s: download\n", pkg)
-		err = download(pkg, tree.SrcDir())
+		dashReport, err = download(pkg, tree.SrcDir())
 	}
 	if err != nil {
 		errorf("%s: %v\n", pkg, err)
@@ -243,6 +244,9 @@ func install(pkg, parent string) {
 			}
 		}
 	}
+	if dashReport {
+		maybeReportToDashboard(pkg)
+	}
 	if remote {
 		// mark package as installed in $GOROOT/goinstall.log
 		logPackage(pkg)
diff --git a/src/cmd/gotest/doc.go b/src/cmd/gotest/doc.go
index 9dba390..5be06f8 100644
--- a/src/cmd/gotest/doc.go
+++ b/src/cmd/gotest/doc.go
@@ -53,7 +53,9 @@ The resulting test binary, called (for amd64) 6.out, has several flags.
 Usage:
 	6.out [-test.v] [-test.run pattern] [-test.bench pattern] \
 		[-test.cpuprofile=cpu.out] \
-		[-test.memprofile=mem.out] [-test.memprofilerate=1]
+		[-test.memprofile=mem.out] [-test.memprofilerate=1] \
+		[-test.timeout=10] [-test.short] \
+		[-test.benchtime=3] [-test.cpu=1,2,3,4]
 
 The -test.v flag causes the tests to be logged as they run.  The
 -test.run flag causes only those tests whose names match the regular
@@ -93,6 +95,13 @@ The -test.timeout flag sets a timeout for the test in seconds.  If the
 test runs for longer than that, it will panic, dumping a stack trace
 of all existing goroutines.
 
+The -test.benchtime flag specifies the number of seconds to run each benchmark.
+The default is one second.
+
+The -test.cpu flag specifies a list of GOMAXPROCS values for which
+the tests or benchmarks are executed.  The default is the current
+value of GOMAXPROCS.
+
 For convenience, each of these -test.X flags of the test binary is
 also available as the flag -X in gotest itself.  Flags not listed here
 are unaffected.  For instance, the command
diff --git a/src/cmd/gotest/flag.go b/src/cmd/gotest/flag.go
index 780c78b..c3a28f9 100644
--- a/src/cmd/gotest/flag.go
+++ b/src/cmd/gotest/flag.go
@@ -23,6 +23,8 @@ var usageMessage = `Usage of %s:
 
   // These flags can be passed with or without a "test." prefix: -v or -test.v.
   -bench="": passes -test.bench to test
+  -benchtime=1: passes -test.benchtime to test
+  -cpu="": passes -test.cpu to test
   -cpuprofile="": passes -test.cpuprofile to test
   -memprofile="": passes -test.memprofile to test
   -memprofilerate=0: passes -test.memprofilerate to test
@@ -56,6 +58,8 @@ var flagDefn = []*flagSpec{
 
 	// passed to 6.out, adding a "test." prefix to the name if necessary: -v becomes -test.v.
 	&flagSpec{name: "bench", passToTest: true},
+	&flagSpec{name: "benchtime", passToTest: true},
+	&flagSpec{name: "cpu", passToTest: true},
 	&flagSpec{name: "cpuprofile", passToTest: true},
 	&flagSpec{name: "memprofile", passToTest: true},
 	&flagSpec{name: "memprofilerate", passToTest: true},
diff --git a/src/cmd/govet/Makefile b/src/cmd/govet/Makefile
index 291b271..f565b78 100644
--- a/src/cmd/govet/Makefile
+++ b/src/cmd/govet/Makefile
@@ -9,3 +9,6 @@ GOFILES=\
 	govet.go\
 
 include ../../Make.cmd
+
+test testshort: $(TARG)
+	../../../test/errchk $(TARG) -printfuncs='Warn:1,Warnf:1' govet.go
diff --git a/src/cmd/govet/govet.go b/src/cmd/govet/govet.go
index b811c61..5b24d2f 100644
--- a/src/cmd/govet/govet.go
+++ b/src/cmd/govet/govet.go
@@ -15,6 +15,7 @@ import (
 	"go/token"
 	"os"
 	"path/filepath"
+	"reflect"
 	"strconv"
 	"strings"
 	"utf8"
@@ -50,7 +51,7 @@ func main() {
 	flag.Parse()
 
 	if *printfuncs != "" {
-		for _, name := range strings.Split(*printfuncs, ",", -1) {
+		for _, name := range strings.Split(*printfuncs, ",") {
 			if len(name) == 0 {
 				flag.Usage()
 			}
@@ -59,7 +60,7 @@ func main() {
 				var err os.Error
 				skip, err = strconv.Atoi(name[colon+1:])
 				if err != nil {
-					error(`illegal format for "Func:N" argument %q; %s`, name, err)
+					errorf(`illegal format for "Func:N" argument %q; %s`, name, err)
 				}
 				name = name[:colon]
 			}
@@ -93,7 +94,7 @@ func doFile(name string, reader io.Reader) {
 	fs := token.NewFileSet()
 	parsedFile, err := parser.ParseFile(fs, name, reader, 0)
 	if err != nil {
-		error("%s: %s", name, err)
+		errorf("%s: %s", name, err)
 		return
 	}
 	file := &File{fs.File(parsedFile.Pos())}
@@ -121,7 +122,7 @@ func walkDir(root string) {
 	done := make(chan bool)
 	go func() {
 		for e := range errors {
-			error("walk error: %s", e)
+			errorf("walk error: %s", e)
 		}
 		done <- true
 	}()
@@ -132,7 +133,7 @@ func walkDir(root string) {
 
 // error formats the error to standard error, adding program
 // identification and a newline
-func error(format string, args ...interface{}) {
+func errorf(format string, args ...interface{}) {
 	fmt.Fprintf(os.Stderr, "govet: "+format+"\n", args...)
 	setExit(2)
 }
@@ -185,15 +186,35 @@ func (f *File) checkFile(name string, file *ast.File) {
 
 // Visit implements the ast.Visitor interface.
 func (f *File) Visit(node ast.Node) ast.Visitor {
-	// TODO: could return nil for nodes that cannot contain a CallExpr -
-	// will shortcut traversal.  Worthwhile?
 	switch n := node.(type) {
 	case *ast.CallExpr:
 		f.checkCallExpr(n)
+	case *ast.Field:
+		f.checkFieldTag(n)
 	}
 	return f
 }
 
+// checkField checks a struct field tag.
+func (f *File) checkFieldTag(field *ast.Field) {
+	if field.Tag == nil {
+		return
+	}
+
+	tag, err := strconv.Unquote(field.Tag.Value)
+	if err != nil {
+		f.Warnf(field.Pos(), "unable to read struct tag %s", field.Tag.Value)
+		return
+	}
+
+	// Check tag for validity by appending
+	// new key:value to end and checking that
+	// the tag parsing code can find it.
+	if reflect.StructTag(tag+` _gofix:"_magic"`).Get("_gofix") != "_magic" {
+		f.Warnf(field.Pos(), "struct field tag %s not compatible with reflect.StructTag.Get", field.Tag.Value)
+		return
+	}
+}
 
 // checkCallExpr checks a call expression.
 func (f *File) checkCallExpr(call *ast.CallExpr) {
@@ -358,19 +379,24 @@ func (f *File) checkPrint(call *ast.CallExpr, name string, skip int) {
 }
 
 // This function never executes, but it serves as a simple test for the program.
-// Test with govet -printfuncs="Bad:1,Badf:1,Warn:1,Warnf:1" govet.go
+// Test with make test.
 func BadFunctionUsedInTests() {
-	fmt.Println()                      // niladic call
-	fmt.Println("%s", "hi")            // % in call to Println
-	fmt.Printf("%s", "hi", 3)          // wrong # percents
-	fmt.Printf("%s%%%d", "hi", 3)      // right # percents
-	fmt.Printf("%.*d", 3, 3)           // right # percents, with a *
-	fmt.Printf("%.*d", 3, 3, 3)        // wrong # percents, with a *
-	printf("now is the time", "buddy") // no %s
-	Printf("now is the time", "buddy") // no %s
+	fmt.Println()                      // not an error
+	fmt.Println("%s", "hi")            // ERROR "possible formatting directive in Println call"
+	fmt.Printf("%s", "hi", 3)          // ERROR "wrong number of args in Printf call"
+	fmt.Printf("%s%%%d", "hi", 3)      // correct
+	fmt.Printf("%.*d", 3, 3)           // correct
+	fmt.Printf("%.*d", 3, 3, 3)        // ERROR "wrong number of args in Printf call"
+	printf("now is the time", "buddy") // ERROR "no formatting directive"
+	Printf("now is the time", "buddy") // ERROR "no formatting directive"
+	Printf("hi")                       // ok
 	f := new(File)
-	f.Warn(0, "%s", "hello", 3)  // % in call to added function
-	f.Warnf(0, "%s", "hello", 3) // wrong # %s in call to added function
+	f.Warn(0, "%s", "hello", 3)  // ERROR "possible formatting directive in Warn call"
+	f.Warnf(0, "%s", "hello", 3) // ERROR "wrong number of args in Warnf call"
+}
+
+type BadTypeUsedInTests struct {
+	X int "hello" // ERROR "struct field tag"
 }
 
 // printf is used by the test.
diff --git a/src/cmd/goyacc/goyacc.go b/src/cmd/goyacc/goyacc.go
index 220c994..543f8b1 100644
--- a/src/cmd/goyacc/goyacc.go
+++ b/src/cmd/goyacc/goyacc.go
@@ -2834,7 +2834,7 @@ func others() {
 	// copy yaccpar
 	fmt.Fprintf(ftable, "\n//line yaccpar:1\n")
 
-	parts := strings.Split(yaccpar, prefix+"run()", 2)
+	parts := strings.SplitN(yaccpar, prefix+"run()", 2)
 	fmt.Fprintf(ftable, "%v", parts[0])
 	ftable.Write(fcode.Bytes())
 	fmt.Fprintf(ftable, "%v", parts[1])
diff --git a/src/cmd/hgpatch/main.go b/src/cmd/hgpatch/main.go
index 1f3e5e7..4f7aec2 100644
--- a/src/cmd/hgpatch/main.go
+++ b/src/cmd/hgpatch/main.go
@@ -176,7 +176,7 @@ func main() {
 		list[i] = f
 		i++
 	}
-	sort.SortStrings(list)
+	sort.Strings(list)
 	for _, f := range list {
 		fmt.Printf("%s\n", f)
 	}
@@ -282,7 +282,7 @@ func hgModified() ([]string, os.Error) {
 	if err != nil {
 		return nil, err
 	}
-	return strings.Split(strings.TrimSpace(out), "\n", -1), nil
+	return strings.Split(strings.TrimSpace(out), "\n"), nil
 }
 
 // hgAdd adds name to the repository.
diff --git a/src/cmd/ld/data.c b/src/cmd/ld/data.c
index bdad58f..f1132fc 100644
--- a/src/cmd/ld/data.c
+++ b/src/cmd/ld/data.c
@@ -789,14 +789,34 @@ dodata(void)
 	sect->vaddr = 0;
 	datsize = 0;
 	s = datap;
-	for(; s != nil && s->type < SDATA; s = s->next) {
+	for(; s != nil && s->type < SSYMTAB; s = s->next) {
 		s->type = SRODATA;
 		t = rnd(s->size, PtrSize);
 		s->value = datsize;
 		datsize += t;
 	}
 	sect->len = datsize - sect->vaddr;
-	
+
+	/* gosymtab */
+	sect = addsection(&segtext, ".gosymtab", 04);
+	sect->vaddr = datsize;
+	for(; s != nil && s->type < SPCLNTAB; s = s->next) {
+		s->type = SRODATA;
+		s->value = datsize;
+		datsize += s->size;
+	}
+	sect->len = datsize - sect->vaddr;
+
+	/* gopclntab */
+	sect = addsection(&segtext, ".gopclntab", 04);
+	sect->vaddr = datsize;
+	for(; s != nil && s->type < SDATA; s = s->next) {
+		s->type = SRODATA;
+		s->value = datsize;
+		datsize += s->size;
+	}
+	sect->len = datsize - sect->vaddr;
+
 	/* data */
 	datsize = 0;
 	sect = addsection(&segdata, ".data", 06);
@@ -890,7 +910,7 @@ textaddress(void)
 void
 address(void)
 {
-	Section *s, *text, *data, *rodata;
+	Section *s, *text, *data, *rodata, *symtab, *pclntab;
 	Sym *sym, *sub;
 	uvlong va;
 
@@ -921,7 +941,9 @@ address(void)
 	segdata.filelen = segdata.sect->len;	// assume .data is first
 	
 	text = segtext.sect;
-	rodata = segtext.sect->next;
+	rodata = text->next;
+	symtab = rodata->next;
+	pclntab = symtab->next;
 	data = segdata.sect;
 
 	for(sym = datap; sym != nil; sym = sym->next) {
@@ -938,12 +960,11 @@ address(void)
 	xdefine("etext", STEXT, text->vaddr + text->len);
 	xdefine("rodata", SRODATA, rodata->vaddr);
 	xdefine("erodata", SRODATA, rodata->vaddr + rodata->len);
+	xdefine("symtab", SRODATA, symtab->vaddr);
+	xdefine("esymtab", SRODATA, symtab->vaddr + symtab->len);
+	xdefine("pclntab", SRODATA, pclntab->vaddr);
+	xdefine("epclntab", SRODATA, pclntab->vaddr + pclntab->len);
 	xdefine("data", SBSS, data->vaddr);
 	xdefine("edata", SBSS, data->vaddr + data->len);
 	xdefine("end", SBSS, segdata.vaddr + segdata.len);
-
-	sym = lookup("pclntab", 0);
-	xdefine("epclntab", SRODATA, sym->value + sym->size);
-	sym = lookup("symtab", 0);
-	xdefine("esymtab", SRODATA, sym->value + sym->size);
 }
diff --git a/src/cmd/ld/lib.c b/src/cmd/ld/lib.c
index 04ee790..77a62f5 100644
--- a/src/cmd/ld/lib.c
+++ b/src/cmd/ld/lib.c
@@ -956,7 +956,7 @@ pclntab(void)
 	uchar *bp;
 	
 	sym = lookup("pclntab", 0);
-	sym->type = SRODATA;
+	sym->type = SPCLNTAB;
 	sym->reachable = 1;
 	if(debug['s'])
 		return;
diff --git a/src/cmd/ld/lib.h b/src/cmd/ld/lib.h
index 4637131..3479871 100644
--- a/src/cmd/ld/lib.h
+++ b/src/cmd/ld/lib.h
@@ -40,6 +40,8 @@ enum
 	SSTRING,
 	SGOSTRING,
 	SRODATA,
+	SSYMTAB,
+	SPCLNTAB,
 	SDATA,
 	SMACHO,	/* Mach-O __nl_symbol_ptr */
 	SMACHOGOT,
diff --git a/src/cmd/ld/symtab.c b/src/cmd/ld/symtab.c
index c66eca1..60e146b 100644
--- a/src/cmd/ld/symtab.c
+++ b/src/cmd/ld/symtab.c
@@ -351,7 +351,7 @@ symtab(void)
 	s->reachable = 1;
 
 	symt = lookup("symtab", 0);
-	symt->type = SRODATA;
+	symt->type = SSYMTAB;
 	symt->size = 0;
 	symt->reachable = 1;
 	
@@ -372,5 +372,7 @@ symtab(void)
 		}
 	}
 
+	if(debug['s'])
+		return;
 	genasmsym(putsymb);
 }
diff --git a/src/env.bash b/src/env.bash
index 19402f3..f83012a 100644
--- a/src/env.bash
+++ b/src/env.bash
@@ -55,7 +55,6 @@ PROGS="
 	cp
 	cut
 	echo
-	ed
 	egrep
 	gcc
 	grep
@@ -74,7 +73,7 @@ PROGS="
 	uniq
 "
 
-for i in bison ed awk gcc $MAKE; do
+for i in $PROGS; do
 	if ! which $i >/dev/null 2>&1; then
 		echo "Cannot find '$i' on search path." 1>&2
 		echo "See http://golang.org/doc/install.html#ctools" 1>&2
diff --git a/src/lib9/Makefile b/src/lib9/Makefile
index d222e2f..28c97c9 100644
--- a/src/lib9/Makefile
+++ b/src/lib9/Makefile
@@ -116,5 +116,6 @@ GOROOT_FINAL?=$(GOROOT)
 	$(HOST_CC) -c $(HOST_CFLAGS) $<
 
 goos.$O: goos.c
-	$(HOST_CC) -c $(HOST_CFLAGS) -DGOOS='"$(GOOS)"' -DGOARCH='"$(GOARCH)"' -DGOROOT='"$(GOROOT_FINAL)"' -DGOVERSION='"'"$$(../version.bash)"'"' $<
+	GOVERSION=`../version.bash` && \
+		$(HOST_CC) -c $(HOST_CFLAGS) -DGOOS='"$(GOOS)"' -DGOARCH='"$(GOARCH)"' -DGOROOT='"$(GOROOT_FINAL)"' -DGOVERSION='"'"$$GOVERSION"'"' $<
 
diff --git a/src/libmach/darwin.c b/src/libmach/darwin.c
index c443a4f..63abde3 100644
--- a/src/libmach/darwin.c
+++ b/src/libmach/darwin.c
@@ -222,12 +222,21 @@ addpid(int pid, int force)
 		// The excthread reads that port and signals
 		// us if we are waiting on that thread.
 		pthread_t p;
+		int err;
 
 		excport = mach_reply_port();
 		pthread_mutex_init(&mu, nil);
 		pthread_cond_init(&cond, nil);
-		pthread_create(&p, nil, excthread, nil);
-		pthread_create(&p, nil, waitthread, (void*)(uintptr)pid);
+		err = pthread_create(&p, nil, excthread, nil);
+		if (err != 0) {
+			fprint(2, "pthread_create failed: %s\n", strerror(err));
+			abort();
+		}
+		err = pthread_create(&p, nil, waitthread, (void*)(uintptr)pid);
+		if (err != 0) {
+			fprint(2, "pthread_create failed: %s\n", strerror(err));
+			abort();
+		}
 		first = 0;
 	}
 
diff --git a/src/pkg/Makefile b/src/pkg/Makefile
index f18dc1f..7338399 100644
--- a/src/pkg/Makefile
+++ b/src/pkg/Makefile
@@ -62,6 +62,7 @@ DIRS=\
 	crypto/x509\
 	crypto/x509/pkix\
 	crypto/xtea\
+	csv\
 	debug/dwarf\
 	debug/macho\
 	debug/elf\
@@ -82,6 +83,7 @@ DIRS=\
 	exp/gui\
 	exp/gui/x11\
 	exp/regexp/syntax\
+	exp/template\
 	expvar\
 	flag\
 	fmt\
@@ -240,7 +242,6 @@ NOTEST+=\
 	../cmd/godoc\
 	../cmd/goinstall\
 	../cmd/gotest\
-	../cmd/govet\
 	../cmd/goyacc\
 	../cmd/hgpatch\
 
diff --git a/src/pkg/asn1/asn1.go b/src/pkg/asn1/asn1.go
index 2650ef2..6557729 100644
--- a/src/pkg/asn1/asn1.go
+++ b/src/pkg/asn1/asn1.go
@@ -149,7 +149,7 @@ func (b BitString) RightAlign() []byte {
 	return a
 }
 
-// parseBitString parses an ASN.1 bit string from the given byte array and returns it.
+// parseBitString parses an ASN.1 bit string from the given byte slice and returns it.
 func parseBitString(bytes []byte) (ret BitString, err os.Error) {
 	if len(bytes) == 0 {
 		err = SyntaxError{"zero length BIT STRING"}
@@ -227,7 +227,7 @@ type Enumerated int
 type Flag bool
 
 // parseBase128Int parses a base-128 encoded int from the given offset in the
-// given byte array. It returns the value and the new offset.
+// given byte slice. It returns the value and the new offset.
 func parseBase128Int(bytes []byte, initOffset int) (ret, offset int, err os.Error) {
 	offset = initOffset
 	for shifted := 0; offset < len(bytes); shifted++ {
@@ -259,7 +259,7 @@ func parseUTCTime(bytes []byte) (ret *time.Time, err os.Error) {
 	return
 }
 
-// parseGeneralizedTime parses the GeneralizedTime from the given byte array
+// parseGeneralizedTime parses the GeneralizedTime from the given byte slice
 // and returns the resulting time.
 func parseGeneralizedTime(bytes []byte) (ret *time.Time, err os.Error) {
 	return time.Parse("20060102150405Z0700", string(bytes))
@@ -300,7 +300,7 @@ func isPrintable(b byte) bool {
 // IA5String
 
 // parseIA5String parses a ASN.1 IA5String (ASCII string) from the given
-// byte array and returns it.
+// byte slice and returns it.
 func parseIA5String(bytes []byte) (ret string, err os.Error) {
 	for _, b := range bytes {
 		if b >= 0x80 {
@@ -315,11 +315,19 @@ func parseIA5String(bytes []byte) (ret string, err os.Error) {
 // T61String
 
 // parseT61String parses a ASN.1 T61String (8-bit clean string) from the given
-// byte array and returns it.
+// byte slice and returns it.
 func parseT61String(bytes []byte) (ret string, err os.Error) {
 	return string(bytes), nil
 }
 
+// UTF8String
+
+// parseUTF8String parses a ASN.1 UTF8String (raw UTF-8) from the given byte
+// array and returns it.
+func parseUTF8String(bytes []byte) (ret string, err os.Error) {
+	return string(bytes), nil
+}
+
 // A RawValue represents an undecoded ASN.1 object.
 type RawValue struct {
 	Class, Tag int
@@ -336,7 +344,7 @@ type RawContent []byte
 // Tagging
 
 // parseTagAndLength parses an ASN.1 tag and length pair from the given offset
-// into a byte array. It returns the parsed data and the new offset. SET and
+// into a byte slice. It returns the parsed data and the new offset. SET and
 // SET OF (tag 17) are mapped to SEQUENCE and SEQUENCE OF (tag 16) since we
 // don't distinguish between ordered and unordered objects in this code.
 func parseTagAndLength(bytes []byte, initOffset int) (ret tagAndLength, offset int, err os.Error) {
@@ -393,7 +401,7 @@ func parseTagAndLength(bytes []byte, initOffset int) (ret tagAndLength, offset i
 }
 
 // parseSequenceOf is used for SEQUENCE OF and SET OF values. It tries to parse
-// a number of ASN.1 values from the given byte array and returns them as a
+// a number of ASN.1 values from the given byte slice and returns them as a
 // slice of Go values of the given type.
 func parseSequenceOf(bytes []byte, sliceType reflect.Type, elemType reflect.Type) (ret reflect.Value, err os.Error) {
 	expectedTag, compoundType, ok := getUniversalType(elemType)
@@ -456,7 +464,7 @@ func invalidLength(offset, length, sliceLength int) bool {
 	return offset+length < offset || offset+length > sliceLength
 }
 
-// parseField is the main parsing function. Given a byte array and an offset
+// parseField is the main parsing function. Given a byte slice and an offset
 // into the array, it will try to parse a suitable ASN.1 value out and store it
 // in the given Value.
 func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParameters) (offset int, err os.Error) {
@@ -573,16 +581,15 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
 		}
 	}
 
-	// Special case for strings: PrintableString and IA5String both map to
-	// the Go type string. getUniversalType returns the tag for
-	// PrintableString when it sees a string so, if we see an IA5String on
-	// the wire, we change the universal type to match.
-	if universalTag == tagPrintableString && t.tag == tagIA5String {
-		universalTag = tagIA5String
-	}
-	// Likewise for GeneralString
-	if universalTag == tagPrintableString && t.tag == tagGeneralString {
-		universalTag = tagGeneralString
+	// Special case for strings: all the ASN.1 string types map to the Go
+	// type string. getUniversalType returns the tag for PrintableString
+	// when it sees a string, so if we see a different string type on the
+	// wire, we change the universal type to match.
+	if universalTag == tagPrintableString {
+		switch t.tag {
+		case tagIA5String, tagGeneralString, tagT61String, tagUTF8String:
+			universalTag = t.tag
+		}
 	}
 
 	// Special case for time: UTCTime and GeneralizedTime both map to the
@@ -707,7 +714,7 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
 			if i == 0 && field.Type == rawContentsType {
 				continue
 			}
-			innerOffset, err = parseField(val.Field(i), innerBytes, innerOffset, parseFieldParameters(field.Tag))
+			innerOffset, err = parseField(val.Field(i), innerBytes, innerOffset, parseFieldParameters(field.Tag.Get("asn1")))
 			if err != nil {
 				return
 			}
@@ -738,6 +745,8 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
 			v, err = parseIA5String(innerBytes)
 		case tagT61String:
 			v, err = parseT61String(innerBytes)
+		case tagUTF8String:
+			v, err = parseUTF8String(innerBytes)
 		case tagGeneralString:
 			// GeneralString is specified in ISO-2022/ECMA-35,
 			// A brief review suggests that it includes structures
diff --git a/src/pkg/asn1/asn1_test.go b/src/pkg/asn1/asn1_test.go
index 463dbe0..3c94786 100644
--- a/src/pkg/asn1/asn1_test.go
+++ b/src/pkg/asn1/asn1_test.go
@@ -299,11 +299,11 @@ type TestObjectIdentifierStruct struct {
 }
 
 type TestContextSpecificTags struct {
-	A int "tag:1"
+	A int `asn1:"tag:1"`
 }
 
 type TestContextSpecificTags2 struct {
-	A int "explicit,tag:1"
+	A int `asn1:"explicit,tag:1"`
 	B int
 }
 
@@ -353,7 +353,7 @@ type Certificate struct {
 }
 
 type TBSCertificate struct {
-	Version            int "optional,explicit,default:0,tag:0"
+	Version            int `asn1:"optional,explicit,default:0,tag:0"`
 	SerialNumber       RawValue
 	SignatureAlgorithm AlgorithmIdentifier
 	Issuer             RDNSequence
diff --git a/src/pkg/asn1/common.go b/src/pkg/asn1/common.go
index 9db887e..01f4f7b 100644
--- a/src/pkg/asn1/common.go
+++ b/src/pkg/asn1/common.go
@@ -25,6 +25,7 @@ const (
 	tagOctetString     = 4
 	tagOID             = 6
 	tagEnum            = 10
+	tagUTF8String      = 12
 	tagSequence        = 16
 	tagSet             = 17
 	tagPrintableString = 19
@@ -83,7 +84,7 @@ type fieldParameters struct {
 // parseFieldParameters will parse it into a fieldParameters structure,
 // ignoring unknown parts of the string.
 func parseFieldParameters(str string) (ret fieldParameters) {
-	for _, part := range strings.Split(str, ",", -1) {
+	for _, part := range strings.Split(str, ",") {
 		switch {
 		case part == "optional":
 			ret.optional = true
diff --git a/src/pkg/asn1/marshal.go b/src/pkg/asn1/marshal.go
index 7212c91..d7eb63b 100644
--- a/src/pkg/asn1/marshal.go
+++ b/src/pkg/asn1/marshal.go
@@ -413,7 +413,7 @@ func marshalBody(out *forkableWriter, value reflect.Value, params fieldParameter
 		for i := startingField; i < t.NumField(); i++ {
 			var pre *forkableWriter
 			pre, out = out.fork()
-			err = marshalField(pre, v.Field(i), parseFieldParameters(t.Field(i).Tag))
+			err = marshalField(pre, v.Field(i), parseFieldParameters(t.Field(i).Tag.Get("asn1")))
 			if err != nil {
 				return
 			}
diff --git a/src/pkg/asn1/marshal_test.go b/src/pkg/asn1/marshal_test.go
index a951763..03df5f1 100644
--- a/src/pkg/asn1/marshal_test.go
+++ b/src/pkg/asn1/marshal_test.go
@@ -30,23 +30,23 @@ type rawContentsStruct struct {
 }
 
 type implicitTagTest struct {
-	A int "implicit,tag:5"
+	A int `asn1:"implicit,tag:5"`
 }
 
 type explicitTagTest struct {
-	A int "explicit,tag:5"
+	A int `asn1:"explicit,tag:5"`
 }
 
 type ia5StringTest struct {
-	A string "ia5"
+	A string `asn1:"ia5"`
 }
 
 type printableStringTest struct {
-	A string "printable"
+	A string `asn1:"printable"`
 }
 
 type optionalRawValueTest struct {
-	A RawValue "optional"
+	A RawValue `asn1:"optional"`
 }
 
 type testSET []int
diff --git a/src/pkg/big/int.go b/src/pkg/big/int.go
index 4d47a82..0948919 100755
--- a/src/pkg/big/int.go
+++ b/src/pkg/big/int.go
@@ -368,11 +368,60 @@ func (x *Int) Format(s fmt.State, ch int) {
 			format = "0X%s"
 		}
 	}
-	if x.neg {
-		format = "-" + format
+	t := fmt.Sprintf(format, x.abs.string(cs))
+
+	// insert spaces in hexadecimal formats if needed
+	if len(t) > 0 && s.Flag(' ') && (ch == 'x' || ch == 'X') {
+		spaces := (len(t)+1)/2 - 1
+		spaced := make([]byte, len(t)+spaces)
+		var i, j int
+		spaced[i] = t[j]
+		i++
+		j++
+		if len(t)&1 == 0 {
+			spaced[i] = t[j]
+			i++
+			j++
+		}
+		for j < len(t) {
+			spaced[i] = ' '
+			i++
+			spaced[i] = t[j]
+			i++
+			j++
+			spaced[i] = t[j]
+			i++
+			j++
+		}
+		t = string(spaced)
+	}
+
+	// determine sign prefix
+	prefix := ""
+	switch {
+	case x.neg:
+		prefix = "-"
+	case s.Flag('+'):
+		prefix = "+"
+	case s.Flag(' ') && ch != 'x' && ch != 'X':
+		prefix = " "
+	}
+
+	// fill to minimum width and prepend sign prefix
+	if width, ok := s.Width(); ok && len(t)+len(prefix) < width {
+		if s.Flag('0') {
+			t = fmt.Sprintf("%s%0*d%s", prefix, width-len(t)-len(prefix), 0, t)
+		} else {
+			if s.Flag('-') {
+				width = -width
+			}
+			t = fmt.Sprintf("%*s", width, prefix+t)
+		}
+	} else if prefix != "" {
+		t = prefix + t
 	}
 
-	fmt.Fprintf(s, format, x.abs.string(cs))
+	fmt.Fprint(s, t)
 }
 
 
@@ -417,6 +466,7 @@ func (z *Int) scan(r io.RuneScanner, base int) (*Int, int, os.Error) {
 // the scanned number. It accepts the formats 'b' (binary), 'o' (octal),
 // 'd' (decimal), 'x' (lowercase hexadecimal), and 'X' (uppercase hexadecimal).
 func (z *Int) Scan(s fmt.ScanState, ch int) os.Error {
+	s.SkipSpace() // skip leading space characters
 	base := 0
 	switch ch {
 	case 'b':
@@ -585,7 +635,7 @@ func ProbablyPrime(z *Int, n int) bool {
 }
 
 
-// Rand sets z to a pseudo-random number in [0, n) and returns z. 
+// Rand sets z to a pseudo-random number in [0, n) and returns z.
 func (z *Int) Rand(rnd *rand.Rand, n *Int) *Int {
 	z.neg = false
 	if n.neg == true || len(n.abs) == 0 {
diff --git a/src/pkg/big/int_test.go b/src/pkg/big/int_test.go
index 58a5503..7f33c95 100755
--- a/src/pkg/big/int_test.go
+++ b/src/pkg/big/int_test.go
@@ -376,6 +376,35 @@ var formatTests = []struct {
 	{"-10", "%#X", "-0XA"},
 	{"10", "%#y", "%!y(big.Int=10)"},
 	{"-10", "%#y", "%!y(big.Int=-10)"},
+
+	{"1234", "%d", "1234"},
+	{"1234", "%3d", "1234"},
+	{"1234", "%4d", "1234"},
+	{"-1234", "%d", "-1234"},
+	{"1234", "% 5d", " 1234"},
+	{"1234", "%+5d", "+1234"},
+	{"1234", "%-5d", "1234 "},
+	{"1234", "%x", "4d2"},
+	{"1234", "%X", "4D2"},
+	{"1234", "% x", "4 d2"},
+	{"-1234", "%3x", "-4d2"},
+	{"-1234", "%4x", "-4d2"},
+	{"-1234", "%5x", " -4d2"},
+	{"-1234", "%-5x", "-4d2 "},
+	{"-1234", "% x", "-4 d2"},
+	{"1234", "%03d", "1234"},
+	{"1234", "%04d", "1234"},
+	{"1234", "%05d", "01234"},
+	{"1234", "%06d", "001234"},
+	{"-1234", "%06d", "-01234"},
+	{"1234", "%+06d", "+01234"},
+	{"1234", "% 06d", " 01234"},
+	{"1234", "%-6d", "1234  "},
+	{"1234", "%-06d", "001234"},
+	{"-1234", "%-06d", "-01234"},
+	{"10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", // 10**100
+		"% x",
+		"12 49 ad 25 94 c3 7c eb 0b 27 84 c4 ce 0b f3 8a ce 40 8e 21 1a 7c aa b2 43 08 a8 2e 8f 10 00 00 00 00 00 00 00 00 00 00 00 00"},
 }
 
 
@@ -391,7 +420,7 @@ func TestFormat(t *testing.T) {
 		}
 		output := fmt.Sprintf(test.format, x)
 		if output != test.output {
-			t.Errorf("#%d got %s; want %s", i, output, test.output)
+			t.Errorf("#%d got %q; want %q", i, output, test.output)
 		}
 	}
 }
diff --git a/src/pkg/bufio/bufio.go b/src/pkg/bufio/bufio.go
index 497e770..cb2667b 100644
--- a/src/pkg/bufio/bufio.go
+++ b/src/pkg/bufio/bufio.go
@@ -103,6 +103,12 @@ func (b *Reader) fill() {
 	}
 }
 
+func (b *Reader) readErr() os.Error {
+	err := b.err
+	b.err = nil
+	return err
+}
+
 // Peek returns the next n bytes without advancing the reader. The bytes stop
 // being valid at the next read call. If Peek returns fewer than n bytes, it
 // also returns an error explaining why the read is short. The error is
@@ -121,7 +127,7 @@ func (b *Reader) Peek(n int) ([]byte, os.Error) {
 	if m > n {
 		m = n
 	}
-	err := b.err
+	err := b.readErr()
 	if m < n && err == nil {
 		err = ErrBufferFull
 	}
@@ -136,11 +142,11 @@ func (b *Reader) Peek(n int) ([]byte, os.Error) {
 func (b *Reader) Read(p []byte) (n int, err os.Error) {
 	n = len(p)
 	if n == 0 {
-		return 0, b.err
+		return 0, b.readErr()
 	}
 	if b.w == b.r {
 		if b.err != nil {
-			return 0, b.err
+			return 0, b.readErr()
 		}
 		if len(p) >= len(b.buf) {
 			// Large read, empty buffer.
@@ -150,11 +156,11 @@ func (b *Reader) Read(p []byte) (n int, err os.Error) {
 				b.lastByte = int(p[n-1])
 				b.lastRuneSize = -1
 			}
-			return n, b.err
+			return n, b.readErr()
 		}
 		b.fill()
 		if b.w == b.r {
-			return 0, b.err
+			return 0, b.readErr()
 		}
 	}
 
@@ -174,7 +180,7 @@ func (b *Reader) ReadByte() (c byte, err os.Error) {
 	b.lastRuneSize = -1
 	for b.w == b.r {
 		if b.err != nil {
-			return 0, b.err
+			return 0, b.readErr()
 		}
 		b.fill()
 	}
@@ -210,7 +216,7 @@ func (b *Reader) ReadRune() (rune int, size int, err os.Error) {
 	}
 	b.lastRuneSize = -1
 	if b.r == b.w {
-		return 0, 0, b.err
+		return 0, 0, b.readErr()
 	}
 	rune, size = int(b.buf[b.r]), 1
 	if rune >= 0x80 {
@@ -262,7 +268,7 @@ func (b *Reader) ReadSlice(delim byte) (line []byte, err os.Error) {
 		if b.err != nil {
 			line := b.buf[b.r:b.w]
 			b.r = b.w
-			return line, b.err
+			return line, b.readErr()
 		}
 
 		n := b.Buffered()
diff --git a/src/pkg/bufio/bufio_test.go b/src/pkg/bufio/bufio_test.go
index 123adac..5709213 100644
--- a/src/pkg/bufio/bufio_test.go
+++ b/src/pkg/bufio/bufio_test.go
@@ -53,11 +53,12 @@ func readBytes(buf *Reader) string {
 		if e == os.EOF {
 			break
 		}
-		if e != nil {
+		if e == nil {
+			b[nb] = c
+			nb++
+		} else if e != iotest.ErrTimeout {
 			panic("Data: " + e.String())
 		}
-		b[nb] = c
-		nb++
 	}
 	return string(b[0:nb])
 }
@@ -86,6 +87,7 @@ var readMakers = []readMaker{
 	{"byte", iotest.OneByteReader},
 	{"half", iotest.HalfReader},
 	{"data+err", iotest.DataErrReader},
+	{"timeout", iotest.TimeoutReader},
 }
 
 // Call ReadString (which ends up calling everything else)
@@ -97,7 +99,7 @@ func readLines(b *Reader) string {
 		if e == os.EOF {
 			break
 		}
-		if e != nil {
+		if e != nil && e != iotest.ErrTimeout {
 			panic("GetLines: " + e.String())
 		}
 		s += s1
diff --git a/src/pkg/bytes/bytes.go b/src/pkg/bytes/bytes.go
index 0f9ac98..3cec60f 100644
--- a/src/pkg/bytes/bytes.go
+++ b/src/pkg/bytes/bytes.go
@@ -212,26 +212,40 @@ func genSplit(s, sep []byte, sepSave, n int) [][]byte {
 	return a[0 : na+1]
 }
 
-// Split slices s into subslices separated by sep and returns a slice of
+// SplitN slices s into subslices separated by sep and returns a slice of
 // the subslices between those separators.
-// If sep is empty, Split splits after each UTF-8 sequence.
+// If sep is empty, SplitN splits after each UTF-8 sequence.
 // The count determines the number of subslices to return:
 //   n > 0: at most n subslices; the last subslice will be the unsplit remainder.
 //   n == 0: the result is nil (zero subslices)
 //   n < 0: all subslices
-func Split(s, sep []byte, n int) [][]byte { return genSplit(s, sep, 0, n) }
+func SplitN(s, sep []byte, n int) [][]byte { return genSplit(s, sep, 0, n) }
 
-// SplitAfter slices s into subslices after each instance of sep and
+// SplitAfterN slices s into subslices after each instance of sep and
 // returns a slice of those subslices.
-// If sep is empty, Split splits after each UTF-8 sequence.
+// If sep is empty, SplitAfterN splits after each UTF-8 sequence.
 // The count determines the number of subslices to return:
 //   n > 0: at most n subslices; the last subslice will be the unsplit remainder.
 //   n == 0: the result is nil (zero subslices)
 //   n < 0: all subslices
-func SplitAfter(s, sep []byte, n int) [][]byte {
+func SplitAfterN(s, sep []byte, n int) [][]byte {
 	return genSplit(s, sep, len(sep), n)
 }
 
+// Split slices s into all subslices separated by sep and returns a slice of
+// the subslices between those separators.
+// If sep is empty, Split splits after each UTF-8 sequence.
+// It is equivalent to SplitN with a count of -1.
+func Split(s, sep []byte) [][]byte { return genSplit(s, sep, 0, -1) }
+
+// SplitAfter slices s into all subslices after each instance of sep and
+// returns a slice of those subslices.
+// If sep is empty, SplitAfter splits after each UTF-8 sequence.
+// It is equivalent to SplitAfterN with a count of -1.
+func SplitAfter(s, sep []byte) [][]byte {
+	return genSplit(s, sep, len(sep), -1)
+}
+
 // Fields splits the array s around each instance of one or more consecutive white space
 // characters, returning a slice of subarrays of s or an empty list if s contains only white space.
 func Fields(s []byte) [][]byte {
diff --git a/src/pkg/bytes/bytes_test.go b/src/pkg/bytes/bytes_test.go
index 4ce291a..7539353 100644
--- a/src/pkg/bytes/bytes_test.go
+++ b/src/pkg/bytes/bytes_test.go
@@ -6,6 +6,7 @@ package bytes_test
 
 import (
 	. "bytes"
+	"reflect"
 	"testing"
 	"unicode"
 	"utf8"
@@ -315,7 +316,7 @@ var explodetests = []ExplodeTest{
 
 func TestExplode(t *testing.T) {
 	for _, tt := range explodetests {
-		a := Split([]byte(tt.s), nil, tt.n)
+		a := SplitN([]byte(tt.s), nil, tt.n)
 		result := arrayOfString(a)
 		if !eq(result, tt.a) {
 			t.Errorf(`Explode("%s", %d) = %v; want %v`, tt.s, tt.n, result, tt.a)
@@ -354,7 +355,7 @@ var splittests = []SplitTest{
 
 func TestSplit(t *testing.T) {
 	for _, tt := range splittests {
-		a := Split([]byte(tt.s), []byte(tt.sep), tt.n)
+		a := SplitN([]byte(tt.s), []byte(tt.sep), tt.n)
 		result := arrayOfString(a)
 		if !eq(result, tt.a) {
 			t.Errorf(`Split(%q, %q, %d) = %v; want %v`, tt.s, tt.sep, tt.n, result, tt.a)
@@ -367,6 +368,12 @@ func TestSplit(t *testing.T) {
 		if string(s) != tt.s {
 			t.Errorf(`Join(Split(%q, %q, %d), %q) = %q`, tt.s, tt.sep, tt.n, tt.sep, s)
 		}
+		if tt.n < 0 {
+			b := Split([]byte(tt.s), []byte(tt.sep))
+			if !reflect.DeepEqual(a, b) {
+				t.Errorf("Split disagrees withSplitN(%q, %q, %d) = %v; want %v", tt.s, tt.sep, tt.n, b, a)
+			}
+		}
 	}
 }
 
@@ -388,7 +395,7 @@ var splitaftertests = []SplitTest{
 
 func TestSplitAfter(t *testing.T) {
 	for _, tt := range splitaftertests {
-		a := SplitAfter([]byte(tt.s), []byte(tt.sep), tt.n)
+		a := SplitAfterN([]byte(tt.s), []byte(tt.sep), tt.n)
 		result := arrayOfString(a)
 		if !eq(result, tt.a) {
 			t.Errorf(`Split(%q, %q, %d) = %v; want %v`, tt.s, tt.sep, tt.n, result, tt.a)
@@ -398,6 +405,12 @@ func TestSplitAfter(t *testing.T) {
 		if string(s) != tt.s {
 			t.Errorf(`Join(Split(%q, %q, %d), %q) = %q`, tt.s, tt.sep, tt.n, tt.sep, s)
 		}
+		if tt.n < 0 {
+			b := SplitAfter([]byte(tt.s), []byte(tt.sep))
+			if !reflect.DeepEqual(a, b) {
+				t.Errorf("SplitAfter disagrees withSplitAfterN(%q, %q, %d) = %v; want %v", tt.s, tt.sep, tt.n, b, a)
+			}
+		}
 	}
 }
 
diff --git a/src/pkg/compress/lzw/reader_test.go b/src/pkg/compress/lzw/reader_test.go
index 72121a6..f8042b0 100644
--- a/src/pkg/compress/lzw/reader_test.go
+++ b/src/pkg/compress/lzw/reader_test.go
@@ -84,7 +84,7 @@ var lzwTests = []lzwTest{
 func TestReader(t *testing.T) {
 	b := bytes.NewBuffer(nil)
 	for _, tt := range lzwTests {
-		d := strings.Split(tt.desc, ";", -1)
+		d := strings.Split(tt.desc, ";")
 		var order Order
 		switch d[1] {
 		case "LSB":
diff --git a/src/pkg/crypto/aes/cipher.go b/src/pkg/crypto/aes/cipher.go
index 3a9d023..7322353 100644
--- a/src/pkg/crypto/aes/cipher.go
+++ b/src/pkg/crypto/aes/cipher.go
@@ -45,14 +45,14 @@ func NewCipher(key []byte) (*Cipher, os.Error) {
 
 // BlockSize returns the AES block size, 16 bytes.
 // It is necessary to satisfy the Cipher interface in the
-// package "crypto/block".
+// package "crypto/cipher".
 func (c *Cipher) BlockSize() int { return BlockSize }
 
 // Encrypt encrypts the 16-byte buffer src using the key k
 // and stores the result in dst.
 // Note that for amounts of data larger than a block,
 // it is not safe to just call Encrypt on successive blocks;
-// instead, use an encryption mode like CBC (see crypto/block/cbc.go).
+// instead, use an encryption mode like CBC (see crypto/cipher/cbc.go).
 func (c *Cipher) Encrypt(dst, src []byte) { encryptBlock(c.enc, dst, src) }
 
 // Decrypt decrypts the 16-byte buffer src using the key k
diff --git a/src/pkg/crypto/blowfish/cipher.go b/src/pkg/crypto/blowfish/cipher.go
index f3c5175..6c37dfe 100644
--- a/src/pkg/crypto/blowfish/cipher.go
+++ b/src/pkg/crypto/blowfish/cipher.go
@@ -42,14 +42,14 @@ func NewCipher(key []byte) (*Cipher, os.Error) {
 
 // BlockSize returns the Blowfish block size, 8 bytes.
 // It is necessary to satisfy the Cipher interface in the
-// package "crypto/block".
+// package "crypto/cipher".
 func (c *Cipher) BlockSize() int { return BlockSize }
 
 // Encrypt encrypts the 8-byte buffer src using the key k
 // and stores the result in dst.
 // Note that for amounts of data larger than a block,
 // it is not safe to just call Encrypt on successive blocks;
-// instead, use an encryption mode like CBC (see crypto/block/cbc.go).
+// instead, use an encryption mode like CBC (see crypto/cipher/cbc.go).
 func (c *Cipher) Encrypt(dst, src []byte) {
 	l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
 	r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
diff --git a/src/pkg/crypto/ocsp/ocsp.go b/src/pkg/crypto/ocsp/ocsp.go
index 57dbe7d..e725bde 100644
--- a/src/pkg/crypto/ocsp/ocsp.go
+++ b/src/pkg/crypto/ocsp/ocsp.go
@@ -43,7 +43,7 @@ type certID struct {
 
 type responseASN1 struct {
 	Status   asn1.Enumerated
-	Response responseBytes "explicit,tag:0"
+	Response responseBytes `asn1:"explicit,tag:0"`
 }
 
 type responseBytes struct {
@@ -55,30 +55,30 @@ type basicResponse struct {
 	TBSResponseData    responseData
 	SignatureAlgorithm pkix.AlgorithmIdentifier
 	Signature          asn1.BitString
-	Certificates       []asn1.RawValue "explicit,tag:0,optional"
+	Certificates       []asn1.RawValue `asn1:"explicit,tag:0,optional"`
 }
 
 type responseData struct {
 	Raw           asn1.RawContent
-	Version       int              "optional,default:1,explicit,tag:0"
-	RequestorName pkix.RDNSequence "optional,explicit,tag:1"
-	KeyHash       []byte           "optional,explicit,tag:2"
+	Version       int              `asn1:"optional,default:1,explicit,tag:0"`
+	RequestorName pkix.RDNSequence `asn1:"optional,explicit,tag:1"`
+	KeyHash       []byte           `asn1:"optional,explicit,tag:2"`
 	ProducedAt    *time.Time
 	Responses     []singleResponse
 }
 
 type singleResponse struct {
 	CertID     certID
-	Good       asn1.Flag   "explicit,tag:0,optional"
-	Revoked    revokedInfo "explicit,tag:1,optional"
-	Unknown    asn1.Flag   "explicit,tag:2,optional"
+	Good       asn1.Flag   `asn1:"explicit,tag:0,optional"`
+	Revoked    revokedInfo `asn1:"explicit,tag:1,optional"`
+	Unknown    asn1.Flag   `asn1:"explicit,tag:2,optional"`
 	ThisUpdate *time.Time
-	NextUpdate *time.Time "explicit,tag:0,optional"
+	NextUpdate *time.Time `asn1:"explicit,tag:0,optional"`
 }
 
 type revokedInfo struct {
 	RevocationTime *time.Time
-	Reason         int "explicit,tag:0,optional"
+	Reason         int `asn1:"explicit,tag:0,optional"`
 }
 
 // This is the exposed reflection of the internal OCSP structures.
diff --git a/src/pkg/crypto/openpgp/keys.go b/src/pkg/crypto/openpgp/keys.go
index d12d07d..c70fb79 100644
--- a/src/pkg/crypto/openpgp/keys.go
+++ b/src/pkg/crypto/openpgp/keys.go
@@ -12,6 +12,7 @@ import (
 	"crypto/rsa"
 	"io"
 	"os"
+	"time"
 )
 
 // PublicKeyType is the armor type for a PGP public key.
@@ -476,3 +477,69 @@ func (e *Entity) SerializePrivate(w io.Writer) (err os.Error) {
 	}
 	return nil
 }
+
+// Serialize writes the public part of the given Entity to w. (No private
+// key material will be output).
+func (e *Entity) Serialize(w io.Writer) os.Error {
+	err := e.PrimaryKey.Serialize(w)
+	if err != nil {
+		return err
+	}
+	for _, ident := range e.Identities {
+		err = ident.UserId.Serialize(w)
+		if err != nil {
+			return err
+		}
+		err = ident.SelfSignature.Serialize(w)
+		if err != nil {
+			return err
+		}
+		for _, sig := range ident.Signatures {
+			err = sig.Serialize(w)
+			if err != nil {
+				return err
+			}
+		}
+	}
+	for _, subkey := range e.Subkeys {
+		err = subkey.PublicKey.Serialize(w)
+		if err != nil {
+			return err
+		}
+		err = subkey.Sig.Serialize(w)
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// SignIdentity adds a signature to e, from signer, attesting that identity is
+// associated with e. The provided identity must already be an element of
+// e.Identities and the private key of signer must have been decrypted if
+// necessary.
+func (e *Entity) SignIdentity(identity string, signer *Entity) os.Error {
+	if signer.PrivateKey == nil {
+		return error.InvalidArgumentError("signing Entity must have a private key")
+	}
+	if signer.PrivateKey.Encrypted {
+		return error.InvalidArgumentError("signing Entity's private key must be decrypted")
+	}
+	ident, ok := e.Identities[identity]
+	if !ok {
+		return error.InvalidArgumentError("given identity string not found in Entity")
+	}
+
+	sig := &packet.Signature{
+		SigType:      packet.SigTypeGenericCert,
+		PubKeyAlgo:   signer.PrivateKey.PubKeyAlgo,
+		Hash:         crypto.SHA256,
+		CreationTime: uint32(time.Seconds()),
+		IssuerKeyId:  &signer.PrivateKey.KeyId,
+	}
+	if err := sig.SignKey(e.PrimaryKey, signer.PrivateKey); err != nil {
+		return err
+	}
+	ident.Signatures = append(ident.Signatures, sig)
+	return nil
+}
diff --git a/src/pkg/crypto/openpgp/packet/public_key.go b/src/pkg/crypto/openpgp/packet/public_key.go
index ba4d481..e6b0ae5 100644
--- a/src/pkg/crypto/openpgp/packet/public_key.go
+++ b/src/pkg/crypto/openpgp/packet/public_key.go
@@ -219,7 +219,11 @@ func (pk *PublicKey) Serialize(w io.Writer) (err os.Error) {
 		panic("unknown public key algorithm")
 	}
 
-	err = serializeHeader(w, packetTypePublicKey, length)
+	packetType := packetTypePublicKey
+	if pk.IsSubkey {
+		packetType = packetTypePublicSubkey
+	}
+	err = serializeHeader(w, packetType, length)
 	if err != nil {
 		return
 	}
@@ -279,14 +283,14 @@ func (pk *PublicKey) VerifySignature(signed hash.Hash, sig *Signature) (err os.E
 	switch pk.PubKeyAlgo {
 	case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
 		rsaPublicKey, _ := pk.PublicKey.(*rsa.PublicKey)
-		err = rsa.VerifyPKCS1v15(rsaPublicKey, sig.Hash, hashBytes, sig.RSASignature)
+		err = rsa.VerifyPKCS1v15(rsaPublicKey, sig.Hash, hashBytes, sig.RSASignature.bytes)
 		if err != nil {
 			return error.SignatureError("RSA verification failure")
 		}
 		return nil
 	case PubKeyAlgoDSA:
 		dsaPublicKey, _ := pk.PublicKey.(*dsa.PublicKey)
-		if !dsa.Verify(dsaPublicKey, hashBytes, sig.DSASigR, sig.DSASigS) {
+		if !dsa.Verify(dsaPublicKey, hashBytes, new(big.Int).SetBytes(sig.DSASigR.bytes), new(big.Int).SetBytes(sig.DSASigS.bytes)) {
 			return error.SignatureError("DSA verification failure")
 		}
 		return nil
diff --git a/src/pkg/crypto/openpgp/packet/signature.go b/src/pkg/crypto/openpgp/packet/signature.go
index 123c99f..7577e28 100644
--- a/src/pkg/crypto/openpgp/packet/signature.go
+++ b/src/pkg/crypto/openpgp/packet/signature.go
@@ -5,7 +5,6 @@
 package packet
 
 import (
-	"big"
 	"crypto"
 	"crypto/dsa"
 	"crypto/openpgp/error"
@@ -32,8 +31,11 @@ type Signature struct {
 	HashTag      [2]byte
 	CreationTime uint32 // Unix epoch time
 
-	RSASignature     []byte
-	DSASigR, DSASigS *big.Int
+	RSASignature     parsedMPI
+	DSASigR, DSASigS parsedMPI
+
+	// rawSubpackets contains the unparsed subpackets, in order.
+	rawSubpackets []outputSubpacket
 
 	// The following are optional so are nil when not included in the
 	// signature.
@@ -128,14 +130,11 @@ func (sig *Signature) parse(r io.Reader) (err os.Error) {
 
 	switch sig.PubKeyAlgo {
 	case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
-		sig.RSASignature, _, err = readMPI(r)
+		sig.RSASignature.bytes, sig.RSASignature.bitLength, err = readMPI(r)
 	case PubKeyAlgoDSA:
-		var rBytes, sBytes []byte
-		rBytes, _, err = readMPI(r)
-		sig.DSASigR = new(big.Int).SetBytes(rBytes)
+		sig.DSASigR.bytes, sig.DSASigR.bitLength, err = readMPI(r)
 		if err == nil {
-			sBytes, _, err = readMPI(r)
-			sig.DSASigS = new(big.Int).SetBytes(sBytes)
+			sig.DSASigS.bytes, sig.DSASigS.bitLength, err = readMPI(r)
 		}
 	default:
 		panic("unreachable")
@@ -179,7 +178,7 @@ func parseSignatureSubpacket(sig *Signature, subpacket []byte, isHashed bool) (r
 	// RFC 4880, section 5.2.3.1
 	var (
 		length     uint32
-		packetType byte
+		packetType signatureSubpacketType
 		isCritical bool
 	)
 	switch {
@@ -211,10 +210,11 @@ func parseSignatureSubpacket(sig *Signature, subpacket []byte, isHashed bool) (r
 		err = error.StructuralError("zero length signature subpacket")
 		return
 	}
-	packetType = subpacket[0] & 0x7f
+	packetType = signatureSubpacketType(subpacket[0] & 0x7f)
 	isCritical = subpacket[0]&0x80 == 0x80
 	subpacket = subpacket[1:]
-	switch signatureSubpacketType(packetType) {
+	sig.rawSubpackets = append(sig.rawSubpackets, outputSubpacket{isHashed, packetType, isCritical, subpacket})
+	switch packetType {
 	case creationTimeSubpacket:
 		if !isHashed {
 			err = error.StructuralError("signature creation time in non-hashed area")
@@ -385,7 +385,6 @@ func serializeSubpackets(to []byte, subpackets []outputSubpacket, hashed bool) {
 
 // buildHashSuffix constructs the HashSuffix member of sig in preparation for signing.
 func (sig *Signature) buildHashSuffix() (err os.Error) {
-	sig.outSubpackets = sig.buildSubpackets()
 	hashedSubpacketsLen := subpacketsLength(sig.outSubpackets, true)
 
 	var ok bool
@@ -428,6 +427,7 @@ func (sig *Signature) signPrepareHash(h hash.Hash) (digest []byte, err os.Error)
 // the hash of the message to be signed and will be mutated by this function.
 // On success, the signature is stored in sig. Call Serialize to write it out.
 func (sig *Signature) Sign(h hash.Hash, priv *PrivateKey) (err os.Error) {
+	sig.outSubpackets = sig.buildSubpackets()
 	digest, err := sig.signPrepareHash(h)
 	if err != nil {
 		return
@@ -435,9 +435,16 @@ func (sig *Signature) Sign(h hash.Hash, priv *PrivateKey) (err os.Error) {
 
 	switch priv.PubKeyAlgo {
 	case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
-		sig.RSASignature, err = rsa.SignPKCS1v15(rand.Reader, priv.PrivateKey.(*rsa.PrivateKey), sig.Hash, digest)
+		sig.RSASignature.bytes, err = rsa.SignPKCS1v15(rand.Reader, priv.PrivateKey.(*rsa.PrivateKey), sig.Hash, digest)
+		sig.RSASignature.bitLength = uint16(8 * len(sig.RSASignature.bytes))
 	case PubKeyAlgoDSA:
-		sig.DSASigR, sig.DSASigS, err = dsa.Sign(rand.Reader, priv.PrivateKey.(*dsa.PrivateKey), digest)
+		r, s, err := dsa.Sign(rand.Reader, priv.PrivateKey.(*dsa.PrivateKey), digest)
+		if err == nil {
+			sig.DSASigR.bytes = r.Bytes()
+			sig.DSASigR.bitLength = uint16(8 * len(sig.DSASigR.bytes))
+			sig.DSASigS.bytes = s.Bytes()
+			sig.DSASigS.bitLength = uint16(8 * len(sig.DSASigS.bytes))
+		}
 	default:
 		err = error.UnsupportedError("public key algorithm: " + strconv.Itoa(int(sig.PubKeyAlgo)))
 	}
@@ -468,17 +475,20 @@ func (sig *Signature) SignKey(pub *PublicKey, priv *PrivateKey) os.Error {
 
 // Serialize marshals sig to w. SignRSA or SignDSA must have been called first.
 func (sig *Signature) Serialize(w io.Writer) (err os.Error) {
-	if sig.RSASignature == nil && sig.DSASigR == nil {
+	if len(sig.outSubpackets) == 0 {
+		sig.outSubpackets = sig.rawSubpackets
+	}
+	if sig.RSASignature.bytes == nil && sig.DSASigR.bytes == nil {
 		return error.InvalidArgumentError("Signature: need to call SignRSA or SignDSA before Serialize")
 	}
 
 	sigLength := 0
 	switch sig.PubKeyAlgo {
 	case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
-		sigLength = len(sig.RSASignature)
+		sigLength = 2 + len(sig.RSASignature.bytes)
 	case PubKeyAlgoDSA:
-		sigLength = mpiLength(sig.DSASigR)
-		sigLength += mpiLength(sig.DSASigS)
+		sigLength = 2 + len(sig.DSASigR.bytes)
+		sigLength += 2 + len(sig.DSASigS.bytes)
 	default:
 		panic("impossible")
 	}
@@ -486,7 +496,7 @@ func (sig *Signature) Serialize(w io.Writer) (err os.Error) {
 	unhashedSubpacketsLen := subpacketsLength(sig.outSubpackets, false)
 	length := len(sig.HashSuffix) - 6 /* trailer not included */ +
 		2 /* length of unhashed subpackets */ + unhashedSubpacketsLen +
-		2 /* hash tag */ + 2 /* length of signature MPI */ + sigLength
+		2 /* hash tag */ + sigLength
 	err = serializeHeader(w, packetTypeSignature, length)
 	if err != nil {
 		return
@@ -513,12 +523,9 @@ func (sig *Signature) Serialize(w io.Writer) (err os.Error) {
 
 	switch sig.PubKeyAlgo {
 	case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
-		err = writeMPI(w, 8*uint16(len(sig.RSASignature)), sig.RSASignature)
+		err = writeMPIs(w, sig.RSASignature)
 	case PubKeyAlgoDSA:
-		err = writeBig(w, sig.DSASigR)
-		if err == nil {
-			err = writeBig(w, sig.DSASigS)
-		}
+		err = writeMPIs(w, sig.DSASigR, sig.DSASigS)
 	default:
 		panic("impossible")
 	}
@@ -529,6 +536,7 @@ func (sig *Signature) Serialize(w io.Writer) (err os.Error) {
 type outputSubpacket struct {
 	hashed        bool // true if this subpacket is in the hashed area.
 	subpacketType signatureSubpacketType
+	isCritical    bool
 	contents      []byte
 }
 
@@ -538,12 +546,12 @@ func (sig *Signature) buildSubpackets() (subpackets []outputSubpacket) {
 	creationTime[1] = byte(sig.CreationTime >> 16)
 	creationTime[2] = byte(sig.CreationTime >> 8)
 	creationTime[3] = byte(sig.CreationTime)
-	subpackets = append(subpackets, outputSubpacket{true, creationTimeSubpacket, creationTime})
+	subpackets = append(subpackets, outputSubpacket{true, creationTimeSubpacket, false, creationTime})
 
 	if sig.IssuerKeyId != nil {
 		keyId := make([]byte, 8)
 		binary.BigEndian.PutUint64(keyId, *sig.IssuerKeyId)
-		subpackets = append(subpackets, outputSubpacket{true, issuerSubpacket, keyId})
+		subpackets = append(subpackets, outputSubpacket{true, issuerSubpacket, false, keyId})
 	}
 
 	return
diff --git a/src/pkg/crypto/openpgp/packet/signature_test.go b/src/pkg/crypto/openpgp/packet/signature_test.go
index 1305548..c1bbde8 100644
--- a/src/pkg/crypto/openpgp/packet/signature_test.go
+++ b/src/pkg/crypto/openpgp/packet/signature_test.go
@@ -12,9 +12,7 @@ import (
 )
 
 func TestSignatureRead(t *testing.T) {
-	signatureData, _ := hex.DecodeString(signatureDataHex)
-	buf := bytes.NewBuffer(signatureData)
-	packet, err := Read(buf)
+	packet, err := Read(readerFromHex(signatureDataHex))
 	if err != nil {
 		t.Error(err)
 		return
@@ -25,4 +23,20 @@ func TestSignatureRead(t *testing.T) {
 	}
 }
 
-const signatureDataHex = "89011c04000102000605024cb45112000a0910ab105c91af38fb158f8d07ff5596ea368c5efe015bed6e78348c0f033c931d5f2ce5db54ce7f2a7e4b4ad64db758d65a7a71773edeab7ba2a9e0908e6a94a1175edd86c1d843279f045b021a6971a72702fcbd650efc393c5474d5b59a15f96d2eaad4c4c426797e0dcca2803ef41c6ff234d403eec38f31d610c344c06f2401c262f0993b2e66cad8a81ebc4322c723e0d4ba09fe917e8777658307ad8329adacba821420741009dfe87f007759f0982275d028a392c6ed983a0d846f890b36148c7358bdb8a516007fac760261ecd06076813831a36d0459075d1befa245ae7f7fb103d92ca759e9498fe60ef8078a39a3beda510deea251ea9f0a7f0df6ef42060f20780360686f3e400e"
+func TestSignatureReserialize(t *testing.T) {
+	packet, _ := Read(readerFromHex(signatureDataHex))
+	sig := packet.(*Signature)
+	out := new(bytes.Buffer)
+	err := sig.Serialize(out)
+	if err != nil {
+		t.Errorf("error reserializing: %s", err)
+		return
+	}
+
+	expected, _ := hex.DecodeString(signatureDataHex)
+	if !bytes.Equal(expected, out.Bytes()) {
+		t.Errorf("output doesn't match input (got vs expected):\n%s\n%s", hex.Dump(out.Bytes()), hex.Dump(expected))
+	}
+}
+
+const signatureDataHex = "c2c05c04000102000605024cb45112000a0910ab105c91af38fb158f8d07ff5596ea368c5efe015bed6e78348c0f033c931d5f2ce5db54ce7f2a7e4b4ad64db758d65a7a71773edeab7ba2a9e0908e6a94a1175edd86c1d843279f045b021a6971a72702fcbd650efc393c5474d5b59a15f96d2eaad4c4c426797e0dcca2803ef41c6ff234d403eec38f31d610c344c06f2401c262f0993b2e66cad8a81ebc4322c723e0d4ba09fe917e8777658307ad8329adacba821420741009dfe87f007759f0982275d028a392c6ed983a0d846f890b36148c7358bdb8a516007fac760261ecd06076813831a36d0459075d1befa245ae7f7fb103d92ca759e9498fe60ef8078a39a3beda510deea251ea9f0a7f0df6ef42060f20780360686f3e400e"
diff --git a/src/pkg/crypto/openpgp/read.go b/src/pkg/crypto/openpgp/read.go
index 6830147..d95f613 100644
--- a/src/pkg/crypto/openpgp/read.go
+++ b/src/pkg/crypto/openpgp/read.go
@@ -250,11 +250,12 @@ FindLiteralData:
 			md.IsSigned = true
 			md.SignedByKeyId = p.KeyId
 			keys := keyring.KeysById(p.KeyId)
-			for _, key := range keys {
+			for i, key := range keys {
 				if key.SelfSignature.FlagsValid && !key.SelfSignature.FlagSign {
 					continue
 				}
-				md.SignedBy = &key
+				md.SignedBy = &keys[i]
+				break
 			}
 		case *packet.LiteralData:
 			md.LiteralData = p
diff --git a/src/pkg/crypto/openpgp/read_test.go b/src/pkg/crypto/openpgp/read_test.go
index 7182e94..4dc290e 100644
--- a/src/pkg/crypto/openpgp/read_test.go
+++ b/src/pkg/crypto/openpgp/read_test.go
@@ -33,6 +33,29 @@ func TestReadKeyRing(t *testing.T) {
 	}
 }
 
+func TestRereadKeyRing(t *testing.T) {
+	kring, err := ReadKeyRing(readerFromHex(testKeys1And2Hex))
+	if err != nil {
+		t.Errorf("error in initial parse: %s", err)
+		return
+	}
+	out := new(bytes.Buffer)
+	err = kring[0].Serialize(out)
+	if err != nil {
+		t.Errorf("error in serialization: %s", err)
+		return
+	}
+	kring, err = ReadKeyRing(out)
+	if err != nil {
+		t.Errorf("error in second parse: %s", err)
+		return
+	}
+
+	if len(kring) != 1 || uint32(kring[0].PrimaryKey.KeyId) != 0xC20C31BB {
+		t.Errorf("bad keyring: %#v", kring)
+	}
+}
+
 func TestReadPrivateKeyRing(t *testing.T) {
 	kring, err := ReadKeyRing(readerFromHex(testKeys1And2PrivateHex))
 	if err != nil {
diff --git a/src/pkg/crypto/rand/rand_windows.go b/src/pkg/crypto/rand/rand_windows.go
index 281d6dc..0eab6b2 100755
--- a/src/pkg/crypto/rand/rand_windows.go
+++ b/src/pkg/crypto/rand/rand_windows.go
@@ -19,7 +19,7 @@ func init() { Reader = &rngReader{} }
 
 // A rngReader satisfies reads by reading from the Windows CryptGenRandom API.
 type rngReader struct {
-	prov uint32
+	prov syscall.Handle
 	mu   sync.Mutex
 }
 
diff --git a/src/pkg/crypto/tls/generate_cert.go b/src/pkg/crypto/tls/generate_cert.go
index f461888..41206e2 100644
--- a/src/pkg/crypto/tls/generate_cert.go
+++ b/src/pkg/crypto/tls/generate_cert.go
@@ -8,8 +8,10 @@
 package main
 
 import (
-	"crypto/rsa"
+	"big"
+	"crypto/x509/pkix"
 	"crypto/rand"
+	"crypto/rsa"
 	"crypto/x509"
 	"encoding/pem"
 	"flag"
@@ -32,8 +34,8 @@ func main() {
 	now := time.Seconds()
 
 	template := x509.Certificate{
-		SerialNumber: []byte{0},
-		Subject: x509.Name{
+		SerialNumber: new(big.Int).SetInt64(0),
+		Subject: pkix.Name{
 			CommonName:   *hostName,
 			Organization: []string{"Acme Co"},
 		},
diff --git a/src/pkg/crypto/twofish/twofish.go b/src/pkg/crypto/twofish/twofish.go
index 1a1aac9..2e537c6 100644
--- a/src/pkg/crypto/twofish/twofish.go
+++ b/src/pkg/crypto/twofish/twofish.go
@@ -269,7 +269,7 @@ func h(in, key []byte, offset int) uint32 {
 // Encrypt encrypts a 16-byte block from src to dst, which may overlap.
 // Note that for amounts of data larger than a block,
 // it is not safe to just call Encrypt on successive blocks;
-// instead, use an encryption mode like CBC (see crypto/block/cbc.go).
+// instead, use an encryption mode like CBC (see crypto/cipher/cbc.go).
 func (c *Cipher) Encrypt(dst, src []byte) {
 	S1 := c.s[0]
 	S2 := c.s[1]
diff --git a/src/pkg/crypto/x509/pkix/pkix.go b/src/pkg/crypto/x509/pkix/pkix.go
index 7806b2a..266fd55 100644
--- a/src/pkg/crypto/x509/pkix/pkix.go
+++ b/src/pkg/crypto/x509/pkix/pkix.go
@@ -16,7 +16,7 @@ import (
 // 5280, section 4.1.1.2.
 type AlgorithmIdentifier struct {
 	Algorithm  asn1.ObjectIdentifier
-	Parameters asn1.RawValue "optional"
+	Parameters asn1.RawValue `asn1:"optional"`
 }
 
 type RDNSequence []RelativeDistinguishedNameSET
@@ -32,7 +32,7 @@ type AttributeTypeAndValue struct {
 // 5280, section 4.2.
 type Extension struct {
 	Id       asn1.ObjectIdentifier
-	Critical bool "optional"
+	Critical bool `asn1:"optional"`
 	Value    []byte
 }
 
@@ -149,13 +149,13 @@ func (certList *CertificateList) HasExpired(currentTimeSeconds int64) bool {
 // 5280, section 5.1.
 type TBSCertificateList struct {
 	Raw                 asn1.RawContent
-	Version             int "optional,default:2"
+	Version             int `asn1:"optional,default:2"`
 	Signature           AlgorithmIdentifier
 	Issuer              RDNSequence
 	ThisUpdate          *time.Time
 	NextUpdate          *time.Time
-	RevokedCertificates []RevokedCertificate "optional"
-	Extensions          []Extension          "tag:0,optional,explicit"
+	RevokedCertificates []RevokedCertificate `asn1:"optional"`
+	Extensions          []Extension          `asn1:"tag:0,optional,explicit"`
 }
 
 // RevokedCertificate represents the ASN.1 structure of the same name. See RFC
@@ -163,5 +163,5 @@ type TBSCertificateList struct {
 type RevokedCertificate struct {
 	SerialNumber   *big.Int
 	RevocationTime *time.Time
-	Extensions     []Extension "optional"
+	Extensions     []Extension `asn1:"optional"`
 }
diff --git a/src/pkg/crypto/x509/verify.go b/src/pkg/crypto/x509/verify.go
index 9145880..cad863d 100644
--- a/src/pkg/crypto/x509/verify.go
+++ b/src/pkg/crypto/x509/verify.go
@@ -171,8 +171,14 @@ func (c *Certificate) buildChains(cache map[int][][]*Certificate, currentChain [
 		chains = append(chains, appendToFreshChain(currentChain, root))
 	}
 
+nextIntermediate:
 	for _, intermediateNum := range opts.Intermediates.findVerifiedParents(c) {
 		intermediate := opts.Intermediates.certs[intermediateNum]
+		for _, cert := range currentChain {
+			if cert == intermediate {
+				continue nextIntermediate
+			}
+		}
 		err = intermediate.isValid(intermediateCertificate, opts)
 		if err != nil {
 			continue
@@ -202,8 +208,8 @@ func matchHostnames(pattern, host string) bool {
 		return false
 	}
 
-	patternParts := strings.Split(pattern, ".", -1)
-	hostParts := strings.Split(host, ".", -1)
+	patternParts := strings.Split(pattern, ".")
+	hostParts := strings.Split(host, ".")
 
 	if len(patternParts) != len(hostParts) {
 		return false
diff --git a/src/pkg/crypto/x509/verify_test.go b/src/pkg/crypto/x509/verify_test.go
index 7a63118..111f60e 100644
--- a/src/pkg/crypto/x509/verify_test.go
+++ b/src/pkg/crypto/x509/verify_test.go
@@ -72,23 +72,24 @@ var verifyTests = []verifyTest{
 		},
 	},
 	{
-		leaf:          googleLeaf,
-		intermediates: []string{verisignRoot, thawteIntermediate},
-		roots:         []string{verisignRoot},
+		leaf:          dnssecExpLeaf,
+		intermediates: []string{startComIntermediate},
+		roots:         []string{startComRoot},
 		currentTime:   1302726541,
 
 		expectedChains: [][]string{
-			[]string{"Google", "Thawte", "VeriSign"},
+			[]string{"dnssec-exp", "StartCom Class 1", "StartCom Certification Authority"},
 		},
 	},
 	{
 		leaf:          dnssecExpLeaf,
-		intermediates: []string{startComIntermediate},
+		intermediates: []string{startComIntermediate, startComRoot},
 		roots:         []string{startComRoot},
 		currentTime:   1302726541,
 
 		expectedChains: [][]string{
 			[]string{"dnssec-exp", "StartCom Class 1", "StartCom Certification Authority"},
+			[]string{"dnssec-exp", "StartCom Class 1", "StartCom Certification Authority", "StartCom Certification Authority"},
 		},
 	},
 }
diff --git a/src/pkg/crypto/x509/x509.go b/src/pkg/crypto/x509/x509.go
index 8bafeda..348727a 100644
--- a/src/pkg/crypto/x509/x509.go
+++ b/src/pkg/crypto/x509/x509.go
@@ -30,11 +30,11 @@ type pkcs1PrivateKey struct {
 	P       *big.Int
 	Q       *big.Int
 	// We ignore these values, if present, because rsa will calculate them.
-	Dp   *big.Int "optional"
-	Dq   *big.Int "optional"
-	Qinv *big.Int "optional"
+	Dp   *big.Int `asn1:"optional"`
+	Dq   *big.Int `asn1:"optional"`
+	Qinv *big.Int `asn1:"optional"`
 
-	AdditionalPrimes []pkcs1AdditionalRSAPrime "optional"
+	AdditionalPrimes []pkcs1AdditionalRSAPrime `asn1:"optional"`
 }
 
 type pkcs1AdditionalRSAPrime struct {
@@ -136,16 +136,16 @@ type certificate struct {
 
 type tbsCertificate struct {
 	Raw                asn1.RawContent
-	Version            int "optional,explicit,default:1,tag:0"
+	Version            int `asn1:"optional,explicit,default:1,tag:0"`
 	SerialNumber       *big.Int
 	SignatureAlgorithm pkix.AlgorithmIdentifier
 	Issuer             pkix.RDNSequence
 	Validity           validity
 	Subject            pkix.RDNSequence
 	PublicKey          publicKeyInfo
-	UniqueId           asn1.BitString   "optional,tag:1"
-	SubjectUniqueId    asn1.BitString   "optional,tag:2"
-	Extensions         []pkix.Extension "optional,explicit,tag:3"
+	UniqueId           asn1.BitString   `asn1:"optional,tag:1"`
+	SubjectUniqueId    asn1.BitString   `asn1:"optional,tag:2"`
+	Extensions         []pkix.Extension `asn1:"optional,explicit,tag:3"`
 }
 
 type dsaAlgorithmParameters struct {
@@ -168,7 +168,7 @@ type publicKeyInfo struct {
 
 // RFC 5280,  4.2.1.1
 type authKeyId struct {
-	Id []byte "optional,tag:0"
+	Id []byte `asn1:"optional,tag:0"`
 }
 
 type SignatureAlgorithm int
@@ -480,8 +480,8 @@ func (h UnhandledCriticalExtension) String() string {
 }
 
 type basicConstraints struct {
-	IsCA       bool "optional"
-	MaxPathLen int  "optional"
+	IsCA       bool `asn1:"optional"`
+	MaxPathLen int  `asn1:"optional"`
 }
 
 type rsaPublicKey struct {
@@ -497,14 +497,14 @@ type policyInformation struct {
 
 // RFC 5280, 4.2.1.10
 type nameConstraints struct {
-	Permitted []generalSubtree "optional,tag:0"
-	Excluded  []generalSubtree "optional,tag:1"
+	Permitted []generalSubtree `asn1:"optional,tag:0"`
+	Excluded  []generalSubtree `asn1:"optional,tag:1"`
 }
 
 type generalSubtree struct {
-	Name string "tag:2,optional,ia5"
-	Min  int    "optional,tag:0"
-	Max  int    "optional,tag:1"
+	Name string `asn1:"tag:2,optional,ia5"`
+	Min  int    `asn1:"optional,tag:0"`
+	Max  int    `asn1:"optional,tag:1"`
 }
 
 func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (interface{}, os.Error) {
diff --git a/src/pkg/crypto/xtea/cipher.go b/src/pkg/crypto/xtea/cipher.go
index f2a5da0..b3fba3c 100644
--- a/src/pkg/crypto/xtea/cipher.go
+++ b/src/pkg/crypto/xtea/cipher.go
@@ -48,13 +48,13 @@ func NewCipher(key []byte) (*Cipher, os.Error) {
 
 // BlockSize returns the XTEA block size, 8 bytes.
 // It is necessary to satisfy the Cipher interface in the
-// package "crypto/block".
+// package "crypto/cipher".
 func (c *Cipher) BlockSize() int { return BlockSize }
 
 // Encrypt encrypts the 8 byte buffer src using the key and stores the result in dst.
 // Note that for amounts of data larger than a block,
 // it is not safe to just call Encrypt on successive blocks;
-// instead, use an encryption mode like CBC (see crypto/block/cbc.go).
+// instead, use an encryption mode like CBC (see crypto/cipher/cbc.go).
 func (c *Cipher) Encrypt(dst, src []byte) { encryptBlock(c, dst, src) }
 
 // Decrypt decrypts the 8 byte buffer src using the key k and stores the result in dst.
diff --git a/src/pkg/csv/Makefile b/src/pkg/csv/Makefile
new file mode 100644
index 0000000..e364d51
--- /dev/null
+++ b/src/pkg/csv/Makefile
@@ -0,0 +1,12 @@
+# 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.
+
+include ../../Make.inc
+
+TARG=csv
+GOFILES=\
+	reader.go\
+	writer.go\
+
+include ../../Make.pkg
diff --git a/src/pkg/csv/reader.go b/src/pkg/csv/reader.go
new file mode 100644
index 0000000..1f4b61c
--- /dev/null
+++ b/src/pkg/csv/reader.go
@@ -0,0 +1,373 @@
+// 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 csv reads and writes comma-separated values (CSV) files.
+//
+// A csv file contains zero or more records of one or more fields per record.
+// Each record is separated by the newline character. The final record may
+// optionally be followed by a newline character.
+//
+//	field1,field2,field3
+//
+// White space is considered part of a field.
+//
+// Carriage returns before newline characters are silently removed.
+//
+// Blank lines are ignored.  A line with only whitespace characters (excluding
+// the ending newline character) is not considered a blank line.
+//
+// Fields which start and stop with the quote character " are called
+// quoted-fields.  The beginning and ending quote are not part of the
+// field.
+//
+// The source:
+//
+//	normal string,"quoted-field"
+//
+// results in the fields
+//
+//	{`normal string`, `quoted-field`}
+//
+// Within a quoted-field a quote character followed by a second quote
+// character is considered a single quote.
+//
+//	"the ""word"" is true","a ""quoted-field"""
+//
+// results in
+//
+//	{`the "word" is true`, `a "quoted-field"`}
+//
+// Newlines and commas may be included in a quoted-field
+//
+//	"Multi-line
+//	field","comma is ,"
+//
+// results in
+//
+//	{`Multi-line
+//	field`, `comma is ,`}
+package csv
+
+import (
+	"bufio"
+	"bytes"
+	"fmt"
+	"io"
+	"os"
+	"unicode"
+)
+
+// A ParseError is returned for parsing errors.
+// The first line is 1.  The first column is 0.
+type ParseError struct {
+	Line   int      // Line where the error occurred
+	Column int      // Column (rune index) where the error occurred
+	Error  os.Error // The actual error
+}
+
+func (e *ParseError) String() string {
+	return fmt.Sprintf("line %d, column %d: %s", e.Line, e.Column, e.Error)
+}
+
+// These are the errors that can be returned in ParseError.Error
+var (
+	ErrTrailingComma = os.NewError("extra delimiter at end of line")
+	ErrBareQuote     = os.NewError("bare \" in non-quoted-field")
+	ErrQuote         = os.NewError("extraneous \" in field")
+	ErrFieldCount    = os.NewError("wrong number of fields in line")
+)
+
+// A Reader reads records from a CSV-encoded file.
+//
+// As returned by NewReader, a Reader expects input conforming to RFC 4180.
+// The exported fields can be changed to customize the details before the
+// first call to Read or ReadAll.
+//
+// Comma is the field delimiter.  It defaults to ','.
+//
+// Comment, if not 0, is the comment character. Lines beginning with the
+// Comment character is ignored.
+//
+// If FieldsPerRecord is positive, Read requires each record to
+// have the given number of fields.  If FieldsPerRecord is 0, Read sets it to
+// the number of fields in the first record, so that future records must
+// have the same field count.
+//
+// If LazyQuotes is true, a quote may appear in an unquoted field and a
+// non-doubled quote may appear in a quoted field.
+//
+// If TrailingComma is true, the last field may be a unquoted empty field.
+//
+// If TrimLeadingSpace is true, leading white space in a field is ignored.
+type Reader struct {
+	Comma            int  // Field delimiter (set to ',' by NewReader)
+	Comment          int  // Comment character for start of line
+	FieldsPerRecord  int  // Number of expected fields per record
+	LazyQuotes       bool // Allow lazy quotes
+	TrailingComma    bool // Allow trailing comma
+	TrimLeadingSpace bool // Trim leading space
+	line             int
+	column           int
+	r                *bufio.Reader
+	field            bytes.Buffer
+}
+
+// NewReader returns a new Reader that reads from r.
+func NewReader(r io.Reader) *Reader {
+	return &Reader{
+		Comma: ',',
+		r:     bufio.NewReader(r),
+	}
+}
+
+// error creates a new ParseError based on err.
+func (r *Reader) error(err os.Error) os.Error {
+	return &ParseError{
+		Line:   r.line,
+		Column: r.column,
+		Error:  err,
+	}
+}
+
+// Read reads one record from r.  The record is a slice of strings with each
+// string representing one field.
+func (r *Reader) Read() (record []string, err os.Error) {
+	for {
+		record, err = r.parseRecord()
+		if record != nil {
+			break
+		}
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	if r.FieldsPerRecord > 0 {
+		if len(record) != r.FieldsPerRecord {
+			r.column = 0 // report at start of record
+			return record, r.error(ErrFieldCount)
+		}
+	} else if r.FieldsPerRecord == 0 {
+		r.FieldsPerRecord = len(record)
+	}
+	return record, nil
+}
+
+// ReadAll reads all the remaining records from r.
+// Each record is a slice of fields.
+func (r *Reader) ReadAll() (records [][]string, err os.Error) {
+	for {
+		record, err := r.Read()
+		if err == os.EOF {
+			return records, nil
+		}
+		if err != nil {
+			return nil, err
+		}
+		records = append(records, record)
+	}
+	panic("unreachable")
+}
+
+// readRune reads one rune from r, folding \r\n to \n and keeping track
+// of our far into the line we have read.  r.column will point to the start
+// of this rune, not the end of this rune.
+func (r *Reader) readRune() (int, os.Error) {
+	rune, _, err := r.r.ReadRune()
+
+	// Handle \r\n here.  We make the simplifying assumption that
+	// anytime \r is followed by \n that it can be folded to \n.
+	// We will not detect files which contain both \r\n and bare \n.
+	if rune == '\r' {
+		rune, _, err = r.r.ReadRune()
+		if err == nil {
+			if rune != '\n' {
+				r.r.UnreadRune()
+				rune = '\r'
+			}
+		}
+	}
+	r.column++
+	return rune, err
+}
+
+// unreadRune puts the last rune read from r back.
+func (r *Reader) unreadRune() {
+	r.r.UnreadRune()
+	r.column--
+}
+
+// skip reads runes up to and including the rune delim or until error.
+func (r *Reader) skip(delim int) os.Error {
+	for {
+		rune, err := r.readRune()
+		if err != nil {
+			return err
+		}
+		if rune == delim {
+			return nil
+		}
+	}
+	panic("unreachable")
+}
+
+// parseRecord reads and parses a single csv record from r.
+func (r *Reader) parseRecord() (fields []string, err os.Error) {
+	// Each record starts on a new line.  We increment our line
+	// number (lines start at 1, not 0) and set column to -1
+	// so as we increment in readRune it points to the character we read.
+	r.line++
+	r.column = -1
+
+	// Peek at the first rune.  If it is an error we are done.
+	// If we are support comments and it is the comment character
+	// the skip to the end of line.
+
+	rune, _, err := r.r.ReadRune()
+	if err != nil {
+		return nil, err
+	}
+
+	if r.Comment != 0 && rune == r.Comment {
+		return nil, r.skip('\n')
+	}
+	r.r.UnreadRune()
+
+	// At this point we have at least one field.
+	for {
+		haveField, delim, err := r.parseField()
+		if haveField {
+			fields = append(fields, r.field.String())
+		}
+		if delim == '\n' || err == os.EOF {
+			return fields, err
+		} else if err != nil {
+			return nil, err
+		}
+	}
+	panic("unreachable")
+}
+
+
+// parseField parses the next field in the record.  The read field is
+// located in r.field.  Delim is the first character not part of the field
+// (r.Comma or '\n').
+func (r *Reader) parseField() (haveField bool, delim int, err os.Error) {
+	r.field.Reset()
+
+	rune, err := r.readRune()
+	if err != nil {
+		// If we have EOF and are not at the start of a line
+		// then we return the empty field.  We have already
+		// checked for trailing commas if needed.
+		if err == os.EOF && r.column != 0 {
+			return true, 0, err
+		}
+		return false, 0, err
+	}
+
+	if r.TrimLeadingSpace {
+		for unicode.IsSpace(rune) {
+			rune, err = r.readRune()
+			if err != nil {
+				return false, 0, err
+			}
+		}
+	}
+
+	switch rune {
+	case r.Comma:
+		// will check below
+
+	case '\n':
+		// We are a trailing empty field or a blank linke
+		if r.column == 0 {
+			return false, rune, nil
+		}
+		return true, rune, nil
+
+	case '"':
+		// quoted field
+	Quoted:
+		for {
+			rune, err = r.readRune()
+			if err != nil {
+				if err == os.EOF {
+					if r.LazyQuotes {
+						return true, 0, err
+					}
+					return false, 0, r.error(ErrQuote)
+				}
+				return false, 0, err
+			}
+			switch rune {
+			case '"':
+				rune, err = r.readRune()
+				if err != nil || rune == r.Comma {
+					break Quoted
+				}
+				if rune == '\n' {
+					return true, rune, nil
+				}
+				if rune != '"' {
+					if !r.LazyQuotes {
+						r.column--
+						return false, 0, r.error(ErrQuote)
+					}
+					// accept the bare quote
+					r.field.WriteRune('"')
+				}
+			case '\n':
+				r.line++
+				r.column = -1
+			}
+			r.field.WriteRune(rune)
+		}
+
+	default:
+		// unquoted field
+		for {
+			r.field.WriteRune(rune)
+			rune, err = r.readRune()
+			if err != nil || rune == r.Comma {
+				break
+			}
+			if rune == '\n' {
+				return true, rune, nil
+			}
+			if !r.LazyQuotes && rune == '"' {
+				return false, 0, r.error(ErrBareQuote)
+			}
+		}
+	}
+
+	if err != nil {
+		if err == os.EOF {
+			return true, 0, err
+		}
+		return false, 0, err
+	}
+
+	if !r.TrailingComma {
+		// We don't allow trailing commas.  See if we
+		// are at the end of the line (being mindful
+		// of triming spaces
+		c := r.column
+		rune, err = r.readRune()
+		if r.TrimLeadingSpace {
+			for unicode.IsSpace(rune) {
+				rune, err = r.readRune()
+				if err != nil {
+					break
+				}
+			}
+		}
+		if err == os.EOF || rune == '\n' {
+			r.column = c // report the comma
+			return false, 0, r.error(ErrTrailingComma)
+		}
+		r.unreadRune()
+	}
+	return true, rune, nil
+}
diff --git a/src/pkg/csv/reader_test.go b/src/pkg/csv/reader_test.go
new file mode 100644
index 0000000..0068bad
--- /dev/null
+++ b/src/pkg/csv/reader_test.go
@@ -0,0 +1,265 @@
+// 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 csv
+
+import (
+	"reflect"
+	"strings"
+	"testing"
+)
+
+var readTests = []struct {
+	Name               string
+	Input              string
+	Output             [][]string
+	UseFieldsPerRecord bool // false (default) means FieldsPerRecord is -1
+
+	// These fields are copied into the Reader
+	Comma            int
+	Comment          int
+	FieldsPerRecord  int
+	LazyQuotes       bool
+	TrailingComma    bool
+	TrimLeadingSpace bool
+
+	Error  string
+	Line   int // Expected error line if != 0
+	Column int // Expected error column if line != 0
+}{
+	{
+		Name:   "Simple",
+		Input:  "a,b,c\n",
+		Output: [][]string{{"a", "b", "c"}},
+	},
+	{
+		Name:   "CRLF",
+		Input:  "a,b\r\nc,d\r\n",
+		Output: [][]string{{"a", "b"}, {"c", "d"}},
+	},
+	{
+		Name:   "BareCR",
+		Input:  "a,b\rc,d\r\n",
+		Output: [][]string{{"a", "b\rc", "d"}},
+	},
+	{
+		Name:               "RFC4180test",
+		UseFieldsPerRecord: true,
+		Input: `#field1,field2,field3
+"aaa","bb
+b","ccc"
+"a,a","b""bb","ccc"
+zzz,yyy,xxx
+`,
+		Output: [][]string{
+			{"#field1", "field2", "field3"},
+			{"aaa", "bb\nb", "ccc"},
+			{"a,a", `b"bb`, "ccc"},
+			{"zzz", "yyy", "xxx"},
+		},
+	},
+	{
+		Name:   "NoEOLTest",
+		Input:  "a,b,c",
+		Output: [][]string{{"a", "b", "c"}},
+	},
+	{
+		Name:   "Semicolon",
+		Comma:  ';',
+		Input:  "a;b;c\n",
+		Output: [][]string{{"a", "b", "c"}},
+	},
+	{
+		Name: "MultiLine",
+		Input: `"two
+line","one line","three
+line
+field"`,
+		Output: [][]string{{"two\nline", "one line", "three\nline\nfield"}},
+	},
+	{
+		Name:  "BlankLine",
+		Input: "a,b,c\n\nd,e,f\n\n",
+		Output: [][]string{
+			{"a", "b", "c"},
+			{"d", "e", "f"},
+		},
+	},
+	{
+		Name:             "TrimSpace",
+		Input:            " a,  b,   c\n",
+		TrimLeadingSpace: true,
+		Output:           [][]string{{"a", "b", "c"}},
+	},
+	{
+		Name:   "LeadingSpace",
+		Input:  " a,  b,   c\n",
+		Output: [][]string{{" a", "  b", "   c"}},
+	},
+	{
+		Name:    "Comment",
+		Comment: '#',
+		Input:   "#1,2,3\na,b,c\n#comment",
+		Output:  [][]string{{"a", "b", "c"}},
+	},
+	{
+		Name:   "NoComment",
+		Input:  "#1,2,3\na,b,c",
+		Output: [][]string{{"#1", "2", "3"}, {"a", "b", "c"}},
+	},
+	{
+		Name:       "LazyQuotes",
+		LazyQuotes: true,
+		Input:      `a "word","1"2",a","b`,
+		Output:     [][]string{{`a "word"`, `1"2`, `a"`, `b`}},
+	},
+	{
+		Name:       "BareQuotes",
+		LazyQuotes: true,
+		Input:      `a "word","1"2",a"`,
+		Output:     [][]string{{`a "word"`, `1"2`, `a"`}},
+	},
+	{
+		Name:       "BareDoubleQuotes",
+		LazyQuotes: true,
+		Input:      `a""b,c`,
+		Output:     [][]string{{`a""b`, `c`}},
+	},
+	{
+		Name:   "BadDoubleQuotes",
+		Input:  `a""b,c`,
+		Output: [][]string{{`a""b`, `c`}},
+		Error:  `bare " in non-quoted-field`, Line: 1, Column: 1,
+	},
+	{
+		Name:             "TrimQuote",
+		Input:            ` "a"," b",c`,
+		TrimLeadingSpace: true,
+		Output:           [][]string{{"a", " b", "c"}},
+	},
+	{
+		Name:  "BadBareQuote",
+		Input: `a "word","b"`,
+		Error: `bare " in non-quoted-field`, Line: 1, Column: 2,
+	},
+	{
+		Name:  "BadTrailingQuote",
+		Input: `"a word",b"`,
+		Error: `bare " in non-quoted-field`, Line: 1, Column: 10,
+	},
+	{
+		Name:  "ExtraneousQuote",
+		Input: `"a "word","b"`,
+		Error: `extraneous " in field`, Line: 1, Column: 3,
+	},
+	{
+		Name:               "BadFieldCount",
+		UseFieldsPerRecord: true,
+		Input:              "a,b,c\nd,e",
+		Error:              "wrong number of fields", Line: 2,
+	},
+	{
+		Name:               "BadFieldCount1",
+		UseFieldsPerRecord: true,
+		FieldsPerRecord:    2,
+		Input:              `a,b,c`,
+		Error:              "wrong number of fields", Line: 1,
+	},
+	{
+		Name:   "FieldCount",
+		Input:  "a,b,c\nd,e",
+		Output: [][]string{{"a", "b", "c"}, {"d", "e"}},
+	},
+	{
+		Name:  "BadTrailingCommaEOF",
+		Input: "a,b,c,",
+		Error: "extra delimiter at end of line", Line: 1, Column: 5,
+	},
+	{
+		Name:  "BadTrailingCommaEOL",
+		Input: "a,b,c,\n",
+		Error: "extra delimiter at end of line", Line: 1, Column: 5,
+	},
+	{
+		Name:             "BadTrailingCommaSpaceEOF",
+		TrimLeadingSpace: true,
+		Input:            "a,b,c, ",
+		Error:            "extra delimiter at end of line", Line: 1, Column: 5,
+	},
+	{
+		Name:             "BadTrailingCommaSpaceEOL",
+		TrimLeadingSpace: true,
+		Input:            "a,b,c, \n",
+		Error:            "extra delimiter at end of line", Line: 1, Column: 5,
+	},
+	{
+		Name:             "BadTrailingCommaLine3",
+		TrimLeadingSpace: true,
+		Input:            "a,b,c\nd,e,f\ng,hi,",
+		Error:            "extra delimiter at end of line", Line: 3, Column: 4,
+	},
+	{
+		Name:   "NotTrailingComma3",
+		Input:  "a,b,c, \n",
+		Output: [][]string{{"a", "b", "c", " "}},
+	},
+	{
+		Name:          "CommaFieldTest",
+		TrailingComma: true,
+		Input: `x,y,z,w
+x,y,z,
+x,y,,
+x,,,
+,,,
+"x","y","z","w"
+"x","y","z",""
+"x","y","",""
+"x","","",""
+"","","",""
+`,
+		Output: [][]string{
+			{"x", "y", "z", "w"},
+			{"x", "y", "z", ""},
+			{"x", "y", "", ""},
+			{"x", "", "", ""},
+			{"", "", "", ""},
+			{"x", "y", "z", "w"},
+			{"x", "y", "z", ""},
+			{"x", "y", "", ""},
+			{"x", "", "", ""},
+			{"", "", "", ""},
+		},
+	},
+}
+
+func TestRead(t *testing.T) {
+	for _, tt := range readTests {
+		r := NewReader(strings.NewReader(tt.Input))
+		r.Comment = tt.Comment
+		if tt.UseFieldsPerRecord {
+			r.FieldsPerRecord = tt.FieldsPerRecord
+		} else {
+			r.FieldsPerRecord = -1
+		}
+		r.LazyQuotes = tt.LazyQuotes
+		r.TrailingComma = tt.TrailingComma
+		r.TrimLeadingSpace = tt.TrimLeadingSpace
+		if tt.Comma != 0 {
+			r.Comma = tt.Comma
+		}
+		out, err := r.ReadAll()
+		perr, _ := err.(*ParseError)
+		if tt.Error != "" {
+			if err == nil || !strings.Contains(err.String(), tt.Error) {
+				t.Errorf("%s: error %v, want error %q", tt.Name, err, tt.Error)
+			} else if tt.Line != 0 && (tt.Line != perr.Line || tt.Column != perr.Column) {
+				t.Errorf("%s: error at %d:%d expected %d:%d", tt.Name, perr.Line, perr.Column, tt.Line, tt.Column)
+			}
+		} else if err != nil {
+			t.Errorf("%s: unexpected error %v", tt.Name, err)
+		} else if !reflect.DeepEqual(out, tt.Output) {
+			t.Errorf("%s: out=%q want %q", tt.Name, out, tt.Output)
+		}
+	}
+}
diff --git a/src/pkg/csv/writer.go b/src/pkg/csv/writer.go
new file mode 100644
index 0000000..01386da
--- /dev/null
+++ b/src/pkg/csv/writer.go
@@ -0,0 +1,123 @@
+// 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 csv
+
+import (
+	"bufio"
+	"io"
+	"os"
+	"strings"
+	"unicode"
+	"utf8"
+)
+
+// A Writer writes records to a CSV encoded file.
+//
+// As returned by NewWriter, a Writer writes records terminated by a
+// newline and uses ',' as the field delimiter.  The exported fields can be
+// changed to customize the details before the first call to Write or WriteAll.
+//
+// Comma is the field delimiter.
+//
+// If UseCRLF is true, the Writer ends each record with \r\n instead of \n.
+// just \n is written.
+type Writer struct {
+	Comma   int  // Field delimiter (set to to ',' by NewWriter)
+	UseCRLF bool // True to use \r\n as the line terminator
+	w       *bufio.Writer
+}
+
+// NewWriter returns a new Writer that writes to w.
+func NewWriter(w io.Writer) *Writer {
+	return &Writer{
+		Comma: ',',
+		w:     bufio.NewWriter(w),
+	}
+}
+
+// Writer writes a single CSV record to w along with any necessary quoting.
+// A record is a slice of strings with each string being one field.
+func (w *Writer) Write(record []string) (err os.Error) {
+	for n, field := range record {
+		if n > 0 {
+			if _, err = w.w.WriteRune(w.Comma); err != nil {
+				return
+			}
+		}
+
+		// If we don't have to have a quoted field then just
+		// write out the field and continue to the next field.
+		if !w.fieldNeedsQuotes(field) {
+			if _, err = w.w.WriteString(field); err != nil {
+				return
+			}
+			continue
+		}
+		if err = w.w.WriteByte('"'); err != nil {
+			return
+		}
+
+		for _, rune := range field {
+			switch rune {
+			case '"':
+				_, err = w.w.WriteString(`""`)
+			case '\r':
+				if !w.UseCRLF {
+					err = w.w.WriteByte('\r')
+				}
+			case '\n':
+				if w.UseCRLF {
+					_, err = w.w.WriteString("\r\n")
+				} else {
+					err = w.w.WriteByte('\n')
+				}
+			default:
+				_, err = w.w.WriteRune(rune)
+			}
+			if err != nil {
+				return
+			}
+		}
+
+		if err = w.w.WriteByte('"'); err != nil {
+			return
+		}
+	}
+	if w.UseCRLF {
+		_, err = w.w.WriteString("\r\n")
+	} else {
+		err = w.w.WriteByte('\n')
+	}
+	return
+}
+
+// Flush writes any buffered data to the underlying io.Writer.
+func (w *Writer) Flush() {
+	w.w.Flush()
+}
+
+// WriteAll writes multiple CSV records to w using Write and then calls Flush.
+func (w *Writer) WriteAll(records [][]string) (err os.Error) {
+	for _, record := range records {
+		err = w.Write(record)
+		if err != nil {
+			break
+		}
+	}
+	w.Flush()
+	return nil
+}
+
+// fieldNeedsQuotes returns true if our field must be enclosed in quotes.
+// Empty fields, files with a Comma, fields with a quote or newline, and
+// fields which start with a space must be enclosed in quotes.
+func (w *Writer) fieldNeedsQuotes(field string) bool {
+	if len(field) == 0 || strings.IndexRune(field, w.Comma) >= 0 || strings.IndexAny(field, "\"\r\n") >= 0 {
+		return true
+	}
+
+	rune, _ := utf8.DecodeRuneInString(field)
+	return unicode.IsSpace(rune)
+}
diff --git a/src/pkg/csv/writer_test.go b/src/pkg/csv/writer_test.go
new file mode 100644
index 0000000..5789590
--- /dev/null
+++ b/src/pkg/csv/writer_test.go
@@ -0,0 +1,44 @@
+// 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 csv
+
+import (
+	"bytes"
+	"testing"
+)
+
+var writeTests = []struct {
+	Input   [][]string
+	Output  string
+	UseCRLF bool
+}{
+	{Input: [][]string{{"abc"}}, Output: "abc\n"},
+	{Input: [][]string{{"abc"}}, Output: "abc\r\n", UseCRLF: true},
+	{Input: [][]string{{`"abc"`}}, Output: `"""abc"""` + "\n"},
+	{Input: [][]string{{`a"b`}}, Output: `"a""b"` + "\n"},
+	{Input: [][]string{{`"a"b"`}}, Output: `"""a""b"""` + "\n"},
+	{Input: [][]string{{" abc"}}, Output: `" abc"` + "\n"},
+	{Input: [][]string{{"abc,def"}}, Output: `"abc,def"` + "\n"},
+	{Input: [][]string{{"abc", "def"}}, Output: "abc,def\n"},
+	{Input: [][]string{{"abc"}, {"def"}}, Output: "abc\ndef\n"},
+	{Input: [][]string{{"abc\ndef"}}, Output: "\"abc\ndef\"\n"},
+	{Input: [][]string{{"abc\ndef"}}, Output: "\"abc\r\ndef\"\r\n", UseCRLF: true},
+}
+
+func TestWrite(t *testing.T) {
+	for n, tt := range writeTests {
+		b := &bytes.Buffer{}
+		f := NewWriter(b)
+		f.UseCRLF = tt.UseCRLF
+		err := f.WriteAll(tt.Input)
+		if err != nil {
+			t.Errorf("Unexpected error: %s\n", err)
+		}
+		out := b.String()
+		if out != tt.Output {
+			t.Errorf("#%d: out=%q want %q", n, out, tt.Output)
+		}
+	}
+}
diff --git a/src/pkg/debug/proc/proc_linux.go b/src/pkg/debug/proc/proc_linux.go
index 5831b0e..7ec7971 100644
--- a/src/pkg/debug/proc/proc_linux.go
+++ b/src/pkg/debug/proc/proc_linux.go
@@ -1229,7 +1229,7 @@ func (p *process) attachAllThreads() os.Error {
 					return err
 				}
 
-				statParts := strings.Split(string(statFile), " ", 4)
+				statParts := strings.SplitN(string(statFile), " ", 4)
 				if len(statParts) > 2 && statParts[2] == "Z" {
 					// tid is a zombie
 					p.logTrace("thread %d is a zombie", tid)
diff --git a/src/pkg/exec/exec_test.go b/src/pkg/exec/exec_test.go
index c45a7d7..f6cebb9 100644
--- a/src/pkg/exec/exec_test.go
+++ b/src/pkg/exec/exec_test.go
@@ -55,7 +55,7 @@ func TestCatGoodAndBadFile(t *testing.T) {
 		t.Errorf("expected Waitmsg from cat combined; got %T: %v", err, err)
 	}
 	s := string(bs)
-	sp := strings.Split(s, "\n", 2)
+	sp := strings.SplitN(s, "\n", 2)
 	if len(sp) != 2 {
 		t.Fatalf("expected two lines from cat; got %q", s)
 	}
diff --git a/src/pkg/exec/lp_plan9.go b/src/pkg/exec/lp_plan9.go
index c4e2a7a..e4751a4 100644
--- a/src/pkg/exec/lp_plan9.go
+++ b/src/pkg/exec/lp_plan9.go
@@ -42,7 +42,7 @@ func LookPath(file string) (string, os.Error) {
 	}
 
 	path := os.Getenv("path")
-	for _, dir := range strings.Split(path, "\000", -1) {
+	for _, dir := range strings.Split(path, "\000") {
 		if err := findExecutable(dir + "/" + file); err == nil {
 			return dir + "/" + file, nil
 		}
diff --git a/src/pkg/exec/lp_unix.go b/src/pkg/exec/lp_unix.go
index cdf7207..008fb11 100644
--- a/src/pkg/exec/lp_unix.go
+++ b/src/pkg/exec/lp_unix.go
@@ -39,7 +39,7 @@ func LookPath(file string) (string, os.Error) {
 		return "", &Error{file, err}
 	}
 	pathenv := os.Getenv("PATH")
-	for _, dir := range strings.Split(pathenv, ":", -1) {
+	for _, dir := range strings.Split(pathenv, ":") {
 		if dir == "" {
 			// Unix shell semantics: path element "" means "."
 			dir = "."
diff --git a/src/pkg/exec/lp_windows.go b/src/pkg/exec/lp_windows.go
index 4776345..7581088 100644
--- a/src/pkg/exec/lp_windows.go
+++ b/src/pkg/exec/lp_windows.go
@@ -47,7 +47,7 @@ func LookPath(file string) (f string, err os.Error) {
 		x = `.COM;.EXE;.BAT;.CMD`
 	}
 	exts := []string{}
-	for _, e := range strings.Split(strings.ToLower(x), `;`, -1) {
+	for _, e := range strings.Split(strings.ToLower(x), `;`) {
 		if e == "" {
 			continue
 		}
@@ -67,7 +67,7 @@ func LookPath(file string) (f string, err os.Error) {
 			return
 		}
 	} else {
-		for _, dir := range strings.Split(pathenv, `;`, -1) {
+		for _, dir := range strings.Split(pathenv, `;`) {
 			if f, err = findExecutable(dir+`\`+file, exts); err == nil {
 				return
 			}
diff --git a/src/pkg/exp/ogle/cmd.go b/src/pkg/exp/ogle/cmd.go
index a8db523..ff0d24c 100644
--- a/src/pkg/exp/ogle/cmd.go
+++ b/src/pkg/exp/ogle/cmd.go
@@ -154,7 +154,7 @@ func cmdLoad(args []byte) os.Error {
 		}
 		println("Attached to", pid)
 	} else {
-		parts := strings.Split(path, " ", -1)
+		parts := strings.Split(path, " ")
 		if len(parts) == 0 {
 			fname = ""
 		} else {
diff --git a/src/pkg/exp/regexp/syntax/Makefile b/src/pkg/exp/regexp/syntax/Makefile
index 8e0b4c1..97d4ad6 100644
--- a/src/pkg/exp/regexp/syntax/Makefile
+++ b/src/pkg/exp/regexp/syntax/Makefile
@@ -6,8 +6,11 @@ include ../../../../Make.inc
 
 TARG=exp/regexp/syntax
 GOFILES=\
+	compile.go\
 	parse.go\
 	perl_groups.go\
+	prog.go\
 	regexp.go\
+	simplify.go\
 
 include ../../../../Make.pkg
diff --git a/src/pkg/exp/regexp/syntax/compile.go b/src/pkg/exp/regexp/syntax/compile.go
new file mode 100644
index 0000000..ec9556f
--- /dev/null
+++ b/src/pkg/exp/regexp/syntax/compile.go
@@ -0,0 +1,264 @@
+package syntax
+
+import (
+	"os"
+	"unicode"
+)
+
+// A patchList is a list of instruction pointers that need to be filled in (patched).
+// Because the pointers haven't been filled in yet, we can reuse their storage
+// to hold the list.  It's kind of sleazy, but works well in practice.
+// See http://swtch.com/~rsc/regexp/regexp1.html for inspiration.
+// 
+// These aren't really pointers: they're integers, so we can reinterpret them
+// this way without using package unsafe.  A value l denotes
+// p.inst[l>>1].Out (l&1==0) or .Arg (l&1==1). 
+// l == 0 denotes the empty list, okay because we start every program
+// with a fail instruction, so we'll never want to point at its output link.
+type patchList uint32
+
+func (l patchList) next(p *Prog) patchList {
+	i := &p.Inst[l>>1]
+	if l&1 == 0 {
+		return patchList(i.Out)
+	}
+	return patchList(i.Arg)
+}
+
+func (l patchList) patch(p *Prog, val uint32) {
+	for l != 0 {
+		i := &p.Inst[l>>1]
+		if l&1 == 0 {
+			l = patchList(i.Out)
+			i.Out = val
+		} else {
+			l = patchList(i.Arg)
+			i.Arg = val
+		}
+	}
+}
+
+func (l1 patchList) append(p *Prog, l2 patchList) patchList {
+	if l1 == 0 {
+		return l2
+	}
+	if l2 == 0 {
+		return l1
+	}
+
+	last := l1
+	for {
+		next := last.next(p)
+		if next == 0 {
+			break
+		}
+		last = next
+	}
+
+	i := &p.Inst[last>>1]
+	if last&1 == 0 {
+		i.Out = uint32(l2)
+	} else {
+		i.Arg = uint32(l2)
+	}
+	return l1
+}
+
+// A frag represents a compiled program fragment.
+type frag struct {
+	i   uint32    // index of first instruction
+	out patchList // where to record end instruction
+}
+
+type compiler struct {
+	p *Prog
+}
+
+// Compile compiles the regexp into a program to be executed.
+func Compile(re *Regexp) (*Prog, os.Error) {
+	var c compiler
+	c.init()
+	f := c.compile(re)
+	f.out.patch(c.p, c.inst(InstMatch).i)
+	c.p.Start = int(f.i)
+	return c.p, nil
+}
+
+func (c *compiler) init() {
+	c.p = new(Prog)
+	c.inst(InstFail)
+}
+
+var anyRuneNotNL = []int{0, '\n' - 1, '\n' - 1, unicode.MaxRune}
+var anyRune = []int{0, unicode.MaxRune}
+
+func (c *compiler) compile(re *Regexp) frag {
+	switch re.Op {
+	case OpNoMatch:
+		return c.fail()
+	case OpEmptyMatch:
+		return c.nop()
+	case OpLiteral:
+		if len(re.Rune) == 0 {
+			return c.nop()
+		}
+		var f frag
+		for j := range re.Rune {
+			f1 := c.rune(re.Rune[j : j+1])
+			if j == 0 {
+				f = f1
+			} else {
+				f = c.cat(f, f1)
+			}
+		}
+		return f
+	case OpCharClass:
+		return c.rune(re.Rune)
+	case OpAnyCharNotNL:
+		return c.rune(anyRuneNotNL)
+	case OpAnyChar:
+		return c.rune(anyRune)
+	case OpBeginLine:
+		return c.empty(EmptyBeginLine)
+	case OpEndLine:
+		return c.empty(EmptyEndLine)
+	case OpBeginText:
+		return c.empty(EmptyBeginText)
+	case OpEndText:
+		return c.empty(EmptyEndText)
+	case OpWordBoundary:
+		return c.empty(EmptyWordBoundary)
+	case OpNoWordBoundary:
+		return c.empty(EmptyNoWordBoundary)
+	case OpCapture:
+		bra := c.cap(uint32(re.Cap << 1))
+		sub := c.compile(re.Sub[0])
+		ket := c.cap(uint32(re.Cap<<1 | 1))
+		return c.cat(c.cat(bra, sub), ket)
+	case OpStar:
+		return c.star(c.compile(re.Sub[0]), re.Flags&NonGreedy != 0)
+	case OpPlus:
+		return c.plus(c.compile(re.Sub[0]), re.Flags&NonGreedy != 0)
+	case OpQuest:
+		return c.quest(c.compile(re.Sub[0]), re.Flags&NonGreedy != 0)
+	case OpConcat:
+		if len(re.Sub) == 0 {
+			return c.nop()
+		}
+		var f frag
+		for i, sub := range re.Sub {
+			if i == 0 {
+				f = c.compile(sub)
+			} else {
+				f = c.cat(f, c.compile(sub))
+			}
+		}
+		return f
+	case OpAlternate:
+		var f frag
+		for _, sub := range re.Sub {
+			f = c.alt(f, c.compile(sub))
+		}
+		return f
+	}
+	panic("regexp: unhandled case in compile")
+}
+
+func (c *compiler) inst(op InstOp) frag {
+	// TODO: impose length limit
+	f := frag{i: uint32(len(c.p.Inst))}
+	c.p.Inst = append(c.p.Inst, Inst{Op: op})
+	return f
+}
+
+func (c *compiler) nop() frag {
+	f := c.inst(InstNop)
+	f.out = patchList(f.i << 1)
+	return f
+}
+
+func (c *compiler) fail() frag {
+	return frag{}
+}
+
+func (c *compiler) cap(arg uint32) frag {
+	f := c.inst(InstCapture)
+	f.out = patchList(f.i << 1)
+	c.p.Inst[f.i].Arg = arg
+	return f
+}
+
+func (c *compiler) cat(f1, f2 frag) frag {
+	// concat of failure is failure
+	if f1.i == 0 || f2.i == 0 {
+		return frag{}
+	}
+
+	// TODO: elide nop
+
+	f1.out.patch(c.p, f2.i)
+	return frag{f1.i, f2.out}
+}
+
+func (c *compiler) alt(f1, f2 frag) frag {
+	// alt of failure is other
+	if f1.i == 0 {
+		return f2
+	}
+	if f2.i == 0 {
+		return f1
+	}
+
+	f := c.inst(InstAlt)
+	i := &c.p.Inst[f.i]
+	i.Out = f1.i
+	i.Arg = f2.i
+	f.out = f1.out.append(c.p, f2.out)
+	return f
+}
+
+func (c *compiler) quest(f1 frag, nongreedy bool) frag {
+	f := c.inst(InstAlt)
+	i := &c.p.Inst[f.i]
+	if nongreedy {
+		i.Arg = f1.i
+		f.out = patchList(f.i << 1)
+	} else {
+		i.Out = f1.i
+		f.out = patchList(f.i<<1 | 1)
+	}
+	f.out = f.out.append(c.p, f1.out)
+	return f
+}
+
+func (c *compiler) star(f1 frag, nongreedy bool) frag {
+	f := c.inst(InstAlt)
+	i := &c.p.Inst[f.i]
+	if nongreedy {
+		i.Arg = f1.i
+		f.out = patchList(f.i << 1)
+	} else {
+		i.Out = f1.i
+		f.out = patchList(f.i<<1 | 1)
+	}
+	f1.out.patch(c.p, f.i)
+	return f
+}
+
+func (c *compiler) plus(f1 frag, nongreedy bool) frag {
+	return frag{f1.i, c.star(f1, nongreedy).out}
+}
+
+func (c *compiler) empty(op EmptyOp) frag {
+	f := c.inst(InstEmptyWidth)
+	c.p.Inst[f.i].Arg = uint32(op)
+	f.out = patchList(f.i << 1)
+	return f
+}
+
+func (c *compiler) rune(rune []int) frag {
+	f := c.inst(InstRune)
+	c.p.Inst[f.i].Rune = rune
+	f.out = patchList(f.i << 1)
+	return f
+}
diff --git a/src/pkg/exp/regexp/syntax/parse.go b/src/pkg/exp/regexp/syntax/parse.go
index d04f250..b6c91f7 100644
--- a/src/pkg/exp/regexp/syntax/parse.go
+++ b/src/pkg/exp/regexp/syntax/parse.go
@@ -79,28 +79,108 @@ const (
 type parser struct {
 	flags       Flags     // parse mode flags
 	stack       []*Regexp // stack of parsed expressions
-	numCap      int       // number of capturing groups seen
+	free        *Regexp
+	numCap      int // number of capturing groups seen
 	wholeRegexp string
+	tmpClass    []int // temporary char class work space
+}
+
+func (p *parser) newRegexp(op Op) *Regexp {
+	re := p.free
+	if re != nil {
+		p.free = re.Sub0[0]
+		*re = Regexp{}
+	} else {
+		re = new(Regexp)
+	}
+	re.Op = op
+	return re
+}
+
+func (p *parser) reuse(re *Regexp) {
+	re.Sub0[0] = p.free
+	p.free = re
 }
 
 // Parse stack manipulation.
 
 // push pushes the regexp re onto the parse stack and returns the regexp.
 func (p *parser) push(re *Regexp) *Regexp {
-	// TODO: automatic concatenation
-	// TODO: turn character class into literal
-	// TODO: compute simple
+	if re.Op == OpCharClass && len(re.Rune) == 2 && re.Rune[0] == re.Rune[1] {
+		// Single rune.
+		if p.maybeConcat(re.Rune[0], p.flags&^FoldCase) {
+			return nil
+		}
+		re.Op = OpLiteral
+		re.Rune = re.Rune[:1]
+		re.Flags = p.flags &^ FoldCase
+	} else if re.Op == OpCharClass && len(re.Rune) == 4 &&
+		re.Rune[0] == re.Rune[1] && re.Rune[2] == re.Rune[3] &&
+		unicode.SimpleFold(re.Rune[0]) == re.Rune[2] &&
+		unicode.SimpleFold(re.Rune[2]) == re.Rune[0] ||
+		re.Op == OpCharClass && len(re.Rune) == 2 &&
+			re.Rune[0]+1 == re.Rune[1] &&
+			unicode.SimpleFold(re.Rune[0]) == re.Rune[1] &&
+			unicode.SimpleFold(re.Rune[1]) == re.Rune[0] {
+		// Case-insensitive rune like [Aa] or [Δδ].
+		if p.maybeConcat(re.Rune[0], p.flags|FoldCase) {
+			return nil
+		}
+
+		// Rewrite as (case-insensitive) literal.
+		re.Op = OpLiteral
+		re.Rune = re.Rune[:1]
+		re.Flags = p.flags | FoldCase
+	} else {
+		// Incremental concatenation.
+		p.maybeConcat(-1, 0)
+	}
 
 	p.stack = append(p.stack, re)
 	return re
 }
 
-// newLiteral returns a new OpLiteral Regexp with the given flags
-func newLiteral(r int, flags Flags) *Regexp {
-	re := &Regexp{
-		Op:    OpLiteral,
-		Flags: flags,
+// maybeConcat implements incremental concatenation
+// of literal runes into string nodes.  The parser calls this
+// before each push, so only the top fragment of the stack
+// might need processing.  Since this is called before a push,
+// the topmost literal is no longer subject to operators like *
+// (Otherwise ab* would turn into (ab)*.)
+// If r >= 0 and there's a node left over, maybeConcat uses it
+// to push r with the given flags.
+// maybeConcat reports whether r was pushed.
+func (p *parser) maybeConcat(r int, flags Flags) bool {
+	n := len(p.stack)
+	if n < 2 {
+		return false
 	}
+
+	re1 := p.stack[n-1]
+	re2 := p.stack[n-2]
+	if re1.Op != OpLiteral || re2.Op != OpLiteral || re1.Flags&FoldCase != re2.Flags&FoldCase {
+		return false
+	}
+
+	// Push re1 into re2.
+	re2.Rune = append(re2.Rune, re1.Rune...)
+
+	// Reuse re1 if possible.
+	if r >= 0 {
+		re1.Rune = re1.Rune0[:1]
+		re1.Rune[0] = r
+		re1.Flags = flags
+		return true
+	}
+
+	p.stack = p.stack[:n-1]
+	p.reuse(re1)
+	return false // did not push r
+}
+
+// newLiteral returns a new OpLiteral Regexp with the given flags
+func (p *parser) newLiteral(r int, flags Flags) *Regexp {
+	re := p.newRegexp(OpLiteral)
+	re.Flags = flags
 	re.Rune0[0] = r
 	re.Rune = re.Rune0[:1]
 	return re
@@ -108,14 +188,16 @@ func newLiteral(r int, flags Flags) *Regexp {
 
 // literal pushes a literal regexp for the rune r on the stack
 // and returns that regexp.
-func (p *parser) literal(r int) *Regexp {
-	return p.push(newLiteral(r, p.flags))
+func (p *parser) literal(r int) {
+	p.push(p.newLiteral(r, p.flags))
 }
 
 // op pushes a regexp with the given op onto the stack
 // and returns that regexp.
 func (p *parser) op(op Op) *Regexp {
-	return p.push(&Regexp{Op: op, Flags: p.flags})
+	re := p.newRegexp(op)
+	re.Flags = p.flags
+	return p.push(re)
 }
 
 // repeat replaces the top stack element with itself repeated
@@ -139,12 +221,10 @@ func (p *parser) repeat(op Op, min, max int, opstr, t, lastRepeat string) (strin
 		return "", &Error{ErrMissingRepeatArgument, opstr}
 	}
 	sub := p.stack[n-1]
-	re := &Regexp{
-		Op:    op,
-		Min:   min,
-		Max:   max,
-		Flags: flags,
-	}
+	re := p.newRegexp(op)
+	re.Min = min
+	re.Max = max
+	re.Flags = flags
 	re.Sub = re.Sub0[:1]
 	re.Sub[0] = sub
 	p.stack[n-1] = re
@@ -153,60 +233,385 @@ func (p *parser) repeat(op Op, min, max int, opstr, t, lastRepeat string) (strin
 
 // concat replaces the top of the stack (above the topmost '|' or '(') with its concatenation.
 func (p *parser) concat() *Regexp {
-	// TODO: Flatten concats.
+	p.maybeConcat(-1, 0)
 
 	// Scan down to find pseudo-operator | or (.
 	i := len(p.stack)
 	for i > 0 && p.stack[i-1].Op < opPseudo {
 		i--
 	}
-	sub := p.stack[i:]
+	subs := p.stack[i:]
 	p.stack = p.stack[:i]
 
-	var re *Regexp
-	switch len(sub) {
-	case 0:
-		re = &Regexp{Op: OpEmptyMatch}
-	case 1:
-		re = sub[0]
-	default:
-		re = &Regexp{Op: OpConcat}
-		re.Sub = append(re.Sub0[:0], sub...)
+	// Empty concatenation is special case.
+	if len(subs) == 0 {
+		return p.push(p.newRegexp(OpEmptyMatch))
 	}
-	return p.push(re)
+
+	return p.push(p.collapse(subs, OpConcat))
 }
 
 // alternate replaces the top of the stack (above the topmost '(') with its alternation.
 func (p *parser) alternate() *Regexp {
-	// TODO: Flatten alternates.
-
 	// Scan down to find pseudo-operator (.
 	// There are no | above (.
 	i := len(p.stack)
 	for i > 0 && p.stack[i-1].Op < opPseudo {
 		i--
 	}
-	sub := p.stack[i:]
+	subs := p.stack[i:]
 	p.stack = p.stack[:i]
 
-	var re *Regexp
-	switch len(sub) {
-	case 0:
-		re = &Regexp{Op: OpNoMatch}
-	case 1:
-		re = sub[0]
-	default:
-		re = &Regexp{Op: OpAlternate}
-		re.Sub = append(re.Sub0[:0], sub...)
+	// Make sure top class is clean.
+	// All the others already are (see swapVerticalBar).
+	if len(subs) > 0 {
+		cleanAlt(subs[len(subs)-1])
 	}
-	return p.push(re)
+
+	// Empty alternate is special case
+	// (shouldn't happen but easy to handle).
+	if len(subs) == 0 {
+		return p.push(p.newRegexp(OpNoMatch))
+	}
+
+	return p.push(p.collapse(subs, OpAlternate))
 }
 
-func literalRegexp(s string, flags Flags) *Regexp {
-	re := &Regexp{
-		Op:    OpLiteral,
-		Flags: flags,
+// cleanAlt cleans re for eventual inclusion in an alternation.
+func cleanAlt(re *Regexp) {
+	switch re.Op {
+	case OpCharClass:
+		re.Rune = cleanClass(&re.Rune)
+		if len(re.Rune) == 2 && re.Rune[0] == 0 && re.Rune[1] == unicode.MaxRune {
+			re.Rune = nil
+			re.Op = OpAnyChar
+			return
+		}
+		if len(re.Rune) == 4 && re.Rune[0] == 0 && re.Rune[1] == '\n'-1 && re.Rune[2] == '\n'+1 && re.Rune[3] == unicode.MaxRune {
+			re.Rune = nil
+			re.Op = OpAnyCharNotNL
+			return
+		}
+		if cap(re.Rune)-len(re.Rune) > 100 {
+			// re.Rune will not grow any more.
+			// Make a copy or inline to reclaim storage.
+			re.Rune = append(re.Rune0[:0], re.Rune...)
+		}
+	}
+}
+
+// collapse returns the result of applying op to sub.
+// If sub contains op nodes, they all get hoisted up
+// so that there is never a concat of a concat or an
+// alternate of an alternate.
+func (p *parser) collapse(subs []*Regexp, op Op) *Regexp {
+	if len(subs) == 1 {
+		return subs[0]
+	}
+	re := p.newRegexp(op)
+	re.Sub = re.Sub0[:0]
+	for _, sub := range subs {
+		if sub.Op == op {
+			re.Sub = append(re.Sub, sub.Sub...)
+			p.reuse(sub)
+		} else {
+			re.Sub = append(re.Sub, sub)
+		}
+	}
+	if op == OpAlternate {
+		re.Sub = p.factor(re.Sub, re.Flags)
+		if len(re.Sub) == 1 {
+			old := re
+			re = re.Sub[0]
+			p.reuse(old)
+		}
+	}
+	return re
+}
+
+// factor factors common prefixes from the alternation list sub.
+// It returns a replacement list that reuses the same storage and
+// frees (passes to p.reuse) any removed *Regexps.
+//
+// For example,
+//     ABC|ABD|AEF|BCX|BCY
+// simplifies by literal prefix extraction to
+//     A(B(C|D)|EF)|BC(X|Y)
+// which simplifies by character class introduction to
+//     A(B[CD]|EF)|BC[XY]
+//
+func (p *parser) factor(sub []*Regexp, flags Flags) []*Regexp {
+	if len(sub) < 2 {
+		return sub
+	}
+
+	// Round 1: Factor out common literal prefixes.
+	var str []int
+	var strflags Flags
+	start := 0
+	out := sub[:0]
+	for i := 0; i <= len(sub); i++ {
+		// Invariant: the Regexps that were in sub[0:start] have been
+		// used or marked for reuse, and the slice space has been reused
+		// for out (len(out) <= start).
+		//
+		// Invariant: sub[start:i] consists of regexps that all begin
+		// with str as modified by strflags.
+		var istr []int
+		var iflags Flags
+		if i < len(sub) {
+			istr, iflags = p.leadingString(sub[i])
+			if iflags == strflags {
+				same := 0
+				for same < len(str) && same < len(istr) && str[same] == istr[same] {
+					same++
+				}
+				if same > 0 {
+					// Matches at least one rune in current range.
+					// Keep going around.
+					str = str[:same]
+					continue
+				}
+			}
+		}
+
+		// Found end of a run with common leading literal string:
+		// sub[start:i] all begin with str[0:len(str)], but sub[i]
+		// does not even begin with str[0].
+		//
+		// Factor out common string and append factored expression to out.
+		if i == start {
+			// Nothing to do - run of length 0.
+		} else if i == start+1 {
+			// Just one: don't bother factoring.
+			out = append(out, sub[start])
+		} else {
+			// Construct factored form: prefix(suffix1|suffix2|...)
+			prefix := p.newRegexp(OpLiteral)
+			prefix.Flags = strflags
+			prefix.Rune = append(prefix.Rune[:0], str...)
+
+			for j := start; j < i; j++ {
+				sub[j] = p.removeLeadingString(sub[j], len(str))
+			}
+			suffix := p.collapse(sub[start:i], OpAlternate) // recurse
+
+			re := p.newRegexp(OpConcat)
+			re.Sub = append(re.Sub[:0], prefix, suffix)
+			out = append(out, re)
+		}
+
+		// Prepare for next iteration.
+		start = i
+		str = istr
+		strflags = iflags
+	}
+	sub = out
+
+	// Round 2: Factor out common complex prefixes,
+	// just the first piece of each concatenation,
+	// whatever it is.  This is good enough a lot of the time.
+	start = 0
+	out = sub[:0]
+	var first *Regexp
+	for i := 0; i <= len(sub); i++ {
+		// Invariant: the Regexps that were in sub[0:start] have been
+		// used or marked for reuse, and the slice space has been reused
+		// for out (len(out) <= start).
+		//
+		// Invariant: sub[start:i] consists of regexps that all begin
+		// with str as modified by strflags.
+		var ifirst *Regexp
+		if i < len(sub) {
+			ifirst = p.leadingRegexp(sub[i])
+			if first != nil && first.Equal(ifirst) {
+				continue
+			}
+		}
+
+		// Found end of a run with common leading regexp:
+		// sub[start:i] all begin with first but sub[i] does not.
+		//
+		// Factor out common regexp and append factored expression to out.
+		if i == start {
+			// Nothing to do - run of length 0.
+		} else if i == start+1 {
+			// Just one: don't bother factoring.
+			out = append(out, sub[start])
+		} else {
+			// Construct factored form: prefix(suffix1|suffix2|...)
+			prefix := first
+
+			for j := start; j < i; j++ {
+				reuse := j != start // prefix came from sub[start] 
+				sub[j] = p.removeLeadingRegexp(sub[j], reuse)
+			}
+			suffix := p.collapse(sub[start:i], OpAlternate) // recurse
+
+			re := p.newRegexp(OpConcat)
+			re.Sub = append(re.Sub[:0], prefix, suffix)
+			out = append(out, re)
+		}
+
+		// Prepare for next iteration.
+		start = i
+		first = ifirst
+	}
+	sub = out
+
+	// Round 3: Collapse runs of single literals into character classes.
+	start = 0
+	out = sub[:0]
+	for i := 0; i <= len(sub); i++ {
+		// Invariant: the Regexps that were in sub[0:start] have been
+		// used or marked for reuse, and the slice space has been reused
+		// for out (len(out) <= start).
+		//
+		// Invariant: sub[start:i] consists of regexps that are either
+		// literal runes or character classes.
+		if i < len(sub) && isCharClass(sub[i]) {
+			continue
+		}
+
+		// sub[i] is not a char or char class;
+		// emit char class for sub[start:i]...
+		if i == start {
+			// Nothing to do - run of length 0.
+		} else if i == start+1 {
+			out = append(out, sub[start])
+		} else {
+			// Make new char class.
+			// Start with most complex regexp in sub[start].
+			max := start
+			for j := start + 1; j < i; j++ {
+				if sub[max].Op < sub[j].Op || sub[max].Op == sub[j].Op && len(sub[max].Rune) < len(sub[j].Rune) {
+					max = j
+				}
+			}
+			sub[start], sub[max] = sub[max], sub[start]
+
+			for j := start + 1; j < i; j++ {
+				mergeCharClass(sub[start], sub[j])
+				p.reuse(sub[j])
+			}
+			cleanAlt(sub[start])
+			out = append(out, sub[start])
+		}
+
+		// ... and then emit sub[i].
+		if i < len(sub) {
+			out = append(out, sub[i])
+		}
+		start = i + 1
+	}
+	sub = out
+
+	// Round 4: Collapse runs of empty matches into a single empty match.
+	start = 0
+	out = sub[:0]
+	for i := range sub {
+		if i+1 < len(sub) && sub[i].Op == OpEmptyMatch && sub[i+1].Op == OpEmptyMatch {
+			continue
+		}
+		out = append(out, sub[i])
+	}
+	sub = out
+
+	return sub
+}
+
+// leadingString returns the leading literal string that re begins with.
+// The string refers to storage in re or its children.
+func (p *parser) leadingString(re *Regexp) ([]int, Flags) {
+	if re.Op == OpConcat && len(re.Sub) > 0 {
+		re = re.Sub[0]
+	}
+	if re.Op != OpLiteral {
+		return nil, 0
+	}
+	return re.Rune, re.Flags & FoldCase
+}
+
+// removeLeadingString removes the first n leading runes
+// from the beginning of re.  It returns the replacement for re.
+func (p *parser) removeLeadingString(re *Regexp, n int) *Regexp {
+	if re.Op == OpConcat && len(re.Sub) > 0 {
+		// Removing a leading string in a concatenation
+		// might simplify the concatenation.
+		sub := re.Sub[0]
+		sub = p.removeLeadingString(sub, n)
+		re.Sub[0] = sub
+		if sub.Op == OpEmptyMatch {
+			p.reuse(sub)
+			switch len(re.Sub) {
+			case 0, 1:
+				// Impossible but handle.
+				re.Op = OpEmptyMatch
+				re.Sub = nil
+			case 2:
+				old := re
+				re = re.Sub[1]
+				p.reuse(old)
+			default:
+				copy(re.Sub, re.Sub[1:])
+				re.Sub = re.Sub[:len(re.Sub)-1]
+			}
+		}
+		return re
 	}
+
+	if re.Op == OpLiteral {
+		re.Rune = re.Rune[:copy(re.Rune, re.Rune[n:])]
+		if len(re.Rune) == 0 {
+			re.Op = OpEmptyMatch
+		}
+	}
+	return re
+}
+
+// leadingRegexp returns the leading regexp that re begins with.
+// The regexp refers to storage in re or its children.
+func (p *parser) leadingRegexp(re *Regexp) *Regexp {
+	if re.Op == OpEmptyMatch {
+		return nil
+	}
+	if re.Op == OpConcat && len(re.Sub) > 0 {
+		sub := re.Sub[0]
+		if sub.Op == OpEmptyMatch {
+			return nil
+		}
+		return sub
+	}
+	return re
+}
+
+// removeLeadingRegexp removes the leading regexp in re.
+// It returns the replacement for re.
+// If reuse is true, it passes the removed regexp (if no longer needed) to p.reuse.
+func (p *parser) removeLeadingRegexp(re *Regexp, reuse bool) *Regexp {
+	if re.Op == OpConcat && len(re.Sub) > 0 {
+		if reuse {
+			p.reuse(re.Sub[0])
+		}
+		re.Sub = re.Sub[:copy(re.Sub, re.Sub[1:])]
+		switch len(re.Sub) {
+		case 0:
+			re.Op = OpEmptyMatch
+			re.Sub = nil
+		case 1:
+			old := re
+			re = re.Sub[0]
+			p.reuse(old)
+		}
+		return re
+	}
+	re.Op = OpEmptyMatch
+	return re
+}
+
+func literalRegexp(s string, flags Flags) *Regexp {
+	re := &Regexp{Op: OpLiteral}
+	re.Flags = flags
 	re.Rune = re.Rune0[:0] // use local storage for small strings
 	for _, c := range s {
 		if len(re.Rune) >= cap(re.Rune) {
@@ -264,7 +669,6 @@ func Parse(s string, flags Flags) (*Regexp, os.Error) {
 			p.op(opLeftParen).Cap = p.numCap
 			t = t[1:]
 		case '|':
-			p.concat()
 			if err = p.parseVerticalBar(); err != nil {
 				return nil, err
 			}
@@ -360,7 +764,8 @@ func Parse(s string, flags Flags) (*Regexp, os.Error) {
 				}
 			}
 
-			re := &Regexp{Op: OpCharClass, Flags: p.flags}
+			re := p.newRegexp(OpCharClass)
+			re.Flags = p.flags
 
 			// Look for Unicode character group like \p{Han}
 			if len(t) >= 2 && (t[1] == 'p' || t[1] == 'P') {
@@ -371,7 +776,6 @@ func Parse(s string, flags Flags) (*Regexp, os.Error) {
 				if r != nil {
 					re.Rune = r
 					t = rest
-					// TODO: Handle FoldCase flag.
 					p.push(re)
 					break BigSwitch
 				}
@@ -381,12 +785,10 @@ func Parse(s string, flags Flags) (*Regexp, os.Error) {
 			if r, rest := p.parsePerlClassEscape(t, re.Rune0[:0]); r != nil {
 				re.Rune = r
 				t = rest
-				// TODO: Handle FoldCase flag.
 				p.push(re)
 				break BigSwitch
 			}
-
-			// TODO: Give re back to parser's pool.
+			p.reuse(re)
 
 			// Ordinary single-character escape.
 			if c, t, err = p.parseEscape(t); err != nil {
@@ -592,6 +994,35 @@ func (p *parser) parseInt(s string) (n int, rest string, ok bool) {
 	return
 }
 
+// can this be represented as a character class?
+// single-rune literal string, char class, ., and .|\n.
+func isCharClass(re *Regexp) bool {
+	return re.Op == OpLiteral && len(re.Rune) == 1 ||
+		re.Op == OpCharClass ||
+		re.Op == OpAnyCharNotNL ||
+		re.Op == OpAnyChar
+}
+
+// does re match r?
+func matchRune(re *Regexp, r int) bool {
+	switch re.Op {
+	case OpLiteral:
+		return len(re.Rune) == 1 && re.Rune[0] == r
+	case OpCharClass:
+		for i := 0; i < len(re.Rune); i += 2 {
+			if re.Rune[i] <= r && r <= re.Rune[i+1] {
+				return true
+			}
+		}
+		return false
+	case OpAnyCharNotNL:
+		return r != '\n'
+	case OpAnyChar:
+		return true
+	}
+	return false
+}
+
 // parseVerticalBar handles a | in the input.
 func (p *parser) parseVerticalBar() os.Error {
 	p.concat()
@@ -607,14 +1038,66 @@ func (p *parser) parseVerticalBar() os.Error {
 	return nil
 }
 
+// mergeCharClass makes dst = dst|src.
+// The caller must ensure that dst.Op >= src.Op,
+// to reduce the amount of copying.
+func mergeCharClass(dst, src *Regexp) {
+	switch dst.Op {
+	case OpAnyChar:
+		// src doesn't add anything.
+	case OpAnyCharNotNL:
+		// src might add \n
+		if matchRune(src, '\n') {
+			dst.Op = OpAnyChar
+		}
+	case OpCharClass:
+		// src is simpler, so either literal or char class
+		if src.Op == OpLiteral {
+			dst.Rune = appendRange(dst.Rune, src.Rune[0], src.Rune[0])
+		} else {
+			dst.Rune = appendClass(dst.Rune, src.Rune)
+		}
+	case OpLiteral:
+		// both literal
+		if src.Rune[0] == dst.Rune[0] {
+			break
+		}
+		dst.Op = OpCharClass
+		dst.Rune = append(dst.Rune, dst.Rune[0])
+		dst.Rune = appendRange(dst.Rune, src.Rune[0], src.Rune[0])
+	}
+}
+
 // If the top of the stack is an element followed by an opVerticalBar
 // swapVerticalBar swaps the two and returns true.
 // Otherwise it returns false.
 func (p *parser) swapVerticalBar() bool {
-	if n := len(p.stack); n >= 2 {
+	// If above and below vertical bar are literal or char class,
+	// can merge into a single char class.
+	n := len(p.stack)
+	if n >= 3 && p.stack[n-2].Op == opVerticalBar && isCharClass(p.stack[n-1]) && isCharClass(p.stack[n-3]) {
+		re1 := p.stack[n-1]
+		re3 := p.stack[n-3]
+		// Make re3 the more complex of the two.
+		if re1.Op > re3.Op {
+			re1, re3 = re3, re1
+			p.stack[n-3] = re3
+		}
+		mergeCharClass(re3, re1)
+		p.reuse(re1)
+		p.stack = p.stack[:n-1]
+		return true
+	}
+
+	if n >= 2 {
 		re1 := p.stack[n-1]
 		re2 := p.stack[n-2]
 		if re2.Op == opVerticalBar {
+			if n >= 3 {
+				// Now out of reach.
+				// Clean opportunistically.
+				cleanAlt(p.stack[n-3])
+			}
 			p.stack[n-2] = re1
 			p.stack[n-1] = re2
 			return true
@@ -729,6 +1212,7 @@ Switch:
 				if r > unicode.MaxRune {
 					break Switch
 				}
+				nhex++
 			}
 			if nhex == 0 {
 				break Switch
@@ -801,12 +1285,7 @@ func (p *parser) parsePerlClassEscape(s string, r []int) (out []int, rest string
 	if g.sign == 0 {
 		return
 	}
-	if g.sign < 0 {
-		r = appendNegatedClass(r, g.class)
-	} else {
-		r = appendClass(r, g.class)
-	}
-	return r, s[2:]
+	return p.appendGroup(r, g), s[2:]
 }
 
 // parseNamedClass parses a leading POSIX named character class like [:alnum:]
@@ -827,23 +1306,40 @@ func (p *parser) parseNamedClass(s string, r []int) (out []int, rest string, err
 	if g.sign == 0 {
 		return nil, "", &Error{ErrInvalidCharRange, name}
 	}
-	if g.sign < 0 {
-		r = appendNegatedClass(r, g.class)
+	return p.appendGroup(r, g), s, nil
+}
+
+func (p *parser) appendGroup(r []int, g charGroup) []int {
+	if p.flags&FoldCase == 0 {
+		if g.sign < 0 {
+			r = appendNegatedClass(r, g.class)
+		} else {
+			r = appendClass(r, g.class)
+		}
 	} else {
-		r = appendClass(r, g.class)
+		tmp := p.tmpClass[:0]
+		tmp = appendFoldedClass(tmp, g.class)
+		p.tmpClass = tmp
+		tmp = cleanClass(&p.tmpClass)
+		if g.sign < 0 {
+			r = appendNegatedClass(r, tmp)
+		} else {
+			r = appendClass(r, tmp)
+		}
 	}
-	return r, s, nil
+	return r
 }
 
-// unicodeTable returns the unicode.RangeTable identified by name.
-func unicodeTable(name string) *unicode.RangeTable {
+// unicodeTable returns the unicode.RangeTable identified by name
+// and the table of additional fold-equivalent code points.
+func unicodeTable(name string) (*unicode.RangeTable, *unicode.RangeTable) {
 	if t := unicode.Categories[name]; t != nil {
-		return t
+		return t, unicode.FoldCategory[name]
 	}
 	if t := unicode.Scripts[name]; t != nil {
-		return t
+		return t, unicode.FoldScript[name]
 	}
-	return nil
+	return nil, nil
 }
 
 // parseUnicodeClass parses a leading Unicode character class like \p{Han}
@@ -891,14 +1387,31 @@ func (p *parser) parseUnicodeClass(s string, r []int) (out []int, rest string, e
 		name = name[1:]
 	}
 
-	tab := unicodeTable(name)
+	tab, fold := unicodeTable(name)
 	if tab == nil {
 		return nil, "", &Error{ErrInvalidCharRange, seq}
 	}
-	if sign > 0 {
-		r = appendTable(r, tab)
+
+	if p.flags&FoldCase == 0 || fold == nil {
+		if sign > 0 {
+			r = appendTable(r, tab)
+		} else {
+			r = appendNegatedTable(r, tab)
+		}
 	} else {
-		r = appendNegatedTable(r, tab)
+		// Merge and clean tab and fold in a temporary buffer.
+		// This is necessary for the negative case and just tidy
+		// for the positive case.
+		tmp := p.tmpClass[:0]
+		tmp = appendTable(tmp, tab)
+		tmp = appendTable(tmp, fold)
+		p.tmpClass = tmp
+		tmp = cleanClass(&p.tmpClass)
+		if sign > 0 {
+			r = appendClass(r, tmp)
+		} else {
+			r = appendNegatedClass(r, tmp)
+		}
 	}
 	return r, t, nil
 }
@@ -907,7 +1420,8 @@ func (p *parser) parseUnicodeClass(s string, r []int) (out []int, rest string, e
 // and pushes it onto the parse stack.
 func (p *parser) parseClass(s string) (rest string, err os.Error) {
 	t := s[1:] // chop [
-	re := &Regexp{Op: OpCharClass, Flags: p.flags}
+	re := p.newRegexp(OpCharClass)
+	re.Flags = p.flags
 	re.Rune = re.Rune0[:0]
 
 	sign := +1
@@ -979,12 +1493,14 @@ func (p *parser) parseClass(s string) (rest string, err os.Error) {
 				return "", &Error{Code: ErrInvalidCharRange, Expr: rng}
 			}
 		}
-		class = appendRange(class, lo, hi)
+		if p.flags&FoldCase == 0 {
+			class = appendRange(class, lo, hi)
+		} else {
+			class = appendFoldedRange(class, lo, hi)
+		}
 	}
 	t = t[1:] // chop ]
 
-	// TODO: Handle FoldCase flag.
-
 	// Use &re.Rune instead of &class to avoid allocation.
 	re.Rune = class
 	class = cleanClass(&re.Rune)
@@ -999,10 +1515,15 @@ func (p *parser) parseClass(s string) (rest string, err os.Error) {
 // cleanClass sorts the ranges (pairs of elements of r),
 // merges them, and eliminates duplicates.
 func cleanClass(rp *[]int) []int {
+
 	// Sort by lo increasing, hi decreasing to break ties.
 	sort.Sort(ranges{rp})
 
 	r := *rp
+	if len(r) < 2 {
+		return r
+	}
+
 	// Merge abutting, overlapping.
 	w := 2 // write index
 	for i := 2; i < len(r); i += 2 {
@@ -1025,23 +1546,71 @@ func cleanClass(rp *[]int) []int {
 
 // appendRange returns the result of appending the range lo-hi to the class r.
 func appendRange(r []int, lo, hi int) []int {
-	// Expand last range if overlaps or abuts.
-	if n := len(r); n > 0 {
-		rlo, rhi := r[n-2], r[n-1]
-		if lo <= rhi+1 && rlo <= hi+1 {
-			if lo < rlo {
-				r[n-2] = lo
-			}
-			if hi > rhi {
-				r[n-1] = hi
+	// Expand last range or next to last range if it overlaps or abuts.
+	// Checking two ranges helps when appending case-folded
+	// alphabets, so that one range can be expanding A-Z and the
+	// other expanding a-z.
+	n := len(r)
+	for i := 2; i <= 4; i += 2 { // twice, using i=2, i=4
+		if n >= i {
+			rlo, rhi := r[n-i], r[n-i+1]
+			if lo <= rhi+1 && rlo <= hi+1 {
+				if lo < rlo {
+					r[n-i] = lo
+				}
+				if hi > rhi {
+					r[n-i+1] = hi
+				}
+				return r
 			}
-			return r
 		}
 	}
 
 	return append(r, lo, hi)
 }
 
+const (
+	// minimum and maximum runes involved in folding.
+	// checked during test.
+	minFold = 0x0041
+	maxFold = 0x1044f
+)
+
+// appendFoldedRange returns the result of appending the range lo-hi
+// and its case folding-equivalent runes to the class r.
+func appendFoldedRange(r []int, lo, hi int) []int {
+	// Optimizations.
+	if lo <= minFold && hi >= maxFold {
+		// Range is full: folding can't add more.
+		return appendRange(r, lo, hi)
+	}
+	if hi < minFold || lo > maxFold {
+		// Range is outside folding possibilities.
+		return appendRange(r, lo, hi)
+	}
+	if lo < minFold {
+		// [lo, minFold-1] needs no folding.
+		r = appendRange(r, lo, minFold-1)
+		lo = minFold
+	}
+	if hi > maxFold {
+		// [maxFold+1, hi] needs no folding.
+		r = appendRange(r, maxFold+1, hi)
+		hi = maxFold
+	}
+
+	// Brute force.  Depend on appendRange to coalesce ranges on the fly.
+	for c := lo; c <= hi; c++ {
+		r = appendRange(r, c, c)
+		f := unicode.SimpleFold(c)
+		for f != c {
+			r = appendRange(r, f, f)
+			f = unicode.SimpleFold(f)
+		}
+	}
+	return r
+}
+
 // appendClass returns the result of appending the class x to the class r.
 // It assume x is clean.
 func appendClass(r []int, x []int) []int {
@@ -1051,6 +1620,14 @@ func appendClass(r []int, x []int) []int {
 	return r
 }
 
+// appendFolded returns the result of appending the case folding of the class x to the class r.
+func appendFoldedClass(r []int, x []int) []int {
+	for i := 0; i < len(x); i += 2 {
+		r = appendFoldedRange(r, x[i], x[i+1])
+	}
+	return r
+}
+
 // appendNegatedClass returns the result of appending the negation of the class x to the class r.
 // It assumes x is clean.
 func appendNegatedClass(r []int, x []int) []int {
@@ -1148,10 +1725,11 @@ func negateClass(r []int) []int {
 		}
 		nextLo = hi + 1
 	}
+	r = r[:w]
 	if nextLo <= unicode.MaxRune {
 		// It's possible for the negation to have one more
 		// range - this one - than the original class, so use append.
-		r = append(r[:w], nextLo, unicode.MaxRune)
+		r = append(r, nextLo, unicode.MaxRune)
 	}
 	return r
 }
diff --git a/src/pkg/exp/regexp/syntax/parse_test.go b/src/pkg/exp/regexp/syntax/parse_test.go
index b52cab1..779b9af 100644
--- a/src/pkg/exp/regexp/syntax/parse_test.go
+++ b/src/pkg/exp/regexp/syntax/parse_test.go
@@ -16,141 +16,152 @@ var parseTests = []struct {
 	Dump   string
 }{
 	// Base cases
-	{"a", "lit{a}"},
-	{"a.", "cat{lit{a}dot{}}"},
-	{"a.b", "cat{lit{a}dot{}lit{b}}"},
-	//	{ "ab", "str{ab}" },
-	{"ab", "cat{lit{a}lit{b}}"},
-	{"a.b.c", "cat{lit{a}dot{}lit{b}dot{}lit{c}}"},
-	//	{ "abc", "str{abc}" },
-	{"abc", "cat{lit{a}lit{b}lit{c}}"},
-	{"a|^", "alt{lit{a}bol{}}"},
-	//	{ "a|b", "cc{0x61-0x62}" },
-	{"a|b", "alt{lit{a}lit{b}}"},
-	{"(a)", "cap{lit{a}}"},
-	{"(a)|b", "alt{cap{lit{a}}lit{b}}"},
-	{"a*", "star{lit{a}}"},
-	{"a+", "plus{lit{a}}"},
-	{"a?", "que{lit{a}}"},
-	{"a{2}", "rep{2,2 lit{a}}"},
-	{"a{2,3}", "rep{2,3 lit{a}}"},
-	{"a{2,}", "rep{2,-1 lit{a}}"},
-	{"a*?", "nstar{lit{a}}"},
-	{"a+?", "nplus{lit{a}}"},
-	{"a??", "nque{lit{a}}"},
-	{"a{2}?", "nrep{2,2 lit{a}}"},
-	{"a{2,3}?", "nrep{2,3 lit{a}}"},
-	{"a{2,}?", "nrep{2,-1 lit{a}}"},
-	{"", "emp{}"},
-	//	{ "|", "emp{}" },  // alt{emp{}emp{}} but got factored
-	{"|", "alt{emp{}emp{}}"},
-	{"|x|", "alt{emp{}lit{x}emp{}}"},
-	{".", "dot{}"},
-	{"^", "bol{}"},
-	{"$", "eol{}"},
-	{"\\|", "lit{|}"},
-	{"\\(", "lit{(}"},
-	{"\\)", "lit{)}"},
-	{"\\*", "lit{*}"},
-	{"\\+", "lit{+}"},
-	{"\\?", "lit{?}"},
-	{"{", "lit{{}"},
-	{"}", "lit{}}"},
-	{"\\.", "lit{.}"},
-	{"\\^", "lit{^}"},
-	{"\\$", "lit{$}"},
-	{"\\\\", "lit{\\}"},
-	{"[ace]", "cc{0x61 0x63 0x65}"},
-	{"[abc]", "cc{0x61-0x63}"},
-	{"[a-z]", "cc{0x61-0x7a}"},
-	//	{ "[a]", "lit{a}" },
-	{"[a]", "cc{0x61}"},
-	{"\\-", "lit{-}"},
-	{"-", "lit{-}"},
-	{"\\_", "lit{_}"},
+	{`a`, `lit{a}`},
+	{`a.`, `cat{lit{a}dot{}}`},
+	{`a.b`, `cat{lit{a}dot{}lit{b}}`},
+	{`ab`, `str{ab}`},
+	{`a.b.c`, `cat{lit{a}dot{}lit{b}dot{}lit{c}}`},
+	{`abc`, `str{abc}`},
+	{`a|^`, `alt{lit{a}bol{}}`},
+	{`a|b`, `cc{0x61-0x62}`},
+	{`(a)`, `cap{lit{a}}`},
+	{`(a)|b`, `alt{cap{lit{a}}lit{b}}`},
+	{`a*`, `star{lit{a}}`},
+	{`a+`, `plus{lit{a}}`},
+	{`a?`, `que{lit{a}}`},
+	{`a{2}`, `rep{2,2 lit{a}}`},
+	{`a{2,3}`, `rep{2,3 lit{a}}`},
+	{`a{2,}`, `rep{2,-1 lit{a}}`},
+	{`a*?`, `nstar{lit{a}}`},
+	{`a+?`, `nplus{lit{a}}`},
+	{`a??`, `nque{lit{a}}`},
+	{`a{2}?`, `nrep{2,2 lit{a}}`},
+	{`a{2,3}?`, `nrep{2,3 lit{a}}`},
+	{`a{2,}?`, `nrep{2,-1 lit{a}}`},
+	{``, `emp{}`},
+	{`|`, `emp{}`}, // alt{emp{}emp{}} but got factored
+	{`|x|`, `alt{emp{}lit{x}emp{}}`},
+	{`.`, `dot{}`},
+	{`^`, `bol{}`},
+	{`$`, `eol{}`},
+	{`\|`, `lit{|}`},
+	{`\(`, `lit{(}`},
+	{`\)`, `lit{)}`},
+	{`\*`, `lit{*}`},
+	{`\+`, `lit{+}`},
+	{`\?`, `lit{?}`},
+	{`{`, `lit{{}`},
+	{`}`, `lit{}}`},
+	{`\.`, `lit{.}`},
+	{`\^`, `lit{^}`},
+	{`\$`, `lit{$}`},
+	{`\\`, `lit{\}`},
+	{`[ace]`, `cc{0x61 0x63 0x65}`},
+	{`[abc]`, `cc{0x61-0x63}`},
+	{`[a-z]`, `cc{0x61-0x7a}`},
+	{`[a]`, `lit{a}`},
+	{`\-`, `lit{-}`},
+	{`-`, `lit{-}`},
+	{`\_`, `lit{_}`},
+	{`abc`, `str{abc}`},
+	{`abc|def`, `alt{str{abc}str{def}}`},
+	{`abc|def|ghi`, `alt{str{abc}str{def}str{ghi}}`},
 
 	// Posix and Perl extensions
-	{"[[:lower:]]", "cc{0x61-0x7a}"},
-	{"[a-z]", "cc{0x61-0x7a}"},
-	{"[^[:lower:]]", "cc{0x0-0x60 0x7b-0x10ffff}"},
-	{"[[:^lower:]]", "cc{0x0-0x60 0x7b-0x10ffff}"},
-	//	{ "(?i)[[:lower:]]", "cc{0x41-0x5a 0x61-0x7a 0x17f 0x212a}" },
-	//	{ "(?i)[a-z]", "cc{0x41-0x5a 0x61-0x7a 0x17f 0x212a}" },
-	//	{ "(?i)[^[:lower:]]", "cc{0x0-0x40 0x5b-0x60 0x7b-0x17e 0x180-0x2129 0x212b-0x10ffff}" },
-	//	{ "(?i)[[:^lower:]]", "cc{0x0-0x40 0x5b-0x60 0x7b-0x17e 0x180-0x2129 0x212b-0x10ffff}" },
-	{"\\d", "cc{0x30-0x39}"},
-	{"\\D", "cc{0x0-0x2f 0x3a-0x10ffff}"},
-	{"\\s", "cc{0x9-0xa 0xc-0xd 0x20}"},
-	{"\\S", "cc{0x0-0x8 0xb 0xe-0x1f 0x21-0x10ffff}"},
-	{"\\w", "cc{0x30-0x39 0x41-0x5a 0x5f 0x61-0x7a}"},
-	{"\\W", "cc{0x0-0x2f 0x3a-0x40 0x5b-0x5e 0x60 0x7b-0x10ffff}"},
-	//	{ "(?i)\\w", "cc{0x30-0x39 0x41-0x5a 0x5f 0x61-0x7a 0x17f 0x212a}" },
-	//	{ "(?i)\\W", "cc{0x0-0x2f 0x3a-0x40 0x5b-0x5e 0x60 0x7b-0x17e 0x180-0x2129 0x212b-0x10ffff}" },
-	{"[^\\\\]", "cc{0x0-0x5b 0x5d-0x10ffff}"},
-	//	{ "\\C", "byte{}" },
+	{`[[:lower:]]`, `cc{0x61-0x7a}`},
+	{`[a-z]`, `cc{0x61-0x7a}`},
+	{`[^[:lower:]]`, `cc{0x0-0x60 0x7b-0x10ffff}`},
+	{`[[:^lower:]]`, `cc{0x0-0x60 0x7b-0x10ffff}`},
+	{`(?i)[[:lower:]]`, `cc{0x41-0x5a 0x61-0x7a 0x17f 0x212a}`},
+	{`(?i)[a-z]`, `cc{0x41-0x5a 0x61-0x7a 0x17f 0x212a}`},
+	{`(?i)[^[:lower:]]`, `cc{0x0-0x40 0x5b-0x60 0x7b-0x17e 0x180-0x2129 0x212b-0x10ffff}`},
+	{`(?i)[[:^lower:]]`, `cc{0x0-0x40 0x5b-0x60 0x7b-0x17e 0x180-0x2129 0x212b-0x10ffff}`},
+	{`\d`, `cc{0x30-0x39}`},
+	{`\D`, `cc{0x0-0x2f 0x3a-0x10ffff}`},
+	{`\s`, `cc{0x9-0xa 0xc-0xd 0x20}`},
+	{`\S`, `cc{0x0-0x8 0xb 0xe-0x1f 0x21-0x10ffff}`},
+	{`\w`, `cc{0x30-0x39 0x41-0x5a 0x5f 0x61-0x7a}`},
+	{`\W`, `cc{0x0-0x2f 0x3a-0x40 0x5b-0x5e 0x60 0x7b-0x10ffff}`},
+	{`(?i)\w`, `cc{0x30-0x39 0x41-0x5a 0x5f 0x61-0x7a 0x17f 0x212a}`},
+	{`(?i)\W`, `cc{0x0-0x2f 0x3a-0x40 0x5b-0x5e 0x60 0x7b-0x17e 0x180-0x2129 0x212b-0x10ffff}`},
+	{`[^\\]`, `cc{0x0-0x5b 0x5d-0x10ffff}`},
+	//	{ `\C`, `byte{}` },  // probably never
 
 	// Unicode, negatives, and a double negative.
-	{"\\p{Braille}", "cc{0x2800-0x28ff}"},
-	{"\\P{Braille}", "cc{0x0-0x27ff 0x2900-0x10ffff}"},
-	{"\\p{^Braille}", "cc{0x0-0x27ff 0x2900-0x10ffff}"},
-	{"\\P{^Braille}", "cc{0x2800-0x28ff}"},
-	{"\\pZ", "cc{0x20 0xa0 0x1680 0x180e 0x2000-0x200a 0x2028-0x2029 0x202f 0x205f 0x3000}"},
-	{"[\\p{Braille}]", "cc{0x2800-0x28ff}"},
-	{"[\\P{Braille}]", "cc{0x0-0x27ff 0x2900-0x10ffff}"},
-	{"[\\p{^Braille}]", "cc{0x0-0x27ff 0x2900-0x10ffff}"},
-	{"[\\P{^Braille}]", "cc{0x2800-0x28ff}"},
-	{"[\\pZ]", "cc{0x20 0xa0 0x1680 0x180e 0x2000-0x200a 0x2028-0x2029 0x202f 0x205f 0x3000}"},
+	{`\p{Braille}`, `cc{0x2800-0x28ff}`},
+	{`\P{Braille}`, `cc{0x0-0x27ff 0x2900-0x10ffff}`},
+	{`\p{^Braille}`, `cc{0x0-0x27ff 0x2900-0x10ffff}`},
+	{`\P{^Braille}`, `cc{0x2800-0x28ff}`},
+	{`\pZ`, `cc{0x20 0xa0 0x1680 0x180e 0x2000-0x200a 0x2028-0x2029 0x202f 0x205f 0x3000}`},
+	{`[\p{Braille}]`, `cc{0x2800-0x28ff}`},
+	{`[\P{Braille}]`, `cc{0x0-0x27ff 0x2900-0x10ffff}`},
+	{`[\p{^Braille}]`, `cc{0x0-0x27ff 0x2900-0x10ffff}`},
+	{`[\P{^Braille}]`, `cc{0x2800-0x28ff}`},
+	{`[\pZ]`, `cc{0x20 0xa0 0x1680 0x180e 0x2000-0x200a 0x2028-0x2029 0x202f 0x205f 0x3000}`},
+	{`\p{Lu}`, mkCharClass(unicode.IsUpper)},
+	{`[\p{Lu}]`, mkCharClass(unicode.IsUpper)},
+	{`(?i)[\p{Lu}]`, mkCharClass(isUpperFold)},
+
+	// Hex, octal.
+	{`[\012-\234]\141`, `cat{cc{0xa-0x9c}lit{a}}`},
+	{`[\x{41}-\x7a]\x61`, `cat{cc{0x41-0x7a}lit{a}}`},
 
 	// More interesting regular expressions.
-	//	{ "a{,2}", "str{a{,2}}" },
-	//	{ "\\.\\^\\$\\\\", "str{.^$\\}" },
-	{"[a-zABC]", "cc{0x41-0x43 0x61-0x7a}"},
-	{"[^a]", "cc{0x0-0x60 0x62-0x10ffff}"},
-	{"[\xce\xb1-\xce\xb5\xe2\x98\xba]", "cc{0x3b1-0x3b5 0x263a}"}, // utf-8
-	{"a*{", "cat{star{lit{a}}lit{{}}"},
+	{`a{,2}`, `str{a{,2}}`},
+	{`\.\^\$\\`, `str{.^$\}`},
+	{`[a-zABC]`, `cc{0x41-0x43 0x61-0x7a}`},
+	{`[^a]`, `cc{0x0-0x60 0x62-0x10ffff}`},
+	{`[α-ε☺]`, `cc{0x3b1-0x3b5 0x263a}`}, // utf-8
+	{`a*{`, `cat{star{lit{a}}lit{{}}`},
 
 	// Test precedences
-	//	{ "(?:ab)*", "star{str{ab}}" },
-	//	{ "(ab)*", "star{cap{str{ab}}}" },
-	//	{ "ab|cd", "alt{str{ab}str{cd}}" },
-	//	{ "a(b|c)d", "cat{lit{a}cap{cc{0x62-0x63}}lit{d}}" },
-	{"(?:ab)*", "star{cat{lit{a}lit{b}}}"},
-	{"(ab)*", "star{cap{cat{lit{a}lit{b}}}}"},
-	{"ab|cd", "alt{cat{lit{a}lit{b}}cat{lit{c}lit{d}}}"},
-	{"a(b|c)d", "cat{lit{a}cap{alt{lit{b}lit{c}}}lit{d}}"},
+	{`(?:ab)*`, `star{str{ab}}`},
+	{`(ab)*`, `star{cap{str{ab}}}`},
+	{`ab|cd`, `alt{str{ab}str{cd}}`},
+	{`a(b|c)d`, `cat{lit{a}cap{cc{0x62-0x63}}lit{d}}`},
 
 	// Test flattening.
-	{"(?:a)", "lit{a}"},
-	//	{ "(?:ab)(?:cd)", "str{abcd}" },
-	//	{ "(?:a|b)|(?:c|d)", "cc{0x61-0x64}" },
-	//	{ "a|.", "dot{}" },
-	//	{ ".|a", "dot{}" },
+	{`(?:a)`, `lit{a}`},
+	{`(?:ab)(?:cd)`, `str{abcd}`},
+	{`(?:a+b+)(?:c+d+)`, `cat{plus{lit{a}}plus{lit{b}}plus{lit{c}}plus{lit{d}}}`},
+	{`(?:a+|b+)|(?:c+|d+)`, `alt{plus{lit{a}}plus{lit{b}}plus{lit{c}}plus{lit{d}}}`},
+	{`(?:a|b)|(?:c|d)`, `cc{0x61-0x64}`},
+	{`a|.`, `dot{}`},
+	{`.|a`, `dot{}`},
+	{`(?:[abc]|A|Z|hello|world)`, `alt{cc{0x41 0x5a 0x61-0x63}str{hello}str{world}}`},
+	{`(?:[abc]|A|Z)`, `cc{0x41 0x5a 0x61-0x63}`},
 
 	// Test Perl quoted literals
-	{"\\Q+|*?{[\\E", "str{+|*?{[}"},
-	{"\\Q+\\E+", "plus{lit{+}}"},
-	{"\\Q\\\\E", "lit{\\}"},
-	{"\\Q\\\\\\E", "str{\\\\}"},
+	{`\Q+|*?{[\E`, `str{+|*?{[}`},
+	{`\Q+\E+`, `plus{lit{+}}`},
+	{`\Q\\E`, `lit{\}`},
+	{`\Q\\\E`, `str{\\}`},
 
 	// Test Perl \A and \z
-	{"(?m)^", "bol{}"},
-	{"(?m)$", "eol{}"},
-	{"(?-m)^", "bot{}"},
-	{"(?-m)$", "eot{}"},
-	{"(?m)\\A", "bot{}"},
-	{"(?m)\\z", "eot{\\z}"},
-	{"(?-m)\\A", "bot{}"},
-	{"(?-m)\\z", "eot{\\z}"},
+	{`(?m)^`, `bol{}`},
+	{`(?m)$`, `eol{}`},
+	{`(?-m)^`, `bot{}`},
+	{`(?-m)$`, `eot{}`},
+	{`(?m)\A`, `bot{}`},
+	{`(?m)\z`, `eot{\z}`},
+	{`(?-m)\A`, `bot{}`},
+	{`(?-m)\z`, `eot{\z}`},
 
 	// Test named captures
-	{"(?P<name>a)", "cap{name:lit{a}}"},
+	{`(?P<name>a)`, `cap{name:lit{a}}`},
 
 	// Case-folded literals
-	//	{ "[Aa]", "litfold{a}" },
+	{`[Aa]`, `litfold{A}`},
+	{`[\x{100}\x{101}]`, `litfold{Ā}`},
+	{`[Δδ]`, `litfold{Δ}`},
 
 	// Strings
-	//	{ "abcde", "str{abcde}" },
-	//	{ "[Aa][Bb]cd", "cat{strfold{ab}str{cd}}" },
+	{`abcde`, `str{abcde}`},
+	{`[Aa][Bb]cd`, `cat{strfold{AB}str{cd}}`},
+
+	// Factoring.
+	{`abc|abd|aef|bcx|bcy`, `alt{cat{lit{a}alt{cat{lit{b}cc{0x63-0x64}}str{ef}}}cat{str{bc}cc{0x78-0x79}}}`},
+	{`ax+y|ax+z|ay+w`, `cat{lit{a}alt{cat{plus{lit{x}}cc{0x79-0x7a}}cat{plus{lit{y}}lit{w}}}}`},
 }
 
 const testFlags = MatchNL | PerlX | UnicodeGroups
@@ -223,8 +234,9 @@ func dumpRegexp(b *bytes.Buffer, re *Regexp) {
 			}
 			if re.Flags&FoldCase != 0 {
 				for _, r := range re.Rune {
-					if unicode.ToUpper(r) != r {
+					if unicode.SimpleFold(r) != r {
 						b.WriteString("fold")
+						break
 					}
 				}
 			}
@@ -270,3 +282,69 @@ func dumpRegexp(b *bytes.Buffer, re *Regexp) {
 	}
 	b.WriteByte('}')
 }
+
+func mkCharClass(f func(int) bool) string {
+	re := &Regexp{Op: OpCharClass}
+	lo := -1
+	for i := 0; i <= unicode.MaxRune; i++ {
+		if f(i) {
+			if lo < 0 {
+				lo = i
+			}
+		} else {
+			if lo >= 0 {
+				re.Rune = append(re.Rune, lo, i-1)
+				lo = -1
+			}
+		}
+	}
+	if lo >= 0 {
+		re.Rune = append(re.Rune, lo, unicode.MaxRune)
+	}
+	return dump(re)
+}
+
+func isUpperFold(rune int) bool {
+	if unicode.IsUpper(rune) {
+		return true
+	}
+	c := unicode.SimpleFold(rune)
+	for c != rune {
+		if unicode.IsUpper(c) {
+			return true
+		}
+		c = unicode.SimpleFold(c)
+	}
+	return false
+}
+
+func TestFoldConstants(t *testing.T) {
+	last := -1
+	for i := 0; i <= unicode.MaxRune; i++ {
+		if unicode.SimpleFold(i) == i {
+			continue
+		}
+		if last == -1 && minFold != i {
+			t.Errorf("minFold=%#U should be %#U", minFold, i)
+		}
+		last = i
+	}
+	if maxFold != last {
+		t.Errorf("maxFold=%#U should be %#U", maxFold, last)
+	}
+}
+
+func TestAppendRangeCollapse(t *testing.T) {
+	// AppendRange should collapse each of the new ranges
+	// into the earlier ones (it looks back two ranges), so that
+	// the slice never grows very large.
+	// Note that we are not calling cleanClass.
+	var r []int
+	for i := 'A'; i <= 'Z'; i++ {
+		r = appendRange(r, i, i)
+		r = appendRange(r, i+'a'-'A', i+'a'-'A')
+	}
+	if string(r) != "AZaz" {
+		t.Errorf("appendRange interlaced A-Z a-z = %s, want AZaz", string(r))
+	}
+}
diff --git a/src/pkg/exp/regexp/syntax/prog.go b/src/pkg/exp/regexp/syntax/prog.go
new file mode 100644
index 0000000..6eeb3da
--- /dev/null
+++ b/src/pkg/exp/regexp/syntax/prog.go
@@ -0,0 +1,182 @@
+package syntax
+
+import (
+	"bytes"
+	"strconv"
+)
+
+// Compiled program.
+// May not belong in this package, but convenient for now.
+
+// A Prog is a compiled regular expression program.
+type Prog struct {
+	Inst  []Inst
+	Start int // index of start instruction
+}
+
+// An InstOp is an instruction opcode.
+type InstOp uint8
+
+const (
+	InstAlt InstOp = iota
+	InstAltMatch
+	InstCapture
+	InstEmptyWidth
+	InstMatch
+	InstFail
+	InstNop
+	InstRune
+)
+
+// An EmptyOp specifies a kind or mixture of zero-width assertions.
+type EmptyOp uint8
+
+const (
+	EmptyBeginLine EmptyOp = 1 << iota
+	EmptyEndLine
+	EmptyBeginText
+	EmptyEndText
+	EmptyWordBoundary
+	EmptyNoWordBoundary
+)
+
+// An Inst is a single instruction in a regular expression program.
+type Inst struct {
+	Op   InstOp
+	Out  uint32 // all but InstMatch, InstFail
+	Arg  uint32 // InstAlt, InstAltMatch, InstCapture, InstEmptyWidth
+	Rune []int
+}
+
+func (p *Prog) String() string {
+	var b bytes.Buffer
+	dumpProg(&b, p)
+	return b.String()
+}
+
+// MatchRune returns true if the instruction matches (and consumes) r.
+// It should only be called when i.Op == InstRune.
+func (i *Inst) MatchRune(r int) bool {
+	rune := i.Rune
+
+	// Special case: single-rune slice is from literal string, not char class.
+	// TODO: Case folding.
+	if len(rune) == 1 {
+		return r == rune[0]
+	}
+
+	// Peek at the first few pairs.
+	// Should handle ASCII well.
+	for j := 0; j < len(rune) && j <= 8; j += 2 {
+		if r < rune[j] {
+			return false
+		}
+		if r <= rune[j+1] {
+			return true
+		}
+	}
+
+	// Otherwise binary search.
+	lo := 0
+	hi := len(rune) / 2
+	for lo < hi {
+		m := lo + (hi-lo)/2
+		if c := rune[2*m]; c <= r {
+			if r <= rune[2*m+1] {
+				return true
+			}
+			lo = m + 1
+		} else {
+			hi = m
+		}
+	}
+	return false
+}
+
+// As per re2's Prog::IsWordChar. Determines whether rune is an ASCII word char.
+// Since we act on runes, it would be easy to support Unicode here.
+func wordRune(rune int) bool {
+	return rune == '_' ||
+		('A' <= rune && rune <= 'Z') ||
+		('a' <= rune && rune <= 'z') ||
+		('0' <= rune && rune <= '9')
+}
+
+// MatchEmptyWidth returns true if the instruction matches
+// an empty string between the runes before and after.
+// It should only be called when i.Op == InstEmptyWidth.
+func (i *Inst) MatchEmptyWidth(before int, after int) bool {
+	switch EmptyOp(i.Arg) {
+	case EmptyBeginLine:
+		return before == '\n' || before == -1
+	case EmptyEndLine:
+		return after == '\n' || after == -1
+	case EmptyBeginText:
+		return before == -1
+	case EmptyEndText:
+		return after == -1
+	case EmptyWordBoundary:
+		return wordRune(before) != wordRune(after)
+	case EmptyNoWordBoundary:
+		return wordRune(before) == wordRune(after)
+	}
+	panic("unknown empty width arg")
+}
+
+
+func (i *Inst) String() string {
+	var b bytes.Buffer
+	dumpInst(&b, i)
+	return b.String()
+}
+
+func bw(b *bytes.Buffer, args ...string) {
+	for _, s := range args {
+		b.WriteString(s)
+	}
+}
+
+func dumpProg(b *bytes.Buffer, p *Prog) {
+	for j := range p.Inst {
+		i := &p.Inst[j]
+		pc := strconv.Itoa(j)
+		if len(pc) < 3 {
+			b.WriteString("   "[len(pc):])
+		}
+		if j == p.Start {
+			pc += "*"
+		}
+		bw(b, pc, "\t")
+		dumpInst(b, i)
+		bw(b, "\n")
+	}
+}
+
+func u32(i uint32) string {
+	return strconv.Uitoa64(uint64(i))
+}
+
+func dumpInst(b *bytes.Buffer, i *Inst) {
+	switch i.Op {
+	case InstAlt:
+		bw(b, "alt -> ", u32(i.Out), ", ", u32(i.Arg))
+	case InstAltMatch:
+		bw(b, "altmatch -> ", u32(i.Out), ", ", u32(i.Arg))
+	case InstCapture:
+		bw(b, "cap ", u32(i.Arg), " -> ", u32(i.Out))
+	case InstEmptyWidth:
+		bw(b, "empty ", u32(i.Arg), " -> ", u32(i.Out))
+	case InstMatch:
+		bw(b, "match")
+	case InstFail:
+		bw(b, "fail")
+	case InstNop:
+		bw(b, "nop -> ", u32(i.Out))
+	case InstRune:
+		if i.Rune == nil {
+			// shouldn't happen
+			bw(b, "rune <nil>")
+		}
+		bw(b, "rune ", strconv.QuoteToASCII(string(i.Rune)), " -> ", u32(i.Out))
+	}
+}
diff --git a/src/pkg/exp/regexp/syntax/prog_test.go b/src/pkg/exp/regexp/syntax/prog_test.go
new file mode 100644
index 0000000..7be4281
--- /dev/null
+++ b/src/pkg/exp/regexp/syntax/prog_test.go
@@ -0,0 +1,91 @@
+package syntax
+
+import (
+	"testing"
+)
+
+var compileTests = []struct {
+	Regexp string
+	Prog   string
+}{
+	{"a", `  0	fail
+  1*	rune "a" -> 2
+  2	match
+`},
+	{"[A-M][n-z]", `  0	fail
+  1*	rune "AM" -> 2
+  2	rune "nz" -> 3
+  3	match
+`},
+	{"", `  0	fail
+  1*	nop -> 2
+  2	match
+`},
+	{"a?", `  0	fail
+  1	rune "a" -> 3
+  2*	alt -> 1, 3
+  3	match
+`},
+	{"a??", `  0	fail
+  1	rune "a" -> 3
+  2*	alt -> 3, 1
+  3	match
+`},
+	{"a+", `  0	fail
+  1*	rune "a" -> 2
+  2	alt -> 1, 3
+  3	match
+`},
+	{"a+?", `  0	fail
+  1*	rune "a" -> 2
+  2	alt -> 3, 1
+  3	match
+`},
+	{"a*", `  0	fail
+  1	rune "a" -> 2
+  2*	alt -> 1, 3
+  3	match
+`},
+	{"a*?", `  0	fail
+  1	rune "a" -> 2
+  2*	alt -> 3, 1
+  3	match
+`},
+	{"a+b+", `  0	fail
+  1*	rune "a" -> 2
+  2	alt -> 1, 3
+  3	rune "b" -> 4
+  4	alt -> 3, 5
+  5	match
+`},
+	{"(a+)(b+)", `  0	fail
+  1*	cap 2 -> 2
+  2	rune "a" -> 3
+  3	alt -> 2, 4
+  4	cap 3 -> 5
+  5	cap 4 -> 6
+  6	rune "b" -> 7
+  7	alt -> 6, 8
+  8	cap 5 -> 9
+  9	match
+`},
+	{"a+|b+", `  0	fail
+  1	rune "a" -> 2
+  2	alt -> 1, 6
+  3	rune "b" -> 4
+  4	alt -> 3, 6
+  5*	alt -> 1, 3
+  6	match
+`},
+}
+
+func TestCompile(t *testing.T) {
+	for _, tt := range compileTests {
+		re, _ := Parse(tt.Regexp, Perl)
+		p, _ := Compile(re)
+		s := p.String()
+		if s != tt.Prog {
+			t.Errorf("compiled %#q:\n--- have\n%s---\n--- want\n%s---", tt.Regexp, s, tt.Prog)
+		}
+	}
+}
diff --git a/src/pkg/exp/regexp/syntax/regexp.go b/src/pkg/exp/regexp/syntax/regexp.go
index a0c4659..00a4add 100644
--- a/src/pkg/exp/regexp/syntax/regexp.go
+++ b/src/pkg/exp/regexp/syntax/regexp.go
@@ -33,6 +33,8 @@ type Regexp struct {
 type Op uint8
 
 // Operators are listed in precedence order, tightest binding to weakest.
+// Character class operators are listed simplest to most complex
+// (OpLiteral, OpCharClass, OpAnyCharNotNL, OpAnyChar).
 
 const (
 	OpNoMatch        Op = 1 + iota // matches no strings
@@ -58,6 +60,59 @@ const (
 
 const opPseudo Op = 128 // where pseudo-ops start
 
+// Equal returns true if x and y have identical structure.
+func (x *Regexp) Equal(y *Regexp) bool {
+	if x == nil || y == nil {
+		return x == y
+	}
+	if x.Op != y.Op {
+		return false
+	}
+	switch x.Op {
+	case OpEndText:
+		// The parse flags remember whether this is \z or \Z.
+		if x.Flags&WasDollar != y.Flags&WasDollar {
+			return false
+		}
+
+	case OpLiteral, OpCharClass:
+		if len(x.Rune) != len(y.Rune) {
+			return false
+		}
+		for i, r := range x.Rune {
+			if r != y.Rune[i] {
+				return false
+			}
+		}
+
+	case OpAlternate, OpConcat:
+		if len(x.Sub) != len(y.Sub) {
+			return false
+		}
+		for i, sub := range x.Sub {
+			if !sub.Equal(y.Sub[i]) {
+				return false
+			}
+		}
+
+	case OpStar, OpPlus, OpQuest:
+		if x.Flags&NonGreedy != y.Flags&NonGreedy || !x.Sub[0].Equal(y.Sub[0]) {
+			return false
+		}
+
+	case OpRepeat:
+		if x.Flags&NonGreedy != y.Flags&NonGreedy || x.Min != y.Min || x.Max != y.Max || !x.Sub[0].Equal(y.Sub[0]) {
+			return false
+		}
+
+	case OpCapture:
+		if x.Cap != y.Cap || x.Name != y.Name || !x.Sub[0].Equal(y.Sub[0]) {
+			return false
+		}
+	}
+	return true
+}
+
 // writeRegexp writes the Perl syntax for the regular expression re to b.
 func writeRegexp(b *bytes.Buffer, re *Regexp) {
 	switch re.Op {
@@ -68,16 +123,24 @@ func writeRegexp(b *bytes.Buffer, re *Regexp) {
 	case OpEmptyMatch:
 		b.WriteString(`(?:)`)
 	case OpLiteral:
+		if re.Flags&FoldCase != 0 {
+			b.WriteString(`(?i:`)
+		}
 		for _, r := range re.Rune {
 			escape(b, r, false)
 		}
+		if re.Flags&FoldCase != 0 {
+			b.WriteString(`)`)
+		}
 	case OpCharClass:
 		if len(re.Rune)%2 != 0 {
 			b.WriteString(`[invalid char class]`)
 			break
 		}
 		b.WriteRune('[')
-		if len(re.Rune) > 0 && re.Rune[0] == 0 && re.Rune[len(re.Rune)-1] == unicode.MaxRune {
+		if len(re.Rune) == 0 {
+			b.WriteString(`^\x00-\x{10FFFF}`)
+		} else if re.Rune[0] == 0 && re.Rune[len(re.Rune)-1] == unicode.MaxRune {
 			// Contains 0 and MaxRune.  Probably a negated class.
 			// Print the gaps.
 			b.WriteRune('^')
@@ -124,7 +187,9 @@ func writeRegexp(b *bytes.Buffer, re *Regexp) {
 		} else {
 			b.WriteRune('(')
 		}
-		writeRegexp(b, re.Sub[0])
+		if re.Sub[0].Op != OpEmptyMatch {
+			writeRegexp(b, re.Sub[0])
+		}
 		b.WriteRune(')')
 	case OpStar, OpPlus, OpQuest, OpRepeat:
 		if sub := re.Sub[0]; sub.Op > OpCapture {
@@ -203,6 +268,15 @@ func escape(b *bytes.Buffer, r int, force bool) {
 	case '\v':
 		b.WriteString(`\v`)
 	default:
+		if r < 0x100 {
+			b.WriteString(`\x`)
+			s := strconv.Itob(r, 16)
+			if len(s) == 1 {
+				b.WriteRune('0')
+			}
+			b.WriteString(s)
+			break
+		}
 		b.WriteString(`\x{`)
 		b.WriteString(strconv.Itob(r, 16))
 		b.WriteString(`}`)
diff --git a/src/pkg/exp/regexp/syntax/simplify.go b/src/pkg/exp/regexp/syntax/simplify.go
new file mode 100644
index 0000000..7239041
--- /dev/null
+++ b/src/pkg/exp/regexp/syntax/simplify.go
@@ -0,0 +1,151 @@
+// 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 syntax
+
+// Simplify returns a regexp equivalent to re but without counted repetitions
+// and with various other simplifications, such as rewriting /(?:a+)+/ to /a+/.
+// The resulting regexp will execute correctly but its string representation
+// will not produce the same parse tree, because capturing parentheses
+// may have been duplicated or removed.  For example, the simplified form
+// for /(x){1,2}/ is /(x)(x)?/ but both parentheses capture as $1.
+// The returned regexp may share structure with or be the original.
+func (re *Regexp) Simplify() *Regexp {
+	if re == nil {
+		return nil
+	}
+	switch re.Op {
+	case OpCapture, OpConcat, OpAlternate:
+		// Simplify children, building new Regexp if children change.
+		nre := re
+		for i, sub := range re.Sub {
+			nsub := sub.Simplify()
+			if nre == re && nsub != sub {
+				// Start a copy.
+				nre = new(Regexp)
+				*nre = *re
+				nre.Rune = nil
+				nre.Sub = append(nre.Sub0[:0], re.Sub[:i]...)
+			}
+			if nre != re {
+				nre.Sub = append(nre.Sub, nsub)
+			}
+		}
+		return nre
+
+	case OpStar, OpPlus, OpQuest:
+		sub := re.Sub[0].Simplify()
+		return simplify1(re.Op, re.Flags, sub, re)
+
+	case OpRepeat:
+		// Special special case: x{0} matches the empty string
+		// and doesn't even need to consider x.
+		if re.Min == 0 && re.Max == 0 {
+			return &Regexp{Op: OpEmptyMatch}
+		}
+
+		// The fun begins.
+		sub := re.Sub[0].Simplify()
+
+		// x{n,} means at least n matches of x.
+		if re.Max == -1 {
+			// Special case: x{0,} is x*.
+			if re.Min == 0 {
+				return simplify1(OpStar, re.Flags, sub, nil)
+			}
+
+			// Special case: x{1,} is x+.
+			if re.Min == 1 {
+				return simplify1(OpPlus, re.Flags, sub, nil)
+			}
+
+			// General case: x{4,} is xxxx+.
+			nre := &Regexp{Op: OpConcat}
+			nre.Sub = nre.Sub0[:0]
+			for i := 0; i < re.Min-1; i++ {
+				nre.Sub = append(nre.Sub, sub)
+			}
+			nre.Sub = append(nre.Sub, simplify1(OpPlus, re.Flags, sub, nil))
+			return nre
+		}
+
+		// Special case x{0} handled above.
+
+		// Special case: x{1} is just x.
+		if re.Min == 1 && re.Max == 1 {
+			return sub
+		}
+
+		// General case: x{n,m} means n copies of x and m copies of x?
+		// The machine will do less work if we nest the final m copies,
+		// so that x{2,5} = xx(x(x(x)?)?)?
+
+		// Build leading prefix: xx.
+		var prefix *Regexp
+		if re.Min > 0 {
+			prefix = &Regexp{Op: OpConcat}
+			prefix.Sub = prefix.Sub0[:0]
+			for i := 0; i < re.Min; i++ {
+				prefix.Sub = append(prefix.Sub, sub)
+			}
+		}
+
+		// Build and attach suffix: (x(x(x)?)?)?
+		if re.Max > re.Min {
+			suffix := simplify1(OpQuest, re.Flags, sub, nil)
+			for i := re.Min + 1; i < re.Max; i++ {
+				nre2 := &Regexp{Op: OpConcat}
+				nre2.Sub = append(nre2.Sub0[:0], sub, suffix)
+				suffix = simplify1(OpQuest, re.Flags, nre2, nil)
+			}
+			if prefix == nil {
+				return suffix
+			}
+			prefix.Sub = append(prefix.Sub, suffix)
+		}
+		if prefix != nil {
+			return prefix
+		}
+
+		// Some degenerate case like min > max or min < max < 0.
+		// Handle as impossible match.
+		return &Regexp{Op: OpNoMatch}
+	}
+
+	return re
+}
+
+// simplify1 implements Simplify for the unary OpStar,
+// OpPlus, and OpQuest operators.  It returns the simple regexp
+// equivalent to
+//
+//	Regexp{Op: op, Flags: flags, Sub: {sub}}
+//
+// under the assumption that sub is already simple, and
+// without first allocating that structure.  If the regexp
+// to be returned turns out to be equivalent to re, simplify1
+// returns re instead.
+//
+// simplify1 is factored out of Simplify because the implementation
+// for other operators generates these unary expressions.
+// Letting them call simplify1 makes sure the expressions they
+// generate are simple.
+func simplify1(op Op, flags Flags, sub, re *Regexp) *Regexp {
+	// Special case: repeat the empty string as much as
+	// you want, but it's still the empty string.
+	if sub.Op == OpEmptyMatch {
+		return sub
+	}
+	// The operators are idempotent if the flags match.
+	if op == sub.Op && flags&NonGreedy == sub.Flags&NonGreedy {
+		return sub
+	}
+	if re != nil && re.Op == op && re.Flags&NonGreedy == flags&NonGreedy && sub == re.Sub[0] {
+		return re
+	}
+
+	re = &Regexp{Op: op, Flags: flags}
+	re.Sub = append(re.Sub0[:0], sub)
+	return re
+}
diff --git a/src/pkg/exp/regexp/syntax/simplify_test.go b/src/pkg/exp/regexp/syntax/simplify_test.go
new file mode 100644
index 0000000..c8cec21
--- /dev/null
+++ b/src/pkg/exp/regexp/syntax/simplify_test.go
@@ -0,0 +1,151 @@
+// 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 syntax
+
+import "testing"
+
+var simplifyTests = []struct {
+	Regexp string
+	Simple string
+}{
+	// Already-simple constructs
+	{`a`, `a`},
+	{`ab`, `ab`},
+	{`a|b`, `[a-b]`},
+	{`ab|cd`, `ab|cd`},
+	{`(ab)*`, `(ab)*`},
+	{`(ab)+`, `(ab)+`},
+	{`(ab)?`, `(ab)?`},
+	{`.`, `.`},
+	{`^`, `^`},
+	{`$`, `$`},
+	{`[ac]`, `[ac]`},
+	{`[^ac]`, `[^ac]`},
+
+	// Posix character classes
+	{`[[:alnum:]]`, `[0-9A-Za-z]`},
+	{`[[:alpha:]]`, `[A-Za-z]`},
+	{`[[:blank:]]`, `[\t ]`},
+	{`[[:cntrl:]]`, `[\x00-\x1f\x7f]`},
+	{`[[:digit:]]`, `[0-9]`},
+	{`[[:graph:]]`, `[!-~]`},
+	{`[[:lower:]]`, `[a-z]`},
+	{`[[:print:]]`, `[ -~]`},
+	{`[[:punct:]]`, "[!-/:-@\\[-`\\{-~]"},
+	{`[[:space:]]`, `[\t-\r ]`},
+	{`[[:upper:]]`, `[A-Z]`},
+	{`[[:xdigit:]]`, `[0-9A-Fa-f]`},
+
+	// Perl character classes
+	{`\d`, `[0-9]`},
+	{`\s`, `[\t-\n\f-\r ]`},
+	{`\w`, `[0-9A-Z_a-z]`},
+	{`\D`, `[^0-9]`},
+	{`\S`, `[^\t-\n\f-\r ]`},
+	{`\W`, `[^0-9A-Z_a-z]`},
+	{`[\d]`, `[0-9]`},
+	{`[\s]`, `[\t-\n\f-\r ]`},
+	{`[\w]`, `[0-9A-Z_a-z]`},
+	{`[\D]`, `[^0-9]`},
+	{`[\S]`, `[^\t-\n\f-\r ]`},
+	{`[\W]`, `[^0-9A-Z_a-z]`},
+
+	// Posix repetitions
+	{`a{1}`, `a`},
+	{`a{2}`, `aa`},
+	{`a{5}`, `aaaaa`},
+	{`a{0,1}`, `a?`},
+	// The next three are illegible because Simplify inserts (?:)
+	// parens instead of () parens to avoid creating extra
+	// captured subexpressions.  The comments show a version with fewer parens.
+	{`(a){0,2}`, `(?:(a)(a)?)?`},                       //       (aa?)?
+	{`(a){0,4}`, `(?:(a)(?:(a)(?:(a)(a)?)?)?)?`},       //   (a(a(aa?)?)?)?
+	{`(a){2,6}`, `(a)(a)(?:(a)(?:(a)(?:(a)(a)?)?)?)?`}, // aa(a(a(aa?)?)?)?
+	{`a{0,2}`, `(?:aa?)?`},                             //       (aa?)?
+	{`a{0,4}`, `(?:a(?:a(?:aa?)?)?)?`},                 //   (a(a(aa?)?)?)?
+	{`a{2,6}`, `aa(?:a(?:a(?:aa?)?)?)?`},               // aa(a(a(aa?)?)?)?
+	{`a{0,}`, `a*`},
+	{`a{1,}`, `a+`},
+	{`a{2,}`, `aa+`},
+	{`a{5,}`, `aaaaa+`},
+
+	// Test that operators simplify their arguments.
+	{`(?:a{1,}){1,}`, `a+`},
+	{`(a{1,}b{1,})`, `(a+b+)`},
+	{`a{1,}|b{1,}`, `a+|b+`},
+	{`(?:a{1,})*`, `(?:a+)*`},
+	{`(?:a{1,})+`, `a+`},
+	{`(?:a{1,})?`, `(?:a+)?`},
+	{``, `(?:)`},
+	{`a{0}`, `(?:)`},
+
+	// Character class simplification
+	{`[ab]`, `[a-b]`},
+	{`[a-za-za-z]`, `[a-z]`},
+	{`[A-Za-zA-Za-z]`, `[A-Za-z]`},
+	{`[ABCDEFGH]`, `[A-H]`},
+	{`[AB-CD-EF-GH]`, `[A-H]`},
+	{`[W-ZP-XE-R]`, `[E-Z]`},
+	{`[a-ee-gg-m]`, `[a-m]`},
+	{`[a-ea-ha-m]`, `[a-m]`},
+	{`[a-ma-ha-e]`, `[a-m]`},
+	{`[a-zA-Z0-9 -~]`, `[ -~]`},
+
+	// Empty character classes
+	{`[^[:cntrl:][:^cntrl:]]`, `[^\x00-\x{10FFFF}]`},
+
+	// Full character classes
+	{`[[:cntrl:][:^cntrl:]]`, `.`},
+
+	// Unicode case folding.
+	{`(?i)A`, `(?i:A)`},
+	{`(?i)a`, `(?i:a)`},
+	{`(?i)[A]`, `(?i:A)`},
+	{`(?i)[a]`, `(?i:A)`},
+	{`(?i)K`, `(?i:K)`},
+	{`(?i)k`, `(?i:k)`},
+	{`(?i)\x{212a}`, "(?i:\u212A)"},
+	{`(?i)[K]`, "[Kk\u212A]"},
+	{`(?i)[k]`, "[Kk\u212A]"},
+	{`(?i)[\x{212a}]`, "[Kk\u212A]"},
+	{`(?i)[a-z]`, "[A-Za-z\u017F\u212A]"},
+	{`(?i)[\x00-\x{FFFD}]`, "[\\x00-\uFFFD]"},
+	{`(?i)[\x00-\x{10FFFF}]`, `.`},
+
+	// Empty string as a regular expression.
+	// The empty string must be preserved inside parens in order
+	// to make submatches work right, so these tests are less
+	// interesting than they might otherwise be.  String inserts
+	// explicit (?:) in place of non-parenthesized empty strings,
+	// to make them easier to spot for other parsers.
+	{`(a|b|)`, `([a-b]|(?:))`},
+	{`(|)`, `()`},
+	{`a()`, `a()`},
+	{`(()|())`, `(()|())`},
+	{`(a|)`, `(a|(?:))`},
+	{`ab()cd()`, `ab()cd()`},
+	{`()`, `()`},
+	{`()*`, `()*`},
+	{`()+`, `()+`},
+	{`()?`, `()?`},
+	{`(){0}`, `(?:)`},
+	{`(){1}`, `()`},
+	{`(){1,}`, `()+`},
+	{`(){0,2}`, `(?:()()?)?`},
+}
+
+func TestSimplify(t *testing.T) {
+	for _, tt := range simplifyTests {
+		re, err := Parse(tt.Regexp, MatchNL|Perl&^OneLine)
+		if err != nil {
+			t.Errorf("Parse(%#q) = error %v", tt.Regexp, err)
+			continue
+		}
+		s := re.Simplify().String()
+		if s != tt.Simple {
+			t.Errorf("Simplify(%#q) = %#q, want %#q", tt.Regexp, s, tt.Simple)
+		}
+	}
+}
diff --git a/src/pkg/exp/template/Makefile b/src/pkg/exp/template/Makefile
index ab9832f..8550b0d 100644
--- a/src/pkg/exp/template/Makefile
+++ b/src/pkg/exp/template/Makefile
@@ -4,9 +4,12 @@
 
 include ../../../Make.inc
 
-TARG=template
+TARG=exp/template
 GOFILES=\
+	exec.go\
+	funcs.go\
 	lex.go\
 	parse.go\
+	set.go\
 
 include ../../../Make.pkg
diff --git a/src/pkg/exp/template/exec.go b/src/pkg/exp/template/exec.go
new file mode 100644
index 0000000..fb0a9e6
--- /dev/null
+++ b/src/pkg/exp/template/exec.go
@@ -0,0 +1,508 @@
+// 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 template
+
+import (
+	"fmt"
+	"io"
+	"os"
+	"reflect"
+	"strings"
+	"unicode"
+	"utf8"
+)
+
+// state represents the state of an execution. It's not part of the
+// template so that multiple executions of the same template
+// can execute in parallel.
+type state struct {
+	tmpl *Template
+	wr   io.Writer
+	set  *Set
+	line int // line number for errors
+}
+
+// errorf formats the error and terminates processing.
+func (s *state) errorf(format string, args ...interface{}) {
+	format = fmt.Sprintf("template: %s:%d: %s", s.tmpl.name, s.line, format)
+	panic(fmt.Errorf(format, args...))
+}
+
+// error terminates processing.
+func (s *state) error(err os.Error) {
+	s.errorf("%s", err)
+}
+
+// Execute applies a parsed template to the specified data object,
+// writing the output to wr.
+func (t *Template) Execute(wr io.Writer, data interface{}) os.Error {
+	return t.ExecuteInSet(wr, data, nil)
+}
+
+// ExecuteInSet applies a parsed template to the specified data object,
+// writing the output to wr. Nested template invocations will be resolved
+// from the specified set.
+func (t *Template) ExecuteInSet(wr io.Writer, data interface{}, set *Set) (err os.Error) {
+	defer t.recover(&err)
+	state := &state{
+		tmpl: t,
+		wr:   wr,
+		set:  set,
+		line: 1,
+	}
+	if t.root == nil {
+		state.errorf("must be parsed before execution")
+	}
+	state.walk(reflect.ValueOf(data), t.root)
+	return
+}
+
+// Walk functions step through the major pieces of the template structure,
+// generating output as they go.
+func (s *state) walk(data reflect.Value, n node) {
+	switch n := n.(type) {
+	case *actionNode:
+		s.line = n.line
+		s.printValue(n, s.evalPipeline(data, n.pipeline))
+	case *listNode:
+		for _, node := range n.nodes {
+			s.walk(data, node)
+		}
+	case *ifNode:
+		s.line = n.line
+		s.walkIfOrWith(nodeIf, data, n.pipeline, n.list, n.elseList)
+	case *rangeNode:
+		s.line = n.line
+		s.walkRange(data, n)
+	case *textNode:
+		if _, err := s.wr.Write(n.text); err != nil {
+			s.error(err)
+		}
+	case *templateNode:
+		s.line = n.line
+		s.walkTemplate(data, n)
+	case *withNode:
+		s.line = n.line
+		s.walkIfOrWith(nodeWith, data, n.pipeline, n.list, n.elseList)
+	default:
+		s.errorf("unknown node: %s", n)
+	}
+}
+
+// walkIfOrWith walks an 'if' or 'with' node. The two control structures
+// are identical in behavior except that 'with' sets dot.
+func (s *state) walkIfOrWith(typ nodeType, data reflect.Value, pipe []*commandNode, list, elseList *listNode) {
+	val := s.evalPipeline(data, pipe)
+	truth, ok := isTrue(val)
+	if !ok {
+		s.errorf("if/with can't use value of type %T", val.Interface())
+	}
+	if truth {
+		if typ == nodeWith {
+			data = val
+		}
+		s.walk(data, list)
+	} else if elseList != nil {
+		s.walk(data, elseList)
+	}
+}
+
+// isTrue returns whether the value is 'true', in the sense of not the zero of its type,
+// and whether the value has a meaningful truth value.
+func isTrue(val reflect.Value) (truth, ok bool) {
+	switch val.Kind() {
+	case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
+		truth = val.Len() > 0
+	case reflect.Bool:
+		truth = val.Bool()
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		truth = val.Int() != 0
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+		truth = val.Uint() != 0
+	case reflect.Float32, reflect.Float64:
+		truth = val.Float() != 0
+	case reflect.Complex64, reflect.Complex128:
+		truth = val.Complex() != 0
+	case reflect.Chan, reflect.Func, reflect.Ptr:
+		truth = !val.IsNil()
+	default:
+		return
+	}
+	return truth, true
+}
+
+func (s *state) walkRange(data reflect.Value, r *rangeNode) {
+	val := s.evalPipeline(data, r.pipeline)
+	switch val.Kind() {
+	case reflect.Array, reflect.Slice:
+		if val.Len() == 0 {
+			break
+		}
+		for i := 0; i < val.Len(); i++ {
+			s.walk(val.Index(i), r.list)
+		}
+		return
+	case reflect.Map:
+		if val.Len() == 0 {
+			break
+		}
+		for _, key := range val.MapKeys() {
+			s.walk(val.MapIndex(key), r.list)
+		}
+		return
+	default:
+		s.errorf("range can't iterate over value of type %T", val.Interface())
+	}
+	if r.elseList != nil {
+		s.walk(data, r.elseList)
+	}
+}
+
+func (s *state) walkTemplate(data reflect.Value, t *templateNode) {
+	name := s.evalArg(data, reflect.TypeOf("string"), t.name).String()
+	if s.set == nil {
+		s.errorf("no set defined in which to invoke template named %q", name)
+	}
+	tmpl := s.set.tmpl[name]
+	if tmpl == nil {
+		s.errorf("template %q not in set", name)
+	}
+	data = s.evalPipeline(data, t.pipeline)
+	newState := *s
+	newState.tmpl = tmpl
+	newState.walk(data, tmpl.root)
+}
+
+// Eval functions evaluate pipelines, commands, and their elements and extract
+// values from the data structure by examining fields, calling methods, and so on.
+// The printing of those values happens only through walk functions.
+
+func (s *state) evalPipeline(data reflect.Value, pipe []*commandNode) reflect.Value {
+	value := reflect.Value{}
+	for _, cmd := range pipe {
+		value = s.evalCommand(data, cmd, value) // previous value is this one's final arg.
+		// If the object has type interface{}, dig down one level to the thing inside.
+		if value.Kind() == reflect.Interface && value.Type().NumMethod() == 0 {
+			value = reflect.ValueOf(value.Interface()) // lovely!
+		}
+	}
+	return value
+}
+
+func (s *state) evalCommand(data reflect.Value, cmd *commandNode, final reflect.Value) reflect.Value {
+	firstWord := cmd.args[0]
+	switch n := firstWord.(type) {
+	case *fieldNode:
+		return s.evalFieldNode(data, n, cmd.args, final)
+	case *identifierNode:
+		return s.evalFieldOrCall(data, n.ident, cmd.args, final)
+	}
+	if len(cmd.args) > 1 || final.IsValid() {
+		s.errorf("can't give argument to non-function %s", cmd.args[0])
+	}
+	switch word := cmd.args[0].(type) {
+	case *dotNode:
+		return data
+	case *boolNode:
+		return reflect.ValueOf(word.true)
+	case *numberNode:
+		// These are ideal constants but we don't know the type
+		// and we have no context.  (If it was a method argument,
+		// we'd know what we need.) The syntax guides us to some extent.
+		switch {
+		case word.isComplex:
+			return reflect.ValueOf(word.complex128) // incontrovertible.
+		case word.isFloat && strings.IndexAny(word.text, ".eE") >= 0:
+			return reflect.ValueOf(word.float64)
+		case word.isInt:
+			return reflect.ValueOf(word.int64)
+		case word.isUint:
+			return reflect.ValueOf(word.uint64)
+		}
+	case *stringNode:
+		return reflect.ValueOf(word.text)
+	}
+	s.errorf("can't handle command %q", firstWord)
+	panic("not reached")
+}
+
+func (s *state) evalFieldNode(data reflect.Value, field *fieldNode, args []node, final reflect.Value) reflect.Value {
+	// Up to the last entry, it must be a field.
+	n := len(field.ident)
+	for i := 0; i < n-1; i++ {
+		data = s.evalField(data, field.ident[i])
+	}
+	// Now it can be a field or method and if a method, gets arguments.
+	return s.evalFieldOrCall(data, field.ident[n-1], args, final)
+}
+
+// Is this an exported - upper case - name?
+func isExported(name string) bool {
+	rune, _ := utf8.DecodeRuneInString(name)
+	return unicode.IsUpper(rune)
+}
+
+func (s *state) evalField(data reflect.Value, fieldName string) reflect.Value {
+	var isNil bool
+	if data, isNil = indirect(data); isNil {
+		s.errorf("%s is nil pointer", fieldName)
+	}
+	switch data.Kind() {
+	case reflect.Struct:
+		// Is it a field?
+		field := data.FieldByName(fieldName)
+		// TODO: look higher up the tree if we can't find it here. Also unexported fields
+		// might succeed higher up, as map keys.
+		if field.IsValid() && isExported(fieldName) { // valid and exported
+			return field
+		}
+		s.errorf("%s has no exported field %q", data.Type(), fieldName)
+	default:
+		s.errorf("can't evaluate field %s of type %s", fieldName, data.Type())
+	}
+	panic("not reached")
+}
+
+func (s *state) evalFieldOrCall(data reflect.Value, fieldName string, args []node, final reflect.Value) reflect.Value {
+	// Is it a function?
+	if function, ok := findFunction(fieldName, s.tmpl, s.set); ok {
+		return s.evalCall(data, function, fieldName, false, args, final)
+	}
+	ptr := data
+	for data.Kind() == reflect.Ptr && !data.IsNil() {
+		ptr, data = data, reflect.Indirect(data)
+	}
+	// Is it a method? We use the pointer because it has value methods too.
+	if method, ok := methodByName(ptr.Type(), fieldName); ok {
+		return s.evalCall(ptr, method.Func, fieldName, true, args, final)
+	}
+	if len(args) > 1 || final.IsValid() {
+		s.errorf("%s is not a method but has arguments", fieldName)
+	}
+	switch data.Kind() {
+	case reflect.Struct:
+		return s.evalField(data, fieldName)
+	default:
+		s.errorf("can't handle evaluation of field %s of type %s", fieldName, data.Type())
+	}
+	panic("not reached")
+}
+
+// TODO: delete when reflect's own MethodByName is released.
+func methodByName(typ reflect.Type, name string) (reflect.Method, bool) {
+	for i := 0; i < typ.NumMethod(); i++ {
+		if typ.Method(i).Name == name {
+			return typ.Method(i), true
+		}
+	}
+	return reflect.Method{}, false
+}
+
+var (
+	osErrorType = reflect.TypeOf(new(os.Error)).Elem()
+)
+
+func (s *state) evalCall(v, fun reflect.Value, name string, isMethod bool, args []node, final reflect.Value) reflect.Value {
+	typ := fun.Type()
+	if !isMethod && len(args) > 0 { // Args will be nil if it's a niladic call in an argument list
+		args = args[1:] // first arg is name of function; not used in call.
+	}
+	numIn := len(args)
+	if final.IsValid() {
+		numIn++
+	}
+	numFixed := len(args)
+	if typ.IsVariadic() {
+		numFixed = typ.NumIn() - 1 // last arg is the variadic one.
+		if numIn < numFixed {
+			s.errorf("wrong number of args for %s: want at least %d got %d", name, typ.NumIn()-1, len(args))
+		}
+	} else if numIn < typ.NumIn()-1 || !typ.IsVariadic() && numIn != typ.NumIn() {
+		s.errorf("wrong number of args for %s: want %d got %d", name, typ.NumIn(), len(args))
+	}
+	if !goodFunc(typ) {
+		s.errorf("can't handle multiple results from method/function %q", name)
+	}
+	// Build the arg list.
+	argv := make([]reflect.Value, numIn)
+	// First arg is the receiver.
+	i := 0
+	if isMethod {
+		argv[0] = v
+		i++
+	}
+	// Others must be evaluated. Fixed args first.
+	for ; i < numFixed; i++ {
+		argv[i] = s.evalArg(v, typ.In(i), args[i])
+	}
+	// And now the ... args.
+	if typ.IsVariadic() {
+		argType := typ.In(typ.NumIn() - 1).Elem() // Argument is a slice.
+		for ; i < len(args); i++ {
+			argv[i] = s.evalArg(v, argType, args[i])
+		}
+	}
+	// Add final value if necessary.
+	if final.IsValid() {
+		argv[len(args)] = final
+	}
+	result := fun.Call(argv)
+	// If we have an os.Error that is not nil, stop execution and return that error to the caller.
+	if len(result) == 2 && !result[1].IsNil() {
+		s.error(result[1].Interface().(os.Error))
+	}
+	return result[0]
+}
+
+func (s *state) evalArg(data reflect.Value, typ reflect.Type, n node) reflect.Value {
+	if field, ok := n.(*fieldNode); ok {
+		value := s.evalFieldNode(data, field, []node{n}, reflect.Value{})
+		if !value.Type().AssignableTo(typ) {
+			s.errorf("wrong type for value; expected %s; got %s", typ, value.Type())
+		}
+		return value
+	}
+	switch typ.Kind() {
+	case reflect.Bool:
+		return s.evalBool(typ, n)
+	case reflect.String:
+		return s.evalString(typ, n)
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		return s.evalInteger(typ, n)
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+		return s.evalUnsignedInteger(typ, n)
+	case reflect.Float32, reflect.Float64:
+		return s.evalFloat(typ, n)
+	case reflect.Complex64, reflect.Complex128:
+		return s.evalComplex(typ, n)
+	case reflect.Interface:
+		if typ.NumMethod() == 0 {
+			return s.evalEmptyInterface(data, typ, n)
+		}
+	}
+	s.errorf("can't handle %s for arg of type %s", n, typ)
+	panic("not reached")
+}
+
+func (s *state) evalBool(typ reflect.Type, n node) reflect.Value {
+	if n, ok := n.(*boolNode); ok {
+		value := reflect.New(typ).Elem()
+		value.SetBool(n.true)
+		return value
+	}
+	s.errorf("expected bool; found %s", n)
+	panic("not reached")
+}
+
+func (s *state) evalString(typ reflect.Type, n node) reflect.Value {
+	if n, ok := n.(*stringNode); ok {
+		value := reflect.New(typ).Elem()
+		value.SetString(n.text)
+		return value
+	}
+	s.errorf("expected string; found %s", n)
+	panic("not reached")
+}
+
+func (s *state) evalInteger(typ reflect.Type, n node) reflect.Value {
+	if n, ok := n.(*numberNode); ok && n.isInt {
+		value := reflect.New(typ).Elem()
+		value.SetInt(n.int64)
+		return value
+	}
+	s.errorf("expected integer; found %s", n)
+	panic("not reached")
+}
+
+func (s *state) evalUnsignedInteger(typ reflect.Type, n node) reflect.Value {
+	if n, ok := n.(*numberNode); ok && n.isUint {
+		value := reflect.New(typ).Elem()
+		value.SetUint(n.uint64)
+		return value
+	}
+	s.errorf("expected unsigned integer; found %s", n)
+	panic("not reached")
+}
+
+func (s *state) evalFloat(typ reflect.Type, n node) reflect.Value {
+	if n, ok := n.(*numberNode); ok && n.isFloat {
+		value := reflect.New(typ).Elem()
+		value.SetFloat(n.float64)
+		return value
+	}
+	s.errorf("expected float; found %s", n)
+	panic("not reached")
+}
+
+func (s *state) evalComplex(typ reflect.Type, n node) reflect.Value {
+	if n, ok := n.(*numberNode); ok && n.isComplex {
+		value := reflect.New(typ).Elem()
+		value.SetComplex(n.complex128)
+		return value
+	}
+	s.errorf("expected complex; found %s", n)
+	panic("not reached")
+}
+
+func (s *state) evalEmptyInterface(data reflect.Value, typ reflect.Type, n node) reflect.Value {
+	switch n := n.(type) {
+	case *boolNode:
+		return reflect.ValueOf(n.true)
+	case *dotNode:
+		return data
+	case *fieldNode:
+		return s.evalFieldNode(data, n, nil, reflect.Value{})
+	case *identifierNode:
+		return s.evalFieldOrCall(data, n.ident, nil, reflect.Value{})
+	case *numberNode:
+		if n.isComplex {
+			return reflect.ValueOf(n.complex128)
+		}
+		if n.isInt {
+			return reflect.ValueOf(n.int64)
+		}
+		if n.isUint {
+			return reflect.ValueOf(n.uint64)
+		}
+		if n.isFloat {
+			return reflect.ValueOf(n.float64)
+		}
+	case *stringNode:
+		return reflect.ValueOf(n.text)
+	}
+	s.errorf("can't handle assignment of %s to empty interface argument", n)
+	panic("not reached")
+}
+
+// indirect returns the item at the end of indirection, and a bool to indicate if it's nil.
+func indirect(v reflect.Value) (rv reflect.Value, isNil bool) {
+	for v.Kind() == reflect.Ptr {
+		if v.IsNil() {
+			return v, true
+		}
+		v = v.Elem()
+	}
+	return v, false
+}
+
+// printValue writes the textual representation of the value to the output of
+// the template.
+func (s *state) printValue(n node, v reflect.Value) {
+	if !v.IsValid() {
+		fmt.Fprint(s.wr, "<no value>")
+		return
+	}
+	switch v.Kind() {
+	case reflect.Ptr:
+		var isNil bool
+		if v, isNil = indirect(v); isNil {
+			fmt.Fprint(s.wr, "<nil>")
+			return
+		}
+	case reflect.Chan, reflect.Func, reflect.Interface:
+		s.errorf("can't print %s of type %s", n, v.Type())
+	}
+	fmt.Fprint(s.wr, v.Interface())
+}
diff --git a/src/pkg/exp/template/exec_test.go b/src/pkg/exp/template/exec_test.go
new file mode 100644
index 0000000..86b958e
--- /dev/null
+++ b/src/pkg/exp/template/exec_test.go
@@ -0,0 +1,342 @@
+// 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 template
+
+import (
+	"bytes"
+	"fmt"
+	"os"
+	"sort"
+	"strings"
+	"testing"
+)
+
+// T has lots of interesting pieces to use to test execution.
+type T struct {
+	// Basics
+	I           int
+	U16         uint16
+	X           string
+	FloatZero   float64
+	ComplexZero float64
+	// Nested structs.
+	U *U
+	// Slices
+	SI      []int
+	SIEmpty []int
+	SB      []bool
+	// Maps
+	MSI      map[string]int
+	MSIone   map[string]int // one element, for deterministic output
+	MSIEmpty map[string]int
+	SMSI     []map[string]int
+	// Empty interfaces; used to see if we can dig inside one.
+	Empty0 interface{} // nil
+	Empty1 interface{}
+	Empty2 interface{}
+	Empty3 interface{}
+	Empty4 interface{}
+	// Pointers
+	PI  *int
+	PSI *[]int
+	NIL *int
+}
+
+var tVal = &T{
+	I:      17,
+	U16:    16,
+	X:      "x",
+	U:      &U{"v"},
+	SI:     []int{3, 4, 5},
+	SB:     []bool{true, false},
+	MSI:    map[string]int{"one": 1, "two": 2, "three": 3},
+	MSIone: map[string]int{"one": 1},
+	SMSI: []map[string]int{
+		{"one": 1, "two": 2},
+		{"eleven": 11, "twelve": 12},
+	},
+	Empty1: 3,
+	Empty2: "empty2",
+	Empty3: []int{7, 8},
+	Empty4: &U{"v"},
+	PI:     newInt(23),
+	PSI:    newIntSlice(21, 22, 23),
+}
+
+// Helpers for creation.
+func newInt(n int) *int {
+	p := new(int)
+	*p = n
+	return p
+}
+
+func newIntSlice(n ...int) *[]int {
+	p := new([]int)
+	*p = make([]int, len(n))
+	copy(*p, n)
+	return p
+}
+
+// Simple methods with and without arguments.
+func (t *T) Method0() string {
+	return "resultOfMethod0"
+}
+
+func (t *T) Method1(a int) int {
+	return a
+}
+
+func (t *T) Method2(a uint16, b string) string {
+	return fmt.Sprintf("Method2: %d %s", a, b)
+}
+
+func (t *T) MAdd(a int, b []int) []int {
+	v := make([]int, len(b))
+	for i, x := range b {
+		v[i] = x + a
+	}
+	return v
+}
+
+// MSort is used to sort map keys for stable output. (Nice trick!)
+func (t *T) MSort(m map[string]int) []string {
+	keys := make([]string, len(m))
+	i := 0
+	for k := range m {
+		keys[i] = k
+		i++
+	}
+	sort.Strings(keys)
+	return keys
+}
+
+// EPERM returns a value and an os.Error according to its argument.
+func (t *T) EPERM(error bool) (bool, os.Error) {
+	if error {
+		return true, os.EPERM
+	}
+	return false, nil
+}
+
+type U struct {
+	V string
+}
+
+type execTest struct {
+	name   string
+	input  string
+	output string
+	data   interface{}
+	ok     bool
+}
+
+var execTests = []execTest{
+	// Trivial cases.
+	{"empty", "", "", nil, true},
+	{"text", "some text", "some text", nil, true},
+
+	// Fields of structs.
+	{".X", "-{{.X}}-", "-x-", tVal, true},
+	{".U.V", "-{{.U.V}}-", "-v-", tVal, true},
+
+	// Dots of all kinds to test basic evaluation.
+	{"dot int", "<{{.}}>", "<13>", 13, true},
+	{"dot uint", "<{{.}}>", "<14>", uint(14), true},
+	{"dot float", "<{{.}}>", "<15.1>", 15.1, true},
+	{"dot bool", "<{{.}}>", "<true>", true, true},
+	{"dot complex", "<{{.}}>", "<(16.2-17i)>", 16.2 - 17i, true},
+	{"dot string", "<{{.}}>", "<hello>", "hello", true},
+	{"dot slice", "<{{.}}>", "<[-1 -2 -3]>", []int{-1, -2, -3}, true},
+	{"dot map", "<{{.}}>", "<map[two:22 one:11]>", map[string]int{"one": 11, "two": 22}, true},
+	{"dot struct", "<{{.}}>", "<{7 seven}>", struct {
+		a int
+		b string
+	}{7, "seven"}, true},
+
+	// Pointers.
+	{"*int", "{{.PI}}", "23", tVal, true},
+	{"*[]int", "{{.PSI}}", "[21 22 23]", tVal, true},
+	{"*[]int[1]", "{{index .PSI 1}}", "22", tVal, true},
+	{"NIL", "{{.NIL}}", "<nil>", tVal, true},
+
+	// Emtpy interfaces holding values.
+	{"empty nil", "{{.Empty0}}", "<no value>", tVal, true},
+	{"empty with int", "{{.Empty1}}", "3", tVal, true},
+	{"empty with string", "{{.Empty2}}", "empty2", tVal, true},
+	{"empty with slice", "{{.Empty3}}", "[7 8]", tVal, true},
+	{"empty with struct", "{{.Empty4}}", "{v}", tVal, true},
+
+	// Method calls.
+	{".Method0", "-{{.Method0}}-", "-resultOfMethod0-", tVal, true},
+	{".Method1(1234)", "-{{.Method1 1234}}-", "-1234-", tVal, true},
+	{".Method1(.I)", "-{{.Method1 .I}}-", "-17-", tVal, true},
+	{".Method2(3, .X)", "-{{.Method2 3 .X}}-", "-Method2: 3 x-", tVal, true},
+	{".Method2(.U16, `str`)", "-{{.Method2 .U16 `str`}}-", "-Method2: 16 str-", tVal, true},
+
+	// Pipelines.
+	{"pipeline", "-{{.Method0 | .Method2 .U16}}-", "-Method2: 16 resultOfMethod0-", tVal, true},
+
+	// If.
+	{"if true", "{{if true}}TRUE{{end}}", "TRUE", tVal, true},
+	{"if false", "{{if false}}TRUE{{else}}FALSE{{end}}", "FALSE", tVal, true},
+	{"if 1", "{{if 1}}NON-ZERO{{else}}ZERO{{end}}", "NON-ZERO", tVal, true},
+	{"if 0", "{{if 0}}NON-ZERO{{else}}ZERO{{end}}", "ZERO", tVal, true},
+	{"if 1.5", "{{if 1.5}}NON-ZERO{{else}}ZERO{{end}}", "NON-ZERO", tVal, true},
+	{"if 0.0", "{{if .FloatZero}}NON-ZERO{{else}}ZERO{{end}}", "ZERO", tVal, true},
+	{"if 1.5i", "{{if 1.5i}}NON-ZERO{{else}}ZERO{{end}}", "NON-ZERO", tVal, true},
+	{"if 0.0i", "{{if .ComplexZero}}NON-ZERO{{else}}ZERO{{end}}", "ZERO", tVal, true},
+	{"if emptystring", "{{if ``}}NON-EMPTY{{else}}EMPTY{{end}}", "EMPTY", tVal, true},
+	{"if string", "{{if `notempty`}}NON-EMPTY{{else}}EMPTY{{end}}", "NON-EMPTY", tVal, true},
+	{"if emptyslice", "{{if .SIEmpty}}NON-EMPTY{{else}}EMPTY{{end}}", "EMPTY", tVal, true},
+	{"if slice", "{{if .SI}}NON-EMPTY{{else}}EMPTY{{end}}", "NON-EMPTY", tVal, true},
+	{"if emptymap", "{{if .MSIEmpty}}NON-EMPTY{{else}}EMPTY{{end}}", "EMPTY", tVal, true},
+	{"if map", "{{if .MSI}}NON-EMPTY{{else}}EMPTY{{end}}", "NON-EMPTY", tVal, true},
+
+	// Printf.
+	{"printf", `{{printf "hello, printf"}}`, "hello, printf", tVal, true},
+	{"printf int", `{{printf "%04x" 127}}`, "007f", tVal, true},
+	{"printf float", `{{printf "%g" 3.5}}`, "3.5", tVal, true},
+	{"printf complex", `{{printf "%g" 1+7i}}`, "(1+7i)", tVal, true},
+	{"printf string", `{{printf "%s" "hello"}}`, "hello", tVal, true},
+	{"printf function", `{{printf "%#q" gopher}}`, "`gopher`", tVal, true},
+	{"printf field", `{{printf "%s" .U.V}}`, "v", tVal, true},
+	{"printf method", `{{printf "%s" .Method0}}`, "resultOfMethod0", tVal, true},
+	{"printf lots", `{{printf "%d %s %g %s" 127 "hello" 7-3i .Method0}}`, "127 hello (7-3i) resultOfMethod0", tVal, true},
+
+	// HTML.
+	{"html", `{{html "<script>alert(\"XSS\");</script>"}}`,
+		"<script>alert("XSS");</script>", nil, true},
+	{"html pipeline", `{{printf "<script>alert(\"XSS\");</script>" | html}}`,
+		"<script>alert("XSS");</script>", nil, true},
+
+	// JavaScript.
+	{"js", `{{js .}}`, `It\'d be nice.`, `It'd be nice.`, true},
+
+	// Booleans
+	{"not", "{{not true}} {{not false}}", "false true", nil, true},
+	{"and", "{{and 0 0}} {{and 1 0}} {{and 0 1}} {{and 1 1}}", "false false false true", nil, true},
+	{"or", "{{or 0 0}} {{or 1 0}} {{or 0 1}} {{or 1 1}}", "false true true true", nil, true},
+	{"boolean if", "{{if and true 1 `hi`}}TRUE{{else}}FALSE{{end}}", "TRUE", tVal, true},
+	{"boolean if not", "{{if and true 1 `hi` | not}}TRUE{{else}}FALSE{{end}}", "FALSE", nil, true},
+
+	// Indexing.
+	{"slice[0]", "{{index .SI 0}}", "3", tVal, true},
+	{"slice[1]", "{{index .SI 1}}", "4", tVal, true},
+	{"slice[HUGE]", "{{index .SI 10}}", "", tVal, false},
+	{"slice[WRONG]", "{{index .SI `hello`}}", "", tVal, false},
+	{"map[one]", "{{index .MSI `one`}}", "1", tVal, true},
+	{"map[two]", "{{index .MSI `two`}}", "2", tVal, true},
+	{"map[NO]", "{{index .MSI `XXX`}}", "", tVal, false},
+	{"map[WRONG]", "{{index .MSI 10}}", "", tVal, false},
+	{"double index", "{{index .SMSI 1 `eleven`}}", "11", tVal, true},
+
+	// With.
+	{"with true", "{{with true}}{{.}}{{end}}", "true", tVal, true},
+	{"with false", "{{with false}}{{.}}{{else}}FALSE{{end}}", "FALSE", tVal, true},
+	{"with 1", "{{with 1}}{{.}}{{else}}ZERO{{end}}", "1", tVal, true},
+	{"with 0", "{{with 0}}{{.}}{{else}}ZERO{{end}}", "ZERO", tVal, true},
+	{"with 1.5", "{{with 1.5}}{{.}}{{else}}ZERO{{end}}", "1.5", tVal, true},
+	{"with 0.0", "{{with .FloatZero}}{{.}}{{else}}ZERO{{end}}", "ZERO", tVal, true},
+	{"with 1.5i", "{{with 1.5i}}{{.}}{{else}}ZERO{{end}}", "(0+1.5i)", tVal, true},
+	{"with 0.0i", "{{with .ComplexZero}}{{.}}{{else}}ZERO{{end}}", "ZERO", tVal, true},
+	{"with emptystring", "{{with ``}}{{.}}{{else}}EMPTY{{end}}", "EMPTY", tVal, true},
+	{"with string", "{{with `notempty`}}{{.}}{{else}}EMPTY{{end}}", "notempty", tVal, true},
+	{"with emptyslice", "{{with .SIEmpty}}{{.}}{{else}}EMPTY{{end}}", "EMPTY", tVal, true},
+	{"with slice", "{{with .SI}}{{.}}{{else}}EMPTY{{end}}", "[3 4 5]", tVal, true},
+	{"with emptymap", "{{with .MSIEmpty}}{{.}}{{else}}EMPTY{{end}}", "EMPTY", tVal, true},
+	{"with map", "{{with .MSIone}}{{.}}{{else}}EMPTY{{end}}", "map[one:1]", tVal, true},
+	{"with empty interface, struct field", "{{with .Empty4}}{{.V}}{{end}}", "v", tVal, true},
+
+	// Range.
+	{"range []int", "{{range .SI}}-{{.}}-{{end}}", "-3--4--5-", tVal, true},
+	{"range empty no else", "{{range .SIEmpty}}-{{.}}-{{end}}", "", tVal, true},
+	{"range []int else", "{{range .SI}}-{{.}}-{{else}}EMPTY{{end}}", "-3--4--5-", tVal, true},
+	{"range empty else", "{{range .SIEmpty}}-{{.}}-{{else}}EMPTY{{end}}", "EMPTY", tVal, true},
+	{"range []bool", "{{range .SB}}-{{.}}-{{end}}", "-true--false-", tVal, true},
+	{"range []int method", "{{range .SI | .MAdd .I}}-{{.}}-{{end}}", "-20--21--22-", tVal, true},
+	{"range map", "{{range .MSI | .MSort}}-{{.}}-{{end}}", "-one--three--two-", tVal, true},
+	{"range empty map no else", "{{range .MSIEmpty}}-{{.}}-{{end}}", "", tVal, true},
+	{"range map else", "{{range .MSI | .MSort}}-{{.}}-{{else}}EMPTY{{end}}", "-one--three--two-", tVal, true},
+	{"range empty map else", "{{range .MSIEmpty}}-{{.}}-{{else}}EMPTY{{end}}", "EMPTY", tVal, true},
+	{"range empty interface", "{{range .Empty3}}-{{.}}-{{else}}EMPTY{{end}}", "-7--8-", tVal, true},
+
+	// Error handling.
+	{"error method, error", "{{.EPERM true}}", "", tVal, false},
+	{"error method, no error", "{{.EPERM false}}", "false", tVal, true},
+}
+
+func gopher() string {
+	return "gopher"
+}
+
+func testExecute(execTests []execTest, set *Set, t *testing.T) {
+	b := new(bytes.Buffer)
+	funcs := FuncMap{"gopher": gopher}
+	for _, test := range execTests {
+		tmpl := New(test.name).Funcs(funcs)
+		err := tmpl.Parse(test.input)
+		if err != nil {
+			t.Errorf("%s: parse error: %s", test.name, err)
+			continue
+		}
+		b.Reset()
+		err = tmpl.ExecuteInSet(b, test.data, set)
+		switch {
+		case !test.ok && err == nil:
+			t.Errorf("%s: expected error; got none", test.name)
+			continue
+		case test.ok && err != nil:
+			t.Errorf("%s: unexpected execute error: %s", test.name, err)
+			continue
+		case !test.ok && err != nil:
+			// expected error, got one
+			if *debug {
+				fmt.Printf("%s: %s\n\t%s\n", test.name, test.input, err)
+			}
+		}
+		result := b.String()
+		if result != test.output {
+			t.Errorf("%s: expected\n\t%q\ngot\n\t%q", test.name, test.output, result)
+		}
+	}
+}
+
+func TestExecute(t *testing.T) {
+	testExecute(execTests, nil, t)
+}
+
+// Check that an error from a method flows back to the top.
+func TestExecuteError(t *testing.T) {
+	b := new(bytes.Buffer)
+	tmpl := New("error")
+	err := tmpl.Parse("{{.EPERM true}}")
+	if err != nil {
+		t.Fatalf("parse error: %s", err)
+	}
+	err = tmpl.Execute(b, tVal)
+	if err == nil {
+		t.Errorf("expected error; got none")
+	} else if !strings.Contains(err.String(), os.EPERM.String()) {
+		t.Errorf("expected os.EPERM; got %s", err)
+	}
+}
+
+func TestJSEscaping(t *testing.T) {
+	testCases := []struct {
+		in, exp string
+	}{
+		{`a`, `a`},
+		{`'foo`, `\'foo`},
+		{`Go "jump" \`, `Go \"jump\" \\`},
+		{`Yukihiro says "今日は世界"`, `Yukihiro says \"今日は世界\"`},
+		{"unprintable \uFDFF", `unprintable \uFDFF`},
+	}
+	for _, tc := range testCases {
+		s := JSEscapeString(tc.in)
+		if s != tc.exp {
+			t.Errorf("JS escaping [%s] got [%s] want [%s]", tc.in, s, tc.exp)
+		}
+	}
+}
diff --git a/src/pkg/exp/template/funcs.go b/src/pkg/exp/template/funcs.go
new file mode 100644
index 0000000..66be40f
--- /dev/null
+++ b/src/pkg/exp/template/funcs.go
@@ -0,0 +1,294 @@
+// 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 template
+
+import (
+	"bytes"
+	"fmt"
+	"io"
+	"os"
+	"reflect"
+	"strings"
+	"unicode"
+	"utf8"
+)
+
+// FuncMap is the type of the map defining the mapping from names to functions.
+// Each function must have either a single return value, or two return values of
+// which the second has type os.Error.
+type FuncMap map[string]interface{}
+
+var funcs = map[string]reflect.Value{
+	"and":    reflect.ValueOf(and),
+	"html":   reflect.ValueOf(HTMLEscaper),
+	"index":  reflect.ValueOf(index),
+	"js":     reflect.ValueOf(JSEscaper),
+	"not":    reflect.ValueOf(not),
+	"or":     reflect.ValueOf(or),
+	"printf": reflect.ValueOf(fmt.Sprintf),
+}
+
+// addFuncs adds to values the functions in funcs, converting them to reflect.Values.
+func addFuncs(values map[string]reflect.Value, funcMap FuncMap) {
+	for name, fn := range funcMap {
+		v := reflect.ValueOf(fn)
+		if v.Kind() != reflect.Func {
+			panic("value for " + name + " not a function")
+		}
+		if !goodFunc(v.Type()) {
+			panic(fmt.Errorf("can't handle multiple results from method/function %q", name))
+		}
+		values[name] = v
+	}
+}
+
+// goodFunc checks that the function or method has the right result signature.
+func goodFunc(typ reflect.Type) bool {
+	// We allow functions with 1 result or 2 results where the second is an os.Error.
+	switch {
+	case typ.NumOut() == 1:
+		return true
+	case typ.NumOut() == 2 && typ.Out(1) == osErrorType:
+		return true
+	}
+	return false
+}
+
+// findFunction looks for a function in the template, set, and global map.
+func findFunction(name string, tmpl *Template, set *Set) (reflect.Value, bool) {
+	if tmpl != nil {
+		if fn := tmpl.funcs[name]; fn.IsValid() {
+			return fn, true
+		}
+	}
+	if set != nil {
+		if fn := set.funcs[name]; fn.IsValid() {
+			return fn, true
+		}
+	}
+	if fn := funcs[name]; fn.IsValid() {
+		return fn, true
+	}
+	return reflect.Value{}, false
+}
+
+// Indexing.
+
+// index returns the result of indexing its first argument by the following
+// arguments.  Thus "index x 1 2 3" is, in Go syntax, x[1][2][3]. Each
+// indexed item must be a map, slice, or array.
+func index(item interface{}, indices ...interface{}) (interface{}, os.Error) {
+	v := reflect.ValueOf(item)
+	for _, i := range indices {
+		index := reflect.ValueOf(i)
+		var isNil bool
+		if v, isNil = indirect(v); isNil {
+			return nil, fmt.Errorf("index of nil pointer")
+		}
+		switch v.Kind() {
+		case reflect.Array, reflect.Slice:
+			var x int64
+			switch index.Kind() {
+			case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+				x = index.Int()
+			case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+				x = int64(index.Uint())
+			default:
+				return nil, fmt.Errorf("cannot index slice/array with type %s", index.Type())
+			}
+			if x < 0 || x >= int64(v.Len()) {
+				return nil, fmt.Errorf("index out of range: %d", x)
+			}
+			v = v.Index(int(x))
+		case reflect.Map:
+			if !index.Type().AssignableTo(v.Type().Key()) {
+				return nil, fmt.Errorf("%s is not index type for %s", index.Type(), v.Type())
+			}
+			v = v.MapIndex(index)
+			if !v.IsValid() {
+				return nil, fmt.Errorf("index %v not present in map", index.Interface())
+			}
+		default:
+			return nil, fmt.Errorf("can't index item of type %s", index.Type())
+		}
+	}
+	return v.Interface(), nil
+}
+
+// Boolean logic.
+
+// and returns the Boolean AND of its arguments.
+func and(arg0 interface{}, args ...interface{}) (truth bool) {
+	truth, _ = isTrue(reflect.ValueOf(arg0))
+	for i := 0; truth && i < len(args); i++ {
+		truth, _ = isTrue(reflect.ValueOf(args[i]))
+	}
+	return
+}
+
+// or returns the Boolean OR of its arguments.
+func or(arg0 interface{}, args ...interface{}) (truth bool) {
+	truth, _ = isTrue(reflect.ValueOf(arg0))
+	for i := 0; !truth && i < len(args); i++ {
+		truth, _ = isTrue(reflect.ValueOf(args[i]))
+	}
+	return
+}
+
+// not returns the Boolean negation of its argument.
+func not(arg interface{}) (truth bool) {
+	truth, _ = isTrue(reflect.ValueOf(arg))
+	return !truth
+}
+
+// HTML escaping.
+
+var (
+	htmlQuot = []byte(""") // shorter than """
+	htmlApos = []byte("'") // shorter than "'"
+	htmlAmp  = []byte("&")
+	htmlLt   = []byte("<")
+	htmlGt   = []byte(">")
+)
+
+// HTMLEscape writes to w the escaped HTML equivalent of the plain text data b.
+func HTMLEscape(w io.Writer, b []byte) {
+	last := 0
+	for i, c := range b {
+		var html []byte
+		switch c {
+		case '"':
+			html = htmlQuot
+		case '\'':
+			html = htmlApos
+		case '&':
+			html = htmlAmp
+		case '<':
+			html = htmlLt
+		case '>':
+			html = htmlGt
+		default:
+			continue
+		}
+		w.Write(b[last:i])
+		w.Write(html)
+		last = i + 1
+	}
+	w.Write(b[last:])
+}
+
+// HTMLEscapeString returns the escaped HTML equivalent of the plain text data s.
+func HTMLEscapeString(s string) string {
+	// Avoid allocation if we can.
+	if strings.IndexAny(s, `'"&<>`) < 0 {
+		return s
+	}
+	var b bytes.Buffer
+	HTMLEscape(&b, []byte(s))
+	return b.String()
+}
+
+// HTMLEscaper returns the escaped HTML equivalent of the textual
+// representation of its arguments.
+func HTMLEscaper(args ...interface{}) string {
+	ok := false
+	var s string
+	if len(args) == 1 {
+		s, ok = args[0].(string)
+	}
+	if !ok {
+		s = fmt.Sprint(args...)
+	}
+	return HTMLEscapeString(s)
+}
+
+// JavaScript escaping.
+
+var (
+	jsLowUni = []byte(`\u00`)
+	hex      = []byte("0123456789ABCDEF")
+
+	jsBackslash = []byte(`\\`)
+	jsApos      = []byte(`\'`)
+	jsQuot      = []byte(`\"`)
+)
+
+
+// JSEscape writes to w the escaped JavaScript equivalent of the plain text data b.
+func JSEscape(w io.Writer, b []byte) {
+	last := 0
+	for i := 0; i < len(b); i++ {
+		c := b[i]
+
+		if ' ' <= c && c < utf8.RuneSelf && c != '\\' && c != '"' && c != '\'' {
+			// fast path: nothing to do
+			continue
+		}
+		w.Write(b[last:i])
+
+		if c < utf8.RuneSelf {
+			// Quotes and slashes get quoted.
+			// Control characters get written as \u00XX.
+			switch c {
+			case '\\':
+				w.Write(jsBackslash)
+			case '\'':
+				w.Write(jsApos)
+			case '"':
+				w.Write(jsQuot)
+			default:
+				w.Write(jsLowUni)
+				t, b := c>>4, c&0x0f
+				w.Write(hex[t : t+1])
+				w.Write(hex[b : b+1])
+			}
+		} else {
+			// Unicode rune.
+			rune, size := utf8.DecodeRune(b[i:])
+			if unicode.IsPrint(rune) {
+				w.Write(b[i : i+size])
+			} else {
+				// TODO(dsymonds): Do this without fmt?
+				fmt.Fprintf(w, "\\u%04X", rune)
+			}
+			i += size - 1
+		}
+		last = i + 1
+	}
+	w.Write(b[last:])
+}
+
+// JSEscapeString returns the escaped JavaScript equivalent of the plain text data s.
+func JSEscapeString(s string) string {
+	// Avoid allocation if we can.
+	if strings.IndexFunc(s, jsIsSpecial) < 0 {
+		return s
+	}
+	var b bytes.Buffer
+	JSEscape(&b, []byte(s))
+	return b.String()
+}
+
+func jsIsSpecial(rune int) bool {
+	switch rune {
+	case '\\', '\'', '"':
+		return true
+	}
+	return rune < ' ' || utf8.RuneSelf <= rune
+}
+
+// JSEscaper returns the escaped JavaScript equivalent of the textual
+// representation of its arguments.
+func JSEscaper(args ...interface{}) string {
+	ok := false
+	var s string
+	if len(args) == 1 {
+		s, ok = args[0].(string)
+	}
+	if !ok {
+		s = fmt.Sprint(args...)
+	}
+	return JSEscapeString(s)
+}
diff --git a/src/pkg/exp/template/lex.go b/src/pkg/exp/template/lex.go
index 826d3eb..d781529 100644
--- a/src/pkg/exp/template/lex.go
+++ b/src/pkg/exp/template/lex.go
@@ -18,58 +18,71 @@ type item struct {
 }
 
 func (i item) String() string {
-	switch i.typ {
-	case itemEOF:
+	switch {
+	case i.typ == itemEOF:
 		return "EOF"
-	case itemError:
+	case i.typ == itemError:
 		return i.val
-	}
-	if len(i.val) > 10 {
+	case i.typ > itemKeyword:
+		return fmt.Sprintf("<%s>", i.val)
+	case len(i.val) > 10:
 		return fmt.Sprintf("%.10q...", i.val)
 	}
 	return fmt.Sprintf("%q", i.val)
 }
 
-// itemType identifies the type of lex item.
+// itemType identifies the type of lex items.
 type itemType int
 
 const (
-	itemError itemType = iota // error occurred; value is text of error
-	itemDot                   // the cursor, spelled '.'.
+	itemError   itemType = iota // error occurred; value is text of error
+	itemBool                    // boolean constant
+	itemComplex                 // complex constant (1+2i); imaginary is just a number
 	itemEOF
-	itemElse       // else keyword
-	itemEnd        // end keyword
-	itemField      // alphanumeric identifier, starting with '.'.
+	itemField      // alphanumeric identifier, starting with '.', possibly chained ('.x.y')
 	itemIdentifier // alphanumeric identifier
-	itemIf         // if keyword
-	itemLeftMeta   // left meta-string
-	itemNumber     // number
+	itemLeftDelim  // left action delimiter
+	itemNumber     // simple number, including imaginary
 	itemPipe       // pipe symbol
-	itemRange      // range keyword
 	itemRawString  // raw quoted string (includes quotes)
-	itemRightMeta  // right meta-string
+	itemRightDelim // right action delimiter
 	itemString     // quoted string (includes quotes)
 	itemText       // plain text
+	// Keywords appear after all the rest.
+	itemKeyword  // used only to delimit the keywords
+	itemDot      // the cursor, spelled '.'.
+	itemDefine   // define keyword
+	itemElse     // else keyword
+	itemEnd      // end keyword
+	itemIf       // if keyword
+	itemRange    // range keyword
+	itemTemplate // template keyword
+	itemWith     // with keyword
 )
 
 // Make the types prettyprint.
 var itemName = map[itemType]string{
 	itemError:      "error",
-	itemDot:        ".",
+	itemBool:       "bool",
+	itemComplex:    "complex",
 	itemEOF:        "EOF",
-	itemElse:       "else",
-	itemEnd:        "end",
 	itemField:      "field",
 	itemIdentifier: "identifier",
-	itemIf:         "if",
-	itemLeftMeta:   "left meta",
+	itemLeftDelim:  "left delim",
 	itemNumber:     "number",
 	itemPipe:       "pipe",
-	itemRange:      "range",
 	itemRawString:  "raw string",
-	itemRightMeta:  "rightMeta",
+	itemRightDelim: "right delim",
 	itemString:     "string",
-	itemText:       "text",
+	// keywords
+	itemDot:      ".",
+	itemDefine:   "define",
+	itemElse:     "else",
+	itemIf:       "if",
+	itemEnd:      "end",
+	itemRange:    "range",
+	itemTemplate: "template",
+	itemWith:     "with",
 }
 
 func (i itemType) String() string {
@@ -81,11 +94,14 @@ func (i itemType) String() string {
 }
 
 var key = map[string]itemType{
-	".":     itemDot,
-	"else":  itemElse,
-	"end":   itemEnd,
-	"if":    itemIf,
-	"range": itemRange,
+	".":        itemDot,
+	"define":   itemDefine,
+	"else":     itemElse,
+	"end":      itemEnd,
+	"if":       itemIf,
+	"range":    itemRange,
+	"template": itemTemplate,
+	"with":     itemWith,
 }
 
 const eof = -1
@@ -97,6 +113,7 @@ type stateFn func(*lexer) stateFn
 type lexer struct {
 	name  string    // the name of the input; used only for error reports.
 	input string    // the string being scanned.
+	state stateFn   // the next lexing function to enter
 	pos   int       // current position in the input.
 	start int       // start position of this item.
 	width int       // width of last rune read from input.
@@ -166,38 +183,47 @@ func (l *lexer) errorf(format string, args ...interface{}) stateFn {
 	return nil
 }
 
-// run lexes the input by executing state functions until nil.
-func (l *lexer) run() {
-	for state := lexText; state != nil; {
-		state = state(l)
+// nextItem returns the next item from the input.
+func (l *lexer) nextItem() item {
+	for {
+		select {
+		case item := <-l.items:
+			return item
+		default:
+			l.state = l.state(l)
+		}
 	}
-	close(l.items)
+	panic("not reached")
 }
 
-// lex launches a new scanner and returns the channel of items.
-func lex(name, input string) (*lexer, chan item) {
+// lex creates a new scanner for the input string.
+func lex(name, input string) *lexer {
 	l := &lexer{
 		name:  name,
 		input: input,
-		items: make(chan item),
+		state: lexText,
+		items: make(chan item, 2), // Two items of buffering is sufficient for all state functions
 	}
-	go l.run()
-	return l, l.items
+	return l
 }
 
 // state functions
 
-const leftMeta = "{{"
-const rightMeta = "}}"
+const (
+	leftDelim    = "{{"
+	rightDelim   = "}}"
+	leftComment  = "{{/*"
+	rightComment = "*/}}"
+)
 
-// lexText scans until a metacharacter
+// lexText scans until an opening action delimiter, "{{".
 func lexText(l *lexer) stateFn {
 	for {
-		if strings.HasPrefix(l.input[l.pos:], leftMeta) {
+		if strings.HasPrefix(l.input[l.pos:], leftDelim) {
 			if l.pos > l.start {
 				l.emit(itemText)
 			}
-			return lexLeftMeta
+			return lexLeftDelim
 		}
 		if l.next() == eof {
 			break
@@ -211,28 +237,42 @@ func lexText(l *lexer) stateFn {
 	return nil
 }
 
-// leftMeta scans the left "metacharacter", which is known to be present.
-func lexLeftMeta(l *lexer) stateFn {
-	l.pos += len(leftMeta)
-	l.emit(itemLeftMeta)
+// lexLeftDelim scans the left delimiter, which is known to be present.
+func lexLeftDelim(l *lexer) stateFn {
+	if strings.HasPrefix(l.input[l.pos:], leftComment) {
+		return lexComment
+	}
+	l.pos += len(leftDelim)
+	l.emit(itemLeftDelim)
 	return lexInsideAction
 }
 
-// rightMeta scans the right "metacharacter", which is known to be present.
-func lexRightMeta(l *lexer) stateFn {
-	l.pos += len(rightMeta)
-	l.emit(itemRightMeta)
+// lexComment scans a comment. The left comment marker is known to be present.
+func lexComment(l *lexer) stateFn {
+	i := strings.Index(l.input[l.pos:], rightComment)
+	if i < 0 {
+		return l.errorf("unclosed comment")
+	}
+	l.pos += i + len(rightComment)
+	l.ignore()
+	return lexText
+}
+
+// lexRightDelim scans the right delimiter, which is known to be present.
+func lexRightDelim(l *lexer) stateFn {
+	l.pos += len(rightDelim)
+	l.emit(itemRightDelim)
 	return lexText
 }
 
-// lexInsideAction scans the elements inside "metacharacters".
+// lexInsideAction scans the elements inside action delimiters.
 func lexInsideAction(l *lexer) stateFn {
 	// Either number, quoted string, or identifier.
 	// Spaces separate and are ignored.
 	// Pipe symbols separate and are emitted.
 	for {
-		if strings.HasPrefix(l.input[l.pos:], rightMeta) {
-			return lexRightMeta
+		if strings.HasPrefix(l.input[l.pos:], rightDelim) {
+			return lexRightDelim
 		}
 		switch r := l.next(); {
 		case r == eof || r == '\n':
@@ -273,15 +313,19 @@ Loop:
 	for {
 		switch r := l.next(); {
 		case isAlphaNumeric(r):
-			// absorb
+			// absorb.
+		case r == '.' && l.input[l.start] == '.':
+			// field chaining; absorb into one token.
 		default:
 			l.backup()
 			word := l.input[l.start:l.pos]
 			switch {
-			case key[word] != itemError:
+			case key[word] > itemKeyword:
 				l.emit(key[word])
 			case word[0] == '.':
 				l.emit(itemField)
+			case word == "true", word == "false":
+				l.emit(itemBool)
 			default:
 				l.emit(itemIdentifier)
 			}
@@ -295,8 +339,23 @@ Loop:
 // isn't a perfect number scanner - for instance it accepts "." and "0x0.2"
 // and "089" - but when it's wrong the input is invalid and the parser (via
 // strconv) will notice.
-// TODO: without expressions you can do imaginary but not complex.
 func lexNumber(l *lexer) stateFn {
+	if !l.scanNumber() {
+		return l.errorf("bad number syntax: %q", l.input[l.start:l.pos])
+	}
+	if sign := l.peek(); sign == '+' || sign == '-' {
+		// Complex: 1+2i.  No spaces, must end in 'i'.
+		if !l.scanNumber() || l.input[l.pos-1] != 'i' {
+			return l.errorf("bad number syntax: %q", l.input[l.start:l.pos])
+		}
+		l.emit(itemComplex)
+	} else {
+		l.emit(itemNumber)
+	}
+	return lexInsideAction
+}
+
+func (l *lexer) scanNumber() bool {
 	// Optional leading sign.
 	l.accept("+-")
 	// Is it hex?
@@ -317,10 +376,9 @@ func lexNumber(l *lexer) stateFn {
 	// Next thing mustn't be alphanumeric.
 	if isAlphaNumeric(l.peek()) {
 		l.next()
-		return l.errorf("bad number syntax: %q", l.input[l.start:l.pos])
+		return false
 	}
-	l.emit(itemNumber)
-	return lexInsideAction
+	return true
 }
 
 // lexQuote scans a quoted string.
diff --git a/src/pkg/exp/template/lex_test.go b/src/pkg/exp/template/lex_test.go
index 184e833..256ec04 100644
--- a/src/pkg/exp/template/lex_test.go
+++ b/src/pkg/exp/template/lex_test.go
@@ -17,8 +17,8 @@ type lexTest struct {
 
 var (
 	tEOF      = item{itemEOF, ""}
-	tLeft     = item{itemLeftMeta, "{{"}
-	tRight    = item{itemRightMeta, "}}"}
+	tLeft     = item{itemLeftDelim, "{{"}
+	tRight    = item{itemRightDelim, "}}"}
 	tRange    = item{itemRange, "range"}
 	tPipe     = item{itemPipe, "|"}
 	tFor      = item{itemIdentifier, "for"}
@@ -31,11 +31,16 @@ var lexTests = []lexTest{
 	{"empty", "", []item{tEOF}},
 	{"spaces", " \t\n", []item{{itemText, " \t\n"}, tEOF}},
 	{"text", `now is the time`, []item{{itemText, "now is the time"}, tEOF}},
+	{"text with comment", "hello-{{/* this is a comment */}}-world", []item{
+		{itemText, "hello-"},
+		{itemText, "-world"},
+		tEOF,
+	}},
 	{"empty action", `{{}}`, []item{tLeft, tRight, tEOF}},
 	{"for", `{{for }}`, []item{tLeft, tFor, tRight, tEOF}},
 	{"quote", `{{"abc \n\t\" "}}`, []item{tLeft, tQuote, tRight, tEOF}},
 	{"raw quote", "{{" + raw + "}}", []item{tLeft, tRawQuote, tRight, tEOF}},
-	{"numbers", "{{1 02 0x14 -7.2i 1e3 +1.2e-4}}", []item{
+	{"numbers", "{{1 02 0x14 -7.2i 1e3 +1.2e-4 4.2i 1+2i}}", []item{
 		tLeft,
 		{itemNumber, "1"},
 		{itemNumber, "02"},
@@ -43,25 +48,40 @@ var lexTests = []lexTest{
 		{itemNumber, "-7.2i"},
 		{itemNumber, "1e3"},
 		{itemNumber, "+1.2e-4"},
+		{itemNumber, "4.2i"},
+		{itemComplex, "1+2i"},
 		tRight,
 		tEOF,
 	}},
-	{"dots", "{{.x . .2 .x.y }}", []item{
+	{"bools", "{{true false}}", []item{
+		tLeft,
+		{itemBool, "true"},
+		{itemBool, "false"},
+		tRight,
+		tEOF,
+	}},
+	{"dot", "{{.}}", []item{
+		tLeft,
+		{itemDot, "."},
+		tRight,
+		tEOF,
+	}},
+	{"dots", "{{.x . .2 .x.y}}", []item{
 		tLeft,
 		{itemField, ".x"},
 		{itemDot, "."},
 		{itemNumber, ".2"},
-		{itemField, ".x"},
-		{itemField, ".y"},
+		{itemField, ".x.y"},
 		tRight,
 		tEOF,
 	}},
-	{"keywords", "{{range if else end}}", []item{
+	{"keywords", "{{range if else end with}}", []item{
 		tLeft,
 		{itemRange, "range"},
 		{itemIf, "if"},
 		{itemElse, "else"},
 		{itemEnd, "end"},
+		{itemWith, "with"},
 		tRight,
 		tEOF,
 	}},
@@ -112,9 +132,13 @@ var lexTests = []lexTest{
 
 // collect gathers the emitted items into a slice.
 func collect(t *lexTest) (items []item) {
-	_, tokens := lex(t.name, t.input)
-	for i := range tokens {
-		items = append(items, i)
+	l := lex(t.name, t.input)
+	for {
+		item := l.nextItem()
+		items = append(items, item)
+		if item.typ == itemEOF || item.typ == itemError {
+			break
+		}
 	}
 	return
 }
diff --git a/src/pkg/exp/template/parse.go b/src/pkg/exp/template/parse.go
index 57ddb00..8b2d602 100644
--- a/src/pkg/exp/template/parse.go
+++ b/src/pkg/exp/template/parse.go
@@ -8,17 +8,21 @@ import (
 	"bytes"
 	"fmt"
 	"os"
+	"reflect"
 	"runtime"
 	"strconv"
+	"strings"
+	"unicode"
 )
 
 // Template is the representation of a parsed template.
 type Template struct {
-	// TODO: At the moment, these are all internal to parsing.
-	name     string
-	root     *listNode
+	name  string
+	root  *listNode
+	funcs map[string]reflect.Value
+	// Parsing only; cleared after parse.
+	set      *Set
 	lex      *lexer
-	tokens   chan item
 	token    item // token lookahead for parser
 	havePeek bool
 }
@@ -28,7 +32,7 @@ func (t *Template) next() item {
 	if t.havePeek {
 		t.havePeek = false
 	} else {
-		t.token = <-t.tokens
+		t.token = t.lex.nextItem()
 	}
 	return t.token
 }
@@ -43,7 +47,7 @@ func (t *Template) peek() item {
 	if t.havePeek {
 		return t.token
 	}
-	t.token = <-t.tokens
+	t.token = t.lex.nextItem()
 	t.havePeek = true
 	return t.token
 }
@@ -64,14 +68,18 @@ const (
 	nodeText nodeType = iota
 	nodeAction
 	nodeCommand
+	nodeDot
 	nodeElse
 	nodeEnd
 	nodeField
 	nodeIdentifier
+	nodeIf
 	nodeList
 	nodeNumber
 	nodeRange
 	nodeString
+	nodeTemplate
+	nodeWith
 )
 
 // Nodes.
@@ -103,25 +111,26 @@ func (l *listNode) String() string {
 // textNode holds plain text.
 type textNode struct {
 	nodeType
-	text string
+	text []byte
 }
 
 func newText(text string) *textNode {
-	return &textNode{nodeType: nodeText, text: text}
+	return &textNode{nodeType: nodeText, text: []byte(text)}
 }
 
 func (t *textNode) String() string {
 	return fmt.Sprintf("(text: %q)", t.text)
 }
 
-// actionNode holds an action (something bounded by metacharacters).
+// actionNode holds an action (something bounded by delimiters).
 type actionNode struct {
 	nodeType
+	line     int
 	pipeline []*commandNode
 }
 
-func newAction() *actionNode {
-	return &actionNode{nodeType: nodeAction}
+func newAction(line int, pipeline []*commandNode) *actionNode {
+	return &actionNode{nodeType: nodeAction, line: line, pipeline: pipeline}
 }
 
 func (a *actionNode) append(command *commandNode) {
@@ -164,45 +173,88 @@ func (i *identifierNode) String() string {
 	return fmt.Sprintf("I=%s", i.ident)
 }
 
-// fieldNode holds a field (identifier starting with '.'). The period is dropped from the ident.
+// dotNode holds the special identifier '.'. It is represented by a nil pointer.
+type dotNode bool
+
+func newDot() *dotNode {
+	return nil
+}
+
+func (d *dotNode) typ() nodeType {
+	return nodeDot
+}
+
+func (d *dotNode) String() string {
+	return "{{<.>}}"
+}
+
+// fieldNode holds a field (identifier starting with '.').
+// The names may be chained ('.x.y').
+// The period is dropped from each ident.
 type fieldNode struct {
 	nodeType
-	ident string
+	ident []string
 }
 
 func newField(ident string) *fieldNode {
-	return &fieldNode{nodeType: nodeField, ident: ident[1:]} //drop period
+	return &fieldNode{nodeType: nodeField, ident: strings.Split(ident[1:], ".")} // [1:] to drop leading period
 }
 
 func (f *fieldNode) String() string {
-	return fmt.Sprintf("F=.%s", f.ident)
+	return fmt.Sprintf("F=%s", f.ident)
+}
+
+// boolNode holds a boolean constant.
+type boolNode struct {
+	nodeType
+	true bool
+}
+
+func newBool(true bool) *boolNode {
+	return &boolNode{nodeType: nodeString, true: true}
+}
+
+func (b *boolNode) String() string {
+	if b.true {
+		return fmt.Sprintf("B=true")
+	}
+	return fmt.Sprintf("B=false")
 }
 
-// numberNode holds a number, signed or unsigned, integer, floating, or imaginary.
+// numberNode holds a number, signed or unsigned integer, floating, or complex.
 // The value is parsed and stored under all the types that can represent the value.
 // This simulates in a small amount of code the behavior of Go's ideal constants.
-// TODO: booleans, complex numbers.
 type numberNode struct {
 	nodeType
-	isInt     bool // number has an integral value
-	isUint    bool // number has an unsigned integral value
-	isFloat   bool // number has a floating-point value
-	imaginary bool // number is imaginary
-	int64          // the signed integer value
-	uint64         // the unsigned integer value
-	float64        // the positive floating-point value
-	text      string
-}
-
-func newNumber(text string) (*numberNode, os.Error) {
+	isInt      bool // number has an integral value
+	isUint     bool // number has an unsigned integral value
+	isFloat    bool // number has a floating-point value
+	isComplex  bool // number is complex
+	int64           // the signed integer value
+	uint64          // the unsigned integer value
+	float64         // the floating-point value
+	complex128      // the complex value
+	text       string
+}
+
+func newNumber(text string, isComplex bool) (*numberNode, os.Error) {
 	n := &numberNode{nodeType: nodeNumber, text: text}
-	// Imaginary constants can only be floating-point.
+	if isComplex {
+		// fmt.Sscan can parse the pair, so let it do the work.
+		if _, err := fmt.Sscan(text, &n.complex128); err != nil {
+			return nil, err
+		}
+		n.isComplex = true
+		n.simplifyComplex()
+		return n, nil
+	}
+	// Imaginary constants can only be complex unless they are zero.
 	if len(text) > 0 && text[len(text)-1] == 'i' {
 		f, err := strconv.Atof64(text[:len(text)-1])
 		if err == nil {
-			n.imaginary = true
-			n.isFloat = true
-			n.float64 = f
+			n.isComplex = true
+			n.complex128 = complex(0, f)
+			n.simplifyComplex()
 			return n, nil
 		}
 	}
@@ -250,6 +302,23 @@ func newNumber(text string) (*numberNode, os.Error) {
 	return n, nil
 }
 
+// simplifyComplex pulls out any other types that are represented by the complex number.
+// These all require that the imaginary part be zero.
+func (n *numberNode) simplifyComplex() {
+	n.isFloat = imag(n.complex128) == 0
+	if n.isFloat {
+		n.float64 = real(n.complex128)
+		n.isInt = float64(int64(n.float64)) == n.float64
+		if n.isInt {
+			n.int64 = int64(n.float64)
+		}
+		n.isUint = float64(uint64(n.float64)) == n.float64
+		if n.isUint {
+			n.uint64 = uint64(n.float64)
+		}
+	}
+}
+
 func (n *numberNode) String() string {
 	return fmt.Sprintf("N=%s", n.text)
 }
@@ -283,11 +352,14 @@ func (e *endNode) String() string {
 	return "{{end}}"
 }
 
-// elseNode represents an {{else}} action. It is represented by a nil pointer.
-type elseNode bool
+// elseNode represents an {{else}} action.
+type elseNode struct {
+	nodeType
+	line int
+}
 
-func newElse() *elseNode {
-	return nil
+func newElse(line int) *elseNode {
+	return &elseNode{nodeType: nodeElse, line: line}
 }
 
 func (e *elseNode) typ() nodeType {
@@ -297,37 +369,106 @@ func (e *elseNode) typ() nodeType {
 func (e *elseNode) String() string {
 	return "{{else}}"
 }
+// ifNode represents an {{if}} action and its commands.
+// TODO: what should evaluation look like? is a pipeline enough?
+type ifNode struct {
+	nodeType
+	line     int
+	pipeline []*commandNode
+	list     *listNode
+	elseList *listNode
+}
+
+func newIf(line int, pipeline []*commandNode, list, elseList *listNode) *ifNode {
+	return &ifNode{nodeType: nodeIf, line: line, pipeline: pipeline, list: list, elseList: elseList}
+}
+
+func (i *ifNode) String() string {
+	if i.elseList != nil {
+		return fmt.Sprintf("({{if %s}} %s {{else}} %s)", i.pipeline, i.list, i.elseList)
+	}
+	return fmt.Sprintf("({{if %s}} %s)", i.pipeline, i.list)
+}
 
-// rangeNode represents an {{range}} action and its commands.
+// rangeNode represents a {{range}} action and its commands.
 type rangeNode struct {
 	nodeType
-	field    node
+	line     int
+	pipeline []*commandNode
 	list     *listNode
 	elseList *listNode
 }
 
-func newRange(field node, list *listNode) *rangeNode {
-	return &rangeNode{nodeType: nodeRange, field: field, list: list}
+func newRange(line int, pipeline []*commandNode, list, elseList *listNode) *rangeNode {
+	return &rangeNode{nodeType: nodeRange, line: line, pipeline: pipeline, list: list, elseList: elseList}
 }
 
 func (r *rangeNode) String() string {
 	if r.elseList != nil {
-		return fmt.Sprintf("({{range %s}} %s {{else}} %s)", r.field, r.list, r.elseList)
+		return fmt.Sprintf("({{range %s}} %s {{else}} %s)", r.pipeline, r.list, r.elseList)
 	}
-	return fmt.Sprintf("({{range %s}} %s)", r.field, r.list)
+	return fmt.Sprintf("({{range %s}} %s)", r.pipeline, r.list)
+}
+
+// templateNode represents a {{template}} action.
+type templateNode struct {
+	nodeType
+	line     int
+	name     node
+	pipeline []*commandNode
 }
 
+func newTemplate(line int, name node, pipeline []*commandNode) *templateNode {
+	return &templateNode{nodeType: nodeTemplate, line: line, name: name, pipeline: pipeline}
+}
+
+func (t *templateNode) String() string {
+	return fmt.Sprintf("{{template %s %s}}", t.name, t.pipeline)
+}
+
+// withNode represents a {{with}} action and its commands.
+type withNode struct {
+	nodeType
+	line     int
+	pipeline []*commandNode
+	list     *listNode
+	elseList *listNode
+}
+
+func newWith(line int, pipeline []*commandNode, list, elseList *listNode) *withNode {
+	return &withNode{nodeType: nodeWith, line: line, pipeline: pipeline, list: list, elseList: elseList}
+}
+
+func (w *withNode) String() string {
+	if w.elseList != nil {
+		return fmt.Sprintf("({{with %s}} %s {{else}} %s)", w.pipeline, w.list, w.elseList)
+	}
+	return fmt.Sprintf("({{with %s}} %s)", w.pipeline, w.list)
+}
+
+
 // Parsing.
 
 // New allocates a new template with the given name.
 func New(name string) *Template {
 	return &Template{
-		name: name,
+		name:  name,
+		funcs: make(map[string]reflect.Value),
 	}
 }
 
+// Funcs adds to the template's function map the elements of the
+// argument map.   It panics if a value in the map is not a function
+// with appropriate return type.
+// The return value is the template, so calls can be chained.
+func (t *Template) Funcs(funcMap FuncMap) *Template {
+	addFuncs(t.funcs, funcMap)
+	return t
+}
+
 // errorf formats the error and terminates processing.
 func (t *Template) errorf(format string, args ...interface{}) {
+	t.root = nil
 	format = fmt.Sprintf("template: %s:%d: %s", t.name, t.lex.lineNumber(), format)
 	panic(fmt.Errorf(format, args...))
 }
@@ -351,25 +492,80 @@ func (t *Template) unexpected(token item, context string) {
 	t.errorf("unexpected %s in %s", token, context)
 }
 
-// Parse parses the template definition string and constructs an efficient representation of the template.
-func (t *Template) Parse(s string) (err os.Error) {
-	t.lex, t.tokens = lex(t.name, s)
-	defer func() {
-		e := recover()
-		if e != nil {
-			if _, ok := e.(runtime.Error); ok {
-				panic(e)
+// recover is the handler that turns panics into returns from the top
+// level of Parse or Execute.
+func (t *Template) recover(errp *os.Error) {
+	e := recover()
+	if e != nil {
+		if _, ok := e.(runtime.Error); ok {
+			panic(e)
+		}
+		t.stopParse()
+		*errp = e.(os.Error)
+	}
+	return
+}
+
+// startParse starts the template parsing from the lexer.
+func (t *Template) startParse(set *Set, lex *lexer) {
+	t.root = nil
+	t.set = set
+	t.lex = lex
+}
+
+// stopParse terminates parsing.
+func (t *Template) stopParse() {
+	t.set, t.lex = nil, nil
+}
+
+// atEOF returns true if, possibly after spaces, we're at EOF.
+func (t *Template) atEOF() bool {
+	for {
+		token := t.peek()
+		switch token.typ {
+		case itemEOF:
+			return true
+		case itemText:
+			for _, r := range token.val {
+				if !unicode.IsSpace(r) {
+					return false
+				}
 			}
-			err = e.(os.Error)
+			t.next() // skip spaces.
+			continue
 		}
-		return
-	}()
-	var next node
+		break
+	}
+	return false
+}
+
+// Parse parses the template definition string to construct an internal representation
+// of the template for execution.
+func (t *Template) Parse(s string) (err os.Error) {
+	t.startParse(nil, lex(t.name, s))
+	defer t.recover(&err)
+	t.parse(true)
+	t.stopParse()
+	return
+}
+
+// ParseInSet parses the template definition string to construct an internal representation
+// of the template for execution. Function bindings are checked against those in the set.
+func (t *Template) ParseInSet(s string, set *Set) (err os.Error) {
+	t.startParse(set, lex(t.name, s))
+	defer t.recover(&err)
+	t.parse(true)
+	t.stopParse()
+	return
+}
+
+// parse is the helper for Parse. It triggers an error if we expect EOF but don't reach it.
+func (t *Template) parse(toEOF bool) (next node) {
 	t.root, next = t.itemList(true)
-	if next != nil {
+	if toEOF && next != nil {
 		t.errorf("unexpected %s", next)
 	}
-	return nil
+	return next
 }
 
 // itemList:
@@ -398,7 +594,7 @@ func (t *Template) textOrAction() node {
 	switch token := t.next(); token.typ {
 	case itemText:
 		return newText(token.val)
-	case itemLeftMeta:
+	case itemLeftDelim:
 		return t.action()
 	default:
 		t.unexpected(token, "input")
@@ -409,63 +605,95 @@ func (t *Template) textOrAction() node {
 // Action:
 //	control
 //	command ("|" command)*
-// Left meta is past. Now get actions.
+// Left delim is past. Now get actions.
+// First word could be a keyword such as range.
 func (t *Template) action() (n node) {
-	action := newAction()
 	switch token := t.next(); token.typ {
-	case itemRange:
-		return t.rangeControl()
 	case itemElse:
 		return t.elseControl()
 	case itemEnd:
 		return t.endControl()
+	case itemIf:
+		return t.ifControl()
+	case itemRange:
+		return t.rangeControl()
+	case itemTemplate:
+		return t.templateControl()
+	case itemWith:
+		return t.withControl()
 	}
 	t.backup()
-Loop:
+	return newAction(t.lex.lineNumber(), t.pipeline("command"))
+}
+
+// Pipeline:
+//	field or command
+//	pipeline "|" pipeline
+func (t *Template) pipeline(context string) (pipe []*commandNode) {
 	for {
 		switch token := t.next(); token.typ {
-		case itemRightMeta:
-			break Loop
-		case itemIdentifier, itemField:
-			t.backup()
-			cmd, err := t.command()
-			if err != nil {
-				t.error(err)
+		case itemRightDelim:
+			if len(pipe) == 0 {
+				t.errorf("missing value for %s", context)
 			}
-			action.append(cmd)
+			return
+		case itemBool, itemComplex, itemDot, itemField, itemIdentifier, itemNumber, itemRawString, itemString:
+			t.backup()
+			pipe = append(pipe, t.command())
 		default:
-			t.unexpected(token, "command")
+			t.unexpected(token, context)
 		}
 	}
-	return action
+	return
 }
 
-// Range:
-//	{{range field}} itemList {{end}}
-//	{{range field}} itemList {{else}} itemList {{end}}
-// Range keyword is past.
-func (t *Template) rangeControl() node {
-	field := t.expect(itemField, "range")
-	t.expect(itemRightMeta, "range")
-	list, next := t.itemList(false)
-	r := newRange(newField(field.val), list)
+func (t *Template) parseControl(context string) (lineNum int, pipe []*commandNode, list, elseList *listNode) {
+	lineNum = t.lex.lineNumber()
+	pipe = t.pipeline(context)
+	var next node
+	list, next = t.itemList(false)
 	switch next.typ() {
 	case nodeEnd: //done
 	case nodeElse:
-		elseList, next := t.itemList(false)
+		elseList, next = t.itemList(false)
 		if next.typ() != nodeEnd {
 			t.errorf("expected end; found %s", next)
 		}
-		r.elseList = elseList
+		elseList = elseList
 	}
-	return r
+	return lineNum, pipe, list, elseList
+}
+
+// If:
+//	{{if pipeline}} itemList {{end}}
+//	{{if pipeline}} itemList {{else}} itemList {{end}}
+// If keyword is past.
+func (t *Template) ifControl() node {
+	return newIf(t.parseControl("if"))
+}
+
+// Range:
+//	{{range pipeline}} itemList {{end}}
+//	{{range pipeline}} itemList {{else}} itemList {{end}}
+// Range keyword is past.
+func (t *Template) rangeControl() node {
+	return newRange(t.parseControl("range"))
 }
 
+// With:
+//	{{with pipeline}} itemList {{end}}
+//	{{with pipeline}} itemList {{else}} itemList {{end}}
+// If keyword is past.
+func (t *Template) withControl() node {
+	return newWith(t.parseControl("with"))
+}
+
+
 // End:
 //	{{end}}
 // End keyword is past.
 func (t *Template) endControl() node {
-	t.expect(itemRightMeta, "end")
+	t.expect(itemRightDelim, "end")
 	return newEnd()
 }
 
@@ -473,50 +701,83 @@ func (t *Template) endControl() node {
 //	{{else}}
 // Else keyword is past.
 func (t *Template) elseControl() node {
-	t.expect(itemRightMeta, "else")
-	return newElse()
+	t.expect(itemRightDelim, "else")
+	return newElse(t.lex.lineNumber())
+}
+
+// Template:
+//	{{template stringValue pipeline}}
+// Template keyword is past.  The name must be something that can evaluate
+// to a string.
+func (t *Template) templateControl() node {
+	var name node
+	switch token := t.next(); token.typ {
+	case itemIdentifier:
+		if _, ok := findFunction(token.val, t, t.set); !ok {
+			t.errorf("function %q not defined", token.val)
+		}
+		name = newIdentifier(token.val)
+	case itemDot:
+		name = newDot()
+	case itemField:
+		name = newField(token.val)
+	case itemString, itemRawString:
+		s, err := strconv.Unquote(token.val)
+		if err != nil {
+			t.error(err)
+		}
+		name = newString(s)
+	default:
+		t.unexpected(token, "template invocation")
+	}
+	pipeline := t.pipeline("template")
+	return newTemplate(t.lex.lineNumber(), name, pipeline)
 }
 
 // command:
-// space-separated arguments up to a pipeline character or right metacharacter.
-// we consume the pipe character but leave the right meta to terminate the action.
-func (t *Template) command() (*commandNode, os.Error) {
+// space-separated arguments up to a pipeline character or right delimiter.
+// we consume the pipe character but leave the right delim to terminate the action.
+func (t *Template) command() *commandNode {
 	cmd := newCommand()
 Loop:
 	for {
 		switch token := t.next(); token.typ {
-		case itemRightMeta:
+		case itemRightDelim:
 			t.backup()
 			break Loop
 		case itemPipe:
 			break Loop
 		case itemError:
-			return nil, os.NewError(token.val)
+			t.errorf("%s", token.val)
 		case itemIdentifier:
+			if _, ok := findFunction(token.val, t, t.set); !ok {
+				t.errorf("function %q not defined", token.val)
+			}
 			cmd.append(newIdentifier(token.val))
+		case itemDot:
+			cmd.append(newDot())
 		case itemField:
 			cmd.append(newField(token.val))
-		case itemNumber:
-			if len(cmd.args) == 0 {
-				t.errorf("command cannot be %q", token.val)
-			}
-			number, err := newNumber(token.val)
+		case itemBool:
+			cmd.append(newBool(token.val == "true"))
+		case itemComplex, itemNumber:
+			number, err := newNumber(token.val, token.typ == itemComplex)
 			if err != nil {
 				t.error(err)
 			}
 			cmd.append(number)
 		case itemString, itemRawString:
-			if len(cmd.args) == 0 {
-				t.errorf("command cannot be %q", token.val)
-			}
 			s, err := strconv.Unquote(token.val)
 			if err != nil {
-				return nil, err
+				t.error(err)
 			}
 			cmd.append(newString(s))
 		default:
 			t.unexpected(token, "command")
 		}
 	}
-	return cmd, nil
+	if len(cmd.args) == 0 {
+		t.errorf("empty command")
+	}
+	return cmd
 }
diff --git a/src/pkg/exp/template/parse_test.go b/src/pkg/exp/template/parse_test.go
index f89eaa6..71580f8 100644
--- a/src/pkg/exp/template/parse_test.go
+++ b/src/pkg/exp/template/parse_test.go
@@ -5,52 +5,65 @@
 package template
 
 import (
+	"flag"
 	"fmt"
 	"testing"
 )
 
-const dumpErrors = true
+var debug = flag.Bool("debug", false, "show the errors produced by the tests")
 
 type numberTest struct {
 	text      string
 	isInt     bool
 	isUint    bool
 	isFloat   bool
-	imaginary bool
+	isComplex bool
 	int64
 	uint64
 	float64
+	complex128
 }
 
 var numberTests = []numberTest{
 	// basics
-	{"0", true, true, true, false, 0, 0, 0},
-	{"-0", true, true, true, false, 0, 0, 0}, // check that -0 is a uint.
-	{"73", true, true, true, false, 73, 73, 73},
-	{"-73", true, false, true, false, -73, 0, -73},
-	{"+73", true, false, true, false, 73, 0, 73},
-	{"100", true, true, true, false, 100, 100, 100},
-	{"1e9", true, true, true, false, 1e9, 1e9, 1e9},
-	{"-1e9", true, false, true, false, -1e9, 0, -1e9},
-	{"-1.2", false, false, true, false, 0, 0, -1.2},
-	{"1e19", false, true, true, false, 0, 1e19, 1e19},
-	{"-1e19", false, false, true, false, 0, 0, -1e19},
-	{"4i", false, false, true, true, 0, 0, 4},
+	{"0", true, true, true, false, 0, 0, 0, 0},
+	{"-0", true, true, true, false, 0, 0, 0, 0}, // check that -0 is a uint.
+	{"73", true, true, true, false, 73, 73, 73, 0},
+	{"-73", true, false, true, false, -73, 0, -73, 0},
+	{"+73", true, false, true, false, 73, 0, 73, 0},
+	{"100", true, true, true, false, 100, 100, 100, 0},
+	{"1e9", true, true, true, false, 1e9, 1e9, 1e9, 0},
+	{"-1e9", true, false, true, false, -1e9, 0, -1e9, 0},
+	{"-1.2", false, false, true, false, 0, 0, -1.2, 0},
+	{"1e19", false, true, true, false, 0, 1e19, 1e19, 0},
+	{"-1e19", false, false, true, false, 0, 0, -1e19, 0},
+	{"4i", false, false, false, true, 0, 0, 0, 4i},
+	{"-1.2+4.2i", false, false, false, true, 0, 0, 0, -1.2 + 4.2i},
+	// complex with 0 imaginary are float (and maybe integer)
+	{"0i", true, true, true, true, 0, 0, 0, 0},
+	{"-1.2+0i", false, false, true, true, 0, 0, -1.2, -1.2},
+	{"-12+0i", true, false, true, true, -12, 0, -12, -12},
+	{"13+0i", true, true, true, true, 13, 13, 13, 13},
 	// funny bases
-	{"0123", true, true, true, false, 0123, 0123, 0123},
-	{"-0x0", true, true, true, false, 0, 0, 0},
-	{"0xdeadbeef", true, true, true, false, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef},
+	{"0123", true, true, true, false, 0123, 0123, 0123, 0},
+	{"-0x0", true, true, true, false, 0, 0, 0, 0},
+	{"0xdeadbeef", true, true, true, false, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0},
 	// some broken syntax
 	{text: "+-2"},
 	{text: "0x123."},
 	{text: "1e."},
 	{text: "0xi."},
+	{text: "1+2."},
 }
 
 func TestNumberParse(t *testing.T) {
 	for _, test := range numberTests {
-		n, err := newNumber(test.text)
-		ok := test.isInt || test.isUint || test.isFloat
+		// If fmt.Sscan thinks it's complex, it's complex.  We can't trust the output
+		// because imaginary comes out as a number.
+		var c complex128
+		_, err := fmt.Sscan(test.text, &c)
+		n, err := newNumber(test.text, err == nil)
+		ok := test.isInt || test.isUint || test.isFloat || test.isComplex
 		if ok && err != nil {
 			t.Errorf("unexpected error for %q", test.text)
 			continue
@@ -62,8 +75,8 @@ func TestNumberParse(t *testing.T) {
 		if !ok {
 			continue
 		}
-		if n.imaginary != test.imaginary {
-			t.Errorf("imaginary incorrect for %q; should be %t", test.text, test.imaginary)
+		if n.isComplex != test.isComplex {
+			t.Errorf("complex incorrect for %q; should be %t", test.text, test.isComplex)
 		}
 		if test.isInt {
 			if !n.isInt {
@@ -95,17 +108,19 @@ func TestNumberParse(t *testing.T) {
 		} else if n.isFloat {
 			t.Errorf("did not expect float for %q", test.text)
 		}
+		if test.isComplex {
+			if !n.isComplex {
+				t.Errorf("expected complex for %q", test.text)
+			}
+			if n.complex128 != test.complex128 {
+				t.Errorf("complex128 for %q should be %g is %g", test.text, test.complex128, n.complex128)
+			}
+		} else if n.isComplex {
+			t.Errorf("did not expect complex for %q", test.text)
+		}
 	}
 }
 
-func num(s string) *numberNode {
-	n, err := newNumber(s)
-	if err != nil {
-		panic(err)
-	}
-	return n
-}
-
 type parseTest struct {
 	name   string
 	input  string
@@ -125,29 +140,45 @@ var parseTests = []parseTest{
 		`[(text: " \t\n")]`},
 	{"text", "some text", noError,
 		`[(text: "some text")]`},
-	{"emptyMeta", "{{}}", noError,
+	{"emptyAction", "{{}}", hasError,
 		`[(action: [])]`},
-	{"simple command", "{{hello}}", noError,
-		`[(action: [(command: [I=hello])])]`},
-	{"multi-word command", "{{hello world}}", noError,
-		`[(action: [(command: [I=hello I=world])])]`},
-	{"multi-word command with number", "{{hello 80}}", noError,
-		`[(action: [(command: [I=hello N=80])])]`},
-	{"multi-word command with string", "{{hello `quoted text`}}", noError,
-		"[(action: [(command: [I=hello S=`quoted text`])])]"},
-	{"pipeline", "{{hello|world}}", noError,
-		`[(action: [(command: [I=hello]) (command: [I=world])])]`},
-	{"simple range", "{{range .x}}hello{{end}}", noError,
-		`[({{range F=.x}} [(text: "hello")])]`},
-	{"nested range", "{{range .x}}hello{{range .y}}goodbye{{end}}{{end}}", noError,
-		`[({{range F=.x}} [(text: "hello")({{range F=.y}} [(text: "goodbye")])])]`},
-	{"range with else", "{{range .x}}true{{else}}false{{end}}", noError,
-		`[({{range F=.x}} [(text: "true")] {{else}} [(text: "false")])]`},
+	{"field", "{{.X}}", noError,
+		`[(action: [(command: [F=[X]])])]`},
+	{"simple command", "{{printf}}", noError,
+		`[(action: [(command: [I=printf])])]`},
+	{"multi-word command", "{{printf `%d` 23}}", noError,
+		"[(action: [(command: [I=printf S=`%d` N=23])])]"},
+	{"pipeline", "{{.X|.Y}}", noError,
+		`[(action: [(command: [F=[X]]) (command: [F=[Y]])])]`},
+	{"simple if", "{{if .X}}hello{{end}}", noError,
+		`[({{if [(command: [F=[X]])]}} [(text: "hello")])]`},
+	{"if with else", "{{if .X}}true{{else}}false{{end}}", noError,
+		`[({{if [(command: [F=[X]])]}} [(text: "true")] {{else}} [(text: "false")])]`},
+	{"simple range", "{{range .X}}hello{{end}}", noError,
+		`[({{range [(command: [F=[X]])]}} [(text: "hello")])]`},
+	{"chained field range", "{{range .X.Y.Z}}hello{{end}}", noError,
+		`[({{range [(command: [F=[X Y Z]])]}} [(text: "hello")])]`},
+	{"nested range", "{{range .X}}hello{{range .Y}}goodbye{{end}}{{end}}", noError,
+		`[({{range [(command: [F=[X]])]}} [(text: "hello")({{range [(command: [F=[Y]])]}} [(text: "goodbye")])])]`},
+	{"range with else", "{{range .X}}true{{else}}false{{end}}", noError,
+		`[({{range [(command: [F=[X]])]}} [(text: "true")] {{else}} [(text: "false")])]`},
+	{"range over pipeline", "{{range .X|.M}}true{{else}}false{{end}}", noError,
+		`[({{range [(command: [F=[X]]) (command: [F=[M]])]}} [(text: "true")] {{else}} [(text: "false")])]`},
+	{"range []int", "{{range .SI}}{{.}}{{end}}", noError,
+		`[({{range [(command: [F=[SI]])]}} [(action: [(command: [{{<.>}}])])])]`},
+	{"constants", "{{range .SI 1 -3.2i true false }}{{end}}", noError,
+		`[({{range [(command: [F=[SI] N=1 N=-3.2i B=true B=false])]}} [])]`},
+	{"template", "{{template `x` .Y}}", noError,
+		"[{{template S=`x` [(command: [F=[Y]])]}}]"},
+	{"with", "{{with .X}}hello{{end}}", noError,
+		`[({{with [(command: [F=[X]])]}} [(text: "hello")])]`},
+	{"with with else", "{{with .X}}hello{{else}}goodbye{{end}}", noError,
+		`[({{with [(command: [F=[X]])]}} [(text: "hello")] {{else}} [(text: "goodbye")])]`},
 	// Errors.
 	{"unclosed action", "hello{{range", hasError, ""},
-	{"not a field", "hello{{range x}}{{end}}", hasError, ""},
 	{"missing end", "hello{{range .x}}", hasError, ""},
 	{"missing end after else", "hello{{range .x}}{{else}}", hasError, ""},
+	{"undefined function", "hello{{undefined}}", hasError, ""},
 }
 
 func TestParse(t *testing.T) {
@@ -163,7 +194,7 @@ func TestParse(t *testing.T) {
 			continue
 		case err != nil && !test.ok:
 			// expected error, got one
-			if dumpErrors {
+			if *debug {
 				fmt.Printf("%s: %s\n\t%s\n", test.name, test.input, err)
 			}
 			continue
diff --git a/src/pkg/exp/template/set.go b/src/pkg/exp/template/set.go
new file mode 100644
index 0000000..492e270
--- /dev/null
+++ b/src/pkg/exp/template/set.go
@@ -0,0 +1,115 @@
+// 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 template
+
+import (
+	"fmt"
+	"io"
+	"os"
+	"reflect"
+	"runtime"
+	"strconv"
+)
+
+// Set holds a set of related templates that can refer to one another by name.
+// A template may be a member of multiple sets.
+type Set struct {
+	tmpl  map[string]*Template
+	funcs map[string]reflect.Value
+}
+
+// NewSet allocates a new, empty template set.
+func NewSet() *Set {
+	return &Set{
+		tmpl:  make(map[string]*Template),
+		funcs: make(map[string]reflect.Value),
+	}
+}
+
+// Funcs adds to the set's function map the elements of the
+// argument map.   It panics if a value in the map is not a function
+// with appropriate return type.
+// The return value is the set, so calls can be chained.
+func (s *Set) Funcs(funcMap FuncMap) *Set {
+	addFuncs(s.funcs, funcMap)
+	return s
+}
+
+// Add adds the argument templates to the set. It panics if the call
+// attempts to reuse a name defined in the template.
+// The return value is the set, so calls can be chained.
+func (s *Set) Add(templates ...*Template) *Set {
+	for _, t := range templates {
+		if _, ok := s.tmpl[t.name]; ok {
+			panic(fmt.Errorf("template: %q already defined in set", t.name))
+		}
+		s.tmpl[t.name] = t
+	}
+	return s
+}
+
+// Template returns the template with the given name in the set,
+// or nil if there is no such template.
+func (s *Set) Template(name string) *Template {
+	return s.tmpl[name]
+}
+
+// Execute looks for the named template in the set and then applies that
+// template to the specified data object, writing the output to wr.  Nested
+// template invocations will be resolved from the set.
+func (s *Set) Execute(name string, wr io.Writer, data interface{}) os.Error {
+	tmpl := s.tmpl[name]
+	if tmpl == nil {
+		return fmt.Errorf("template: no template %q in set", name)
+	}
+	return tmpl.ExecuteInSet(wr, data, s)
+}
+
+// recover is the handler that turns panics into returns from the top
+// level of Parse.
+func (s *Set) recover(errp *os.Error) {
+	e := recover()
+	if e != nil {
+		if _, ok := e.(runtime.Error); ok {
+			panic(e)
+		}
+		s.tmpl = nil
+		*errp = e.(os.Error)
+	}
+	return
+}
+
+// Parse parses the file into a set of named templates.
+func (s *Set) Parse(text string) (err os.Error) {
+	defer s.recover(&err)
+	lex := lex("set", text)
+	const context = "define clause"
+	for {
+		t := New("set") // name will be updated once we know it.
+		t.startParse(s, lex)
+		// Expect EOF or "{{ define name }}".
+		if t.atEOF() {
+			return
+		}
+		t.expect(itemLeftDelim, context)
+		t.expect(itemDefine, context)
+		name := t.expect(itemString, context)
+		t.name, err = strconv.Unquote(name.val)
+		if err != nil {
+			t.error(err)
+		}
+		t.expect(itemRightDelim, context)
+		end := t.parse(false)
+		if end == nil {
+			t.errorf("unexpected EOF in %s", context)
+		}
+		if end.typ() != nodeEnd {
+			t.errorf("unexpected %s in %s", end, context)
+		}
+		t.stopParse()
+		s.tmpl[t.name] = t
+	}
+	return nil
+}
diff --git a/src/pkg/exp/template/set_test.go b/src/pkg/exp/template/set_test.go
new file mode 100644
index 0000000..c0115ec
--- /dev/null
+++ b/src/pkg/exp/template/set_test.go
@@ -0,0 +1,101 @@
+// 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 template
+
+import (
+	"fmt"
+	"testing"
+)
+
+type setParseTest struct {
+	name    string
+	input   string
+	ok      bool
+	names   []string
+	results []string
+}
+
+var setParseTests = []setParseTest{
+	{"empty", "", noError,
+		nil,
+		nil},
+	{"one", `{{define "foo"}} FOO {{end}}`, noError,
+		[]string{"foo"},
+		[]string{`[(text: " FOO ")]`}},
+	{"two", `{{define "foo"}} FOO {{end}}{{define "bar"}} BAR {{end}}`, noError,
+		[]string{"foo", "bar"},
+		[]string{`[(text: " FOO ")]`, `[(text: " BAR ")]`}},
+	// errors
+	{"missing end", `{{define "foo"}} FOO `, hasError,
+		nil,
+		nil},
+	{"malformed name", `{{define "foo}} FOO `, hasError,
+		nil,
+		nil},
+}
+
+func TestSetParse(t *testing.T) {
+	for _, test := range setParseTests {
+		set := NewSet()
+		err := set.Parse(test.input)
+		switch {
+		case err == nil && !test.ok:
+			t.Errorf("%q: expected error; got none", test.name)
+			continue
+		case err != nil && test.ok:
+			t.Errorf("%q: unexpected error: %v", test.name, err)
+			continue
+		case err != nil && !test.ok:
+			// expected error, got one
+			if *debug {
+				fmt.Printf("%s: %s\n\t%s\n", test.name, test.input, err)
+			}
+			continue
+		}
+		if len(set.tmpl) != len(test.names) {
+			t.Errorf("%s: wrong number of templates; wanted %d got %d", test.name, len(test.names), len(set.tmpl))
+			continue
+		}
+		for i, name := range test.names {
+			tmpl, ok := set.tmpl[name]
+			if !ok {
+				t.Errorf("%s: can't find template %q", test.name, name)
+				continue
+			}
+			result := tmpl.root.String()
+			if result != test.results[i] {
+				t.Errorf("%s=(%q): got\n\t%v\nexpected\n\t%v", test.name, test.input, result, test.results[i])
+			}
+		}
+	}
+}
+
+
+var setExecTests = []execTest{
+	{"empty", "", "", nil, true},
+	{"text", "some text", "some text", nil, true},
+	{"invoke text", `{{template "text" .SI}}`, "TEXT", tVal, true},
+	{"invoke dot int", `{{template "dot" .I}}`, "17", tVal, true},
+	{"invoke dot []int", `{{template "dot" .SI}}`, "[3 4 5]", tVal, true},
+	{"invoke dotV", `{{template "dotV" .U}}`, "v", tVal, true},
+	{"invoke nested int", `{{template "nested" .I}}`, "17", tVal, true},
+}
+
+const setText = `
+	{{define "text"}}TEXT{{end}}
+	{{define "dotV"}}{{.V}}{{end}}
+	{{define "dot"}}{{.}}{{end}}
+	{{define "nested"}}{{template "dot" .}}{{end}}
+`
+
+func TestSetExecute(t *testing.T) {
+	// Declare a set with a couple of templates first.
+	set := NewSet()
+	err := set.Parse(setText)
+	if err != nil {
+		t.Fatalf("error parsing set: %s", err)
+	}
+	testExecute(setExecTests, set, t)
+}
diff --git a/src/pkg/fmt/print.go b/src/pkg/fmt/print.go
index 438e0ae..5c083e5 100644
--- a/src/pkg/fmt/print.go
+++ b/src/pkg/fmt/print.go
@@ -162,19 +162,18 @@ func (p *pp) Write(b []byte) (ret int, err os.Error) {
 
 // Fprintf formats according to a format specifier and writes to w.
 // It returns the number of bytes written and any write error encountered.
-func Fprintf(w io.Writer, format string, a ...interface{}) (n int, error os.Error) {
+func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err os.Error) {
 	p := newPrinter()
 	p.doPrintf(format, a)
-	n64, error := p.buf.WriteTo(w)
+	n64, err := p.buf.WriteTo(w)
 	p.free()
-	return int(n64), error
+	return int(n64), err
 }
 
 // Printf formats according to a format specifier and writes to standard output.
 // It returns the number of bytes written and any write error encountered.
-func Printf(format string, a ...interface{}) (n int, errno os.Error) {
-	n, errno = Fprintf(os.Stdout, format, a...)
-	return n, errno
+func Printf(format string, a ...interface{}) (n int, err os.Error) {
+	return Fprintf(os.Stdout, format, a...)
 }
 
 // Sprintf formats according to a format specifier and returns the resulting string.
@@ -197,20 +196,19 @@ func Errorf(format string, a ...interface{}) os.Error {
 // Fprint formats using the default formats for its operands and writes to w.
 // Spaces are added between operands when neither is a string.
 // It returns the number of bytes written and any write error encountered.
-func Fprint(w io.Writer, a ...interface{}) (n int, error os.Error) {
+func Fprint(w io.Writer, a ...interface{}) (n int, err os.Error) {
 	p := newPrinter()
 	p.doPrint(a, false, false)
-	n64, error := p.buf.WriteTo(w)
+	n64, err := p.buf.WriteTo(w)
 	p.free()
-	return int(n64), error
+	return int(n64), err
 }
 
 // Print formats using the default formats for its operands and writes to standard output.
 // Spaces are added between operands when neither is a string.
 // It returns the number of bytes written and any write error encountered.
-func Print(a ...interface{}) (n int, errno os.Error) {
-	n, errno = Fprint(os.Stdout, a...)
-	return n, errno
+func Print(a ...interface{}) (n int, err os.Error) {
+	return Fprint(os.Stdout, a...)
 }
 
 // Sprint formats using the default formats for its operands and returns the resulting string.
@@ -230,20 +228,19 @@ func Sprint(a ...interface{}) string {
 // Fprintln formats using the default formats for its operands and writes to w.
 // Spaces are always added between operands and a newline is appended.
 // It returns the number of bytes written and any write error encountered.
-func Fprintln(w io.Writer, a ...interface{}) (n int, error os.Error) {
+func Fprintln(w io.Writer, a ...interface{}) (n int, err os.Error) {
 	p := newPrinter()
 	p.doPrint(a, true, true)
-	n64, error := p.buf.WriteTo(w)
+	n64, err := p.buf.WriteTo(w)
 	p.free()
-	return int(n64), error
+	return int(n64), err
 }
 
 // Println formats using the default formats for its operands and writes to standard output.
 // Spaces are always added between operands and a newline is appended.
 // It returns the number of bytes written and any write error encountered.
-func Println(a ...interface{}) (n int, errno os.Error) {
-	n, errno = Fprintln(os.Stdout, a...)
-	return n, errno
+func Println(a ...interface{}) (n int, err os.Error) {
+	return Fprintln(os.Stdout, a...)
 }
 
 // Sprintln formats using the default formats for its operands and returns the resulting string.
diff --git a/src/pkg/fmt/scan.go b/src/pkg/fmt/scan.go
index f48fcbb..d93a8c1 100644
--- a/src/pkg/fmt/scan.go
+++ b/src/pkg/fmt/scan.go
@@ -35,6 +35,10 @@ type ScanState interface {
 	ReadRune() (rune int, size int, err os.Error)
 	// UnreadRune causes the next call to ReadRune to return the same rune.
 	UnreadRune() os.Error
+	// SkipSpace skips space in the input. Newlines are treated as space 
+	// unless the scan operation is Scanln, Fscanln or Sscanln, in which case 
+	// a newline is treated as EOF.
+	SkipSpace()
 	// Token skips space in the input if skipSpace is true, then returns the
 	// run of Unicode code points c satisfying f(c).  If f is nil,
 	// !unicode.IsSpace(c) is used; that is, the token will hold non-space
@@ -267,6 +271,14 @@ func notSpace(r int) bool {
 	return !unicode.IsSpace(r)
 }
 
+
+// skipSpace provides Scan() methods the ability to skip space and newline characters 
+// in keeping with the current scanning mode set by format strings and Scan()/Scanln().
+func (s *ss) SkipSpace() {
+	s.skipSpace(false)
+}
+
+
 // readRune is a structure to enable reading UTF-8 encoded code points
 // from an io.Reader.  It is used if the Reader given to the scanner does
 // not already implement io.RuneReader.
diff --git a/src/pkg/go/ast/print_test.go b/src/pkg/go/ast/print_test.go
index 0820dcf..30b396f 100644
--- a/src/pkg/go/ast/print_test.go
+++ b/src/pkg/go/ast/print_test.go
@@ -53,7 +53,7 @@ var tests = []struct {
 // Split s into lines, trim whitespace from all lines, and return
 // the concatenated non-empty lines.
 func trim(s string) string {
-	lines := strings.Split(s, "\n", -1)
+	lines := strings.Split(s, "\n")
 	i := 0
 	for _, line := range lines {
 		line = strings.TrimSpace(line)
diff --git a/src/pkg/go/build/dir.go b/src/pkg/go/build/dir.go
index 20f8f29..e0000b5 100644
--- a/src/pkg/go/build/dir.go
+++ b/src/pkg/go/build/dir.go
@@ -139,7 +139,7 @@ func goodOSArch(filename string) bool {
 	if dot := strings.Index(filename, "."); dot != -1 {
 		filename = filename[:dot]
 	}
-	l := strings.Split(filename, "_", -1)
+	l := strings.Split(filename, "_")
 	n := len(l)
 	if n == 0 {
 		return true
diff --git a/src/pkg/go/build/path.go b/src/pkg/go/build/path.go
index 8ad39fb..ea588ab 100644
--- a/src/pkg/go/build/path.go
+++ b/src/pkg/go/build/path.go
@@ -88,6 +88,9 @@ func FindTree(path string) (tree *Tree, pkg string, err os.Error) {
 		if path, err = filepath.Abs(path); err != nil {
 			return
 		}
+		if path, err = filepath.EvalSymlinks(path); err != nil {
+			return
+		}
 		for _, t := range Path {
 			tpath := t.SrcDir() + string(filepath.Separator)
 			if !strings.HasPrefix(path, tpath) {
diff --git a/src/pkg/go/doc/comment.go b/src/pkg/go/doc/comment.go
index f1ebfa9..85640af 100644
--- a/src/pkg/go/doc/comment.go
+++ b/src/pkg/go/doc/comment.go
@@ -58,7 +58,7 @@ func CommentText(comment *ast.CommentGroup) string {
 		}
 
 		// Split on newlines.
-		cl := strings.Split(c, "\n", -1)
+		cl := strings.Split(c, "\n")
 
 		// Walk lines, stripping trailing white space and adding to list.
 		for _, l := range cl {
diff --git a/src/pkg/go/doc/doc.go b/src/pkg/go/doc/doc.go
index a7a7e0a..b26cd2b 100644
--- a/src/pkg/go/doc/doc.go
+++ b/src/pkg/go/doc/doc.go
@@ -551,7 +551,7 @@ func (doc *docReader) newDoc(importpath string, filenames []string) *PackageDoc
 	p := new(PackageDoc)
 	p.PackageName = doc.pkgName
 	p.ImportPath = importpath
-	sort.SortStrings(filenames)
+	sort.Strings(filenames)
 	p.Filenames = filenames
 	p.Doc = CommentText(doc.doc)
 	// makeTypeDocs may extend the list of doc.values and
diff --git a/src/pkg/go/types/testdata/exports.go b/src/pkg/go/types/testdata/exports.go
index 1de2e00..035a13f 100644
--- a/src/pkg/go/types/testdata/exports.go
+++ b/src/pkg/go/types/testdata/exports.go
@@ -38,7 +38,7 @@ type (
 	T9  struct {
 		a    int
 		b, c float32
-		d    []string "tag"
+		d    []string `go:"tag"`
 	}
 	T10 struct {
 		T8
diff --git a/src/pkg/gob/decode.go b/src/pkg/gob/decode.go
index 415b308..bf7cb95 100644
--- a/src/pkg/gob/decode.go
+++ b/src/pkg/gob/decode.go
@@ -741,7 +741,7 @@ func (dec *Decoder) ignoreInterface(state *decoderState) {
 
 // decodeGobDecoder decodes something implementing the GobDecoder interface.
 // The data is encoded as a byte slice.
-func (dec *Decoder) decodeGobDecoder(state *decoderState, v reflect.Value, index int) {
+func (dec *Decoder) decodeGobDecoder(state *decoderState, v reflect.Value) {
 	// Read the bytes for the value.
 	b := make([]byte, state.decodeUint())
 	_, err := state.b.Read(b)
@@ -969,7 +969,7 @@ func (dec *Decoder) gobDecodeOpFor(ut *userTypeInfo) (*decOp, int) {
 		} else {
 			v = reflect.ValueOf(unsafe.Unreflect(rcvrType, p))
 		}
-		state.dec.decodeGobDecoder(state, v, methodIndex(rcvrType, gobDecodeMethodName))
+		state.dec.decodeGobDecoder(state, v)
 	}
 	return &op, int(ut.indir)
 
diff --git a/src/pkg/gob/doc.go b/src/pkg/gob/doc.go
index 850759b..aaf429c 100644
--- a/src/pkg/gob/doc.go
+++ b/src/pkg/gob/doc.go
@@ -29,29 +29,29 @@ receiver and transmitter will do all necessary indirection and dereferencing to
 convert between gobs and actual Go values.  For instance, a gob type that is
 schematically,
 
-	struct { a, b int }
+	struct { A, B int }
 
 can be sent from or received into any of these Go types:
 
-	struct { a, b int }	// the same
-	*struct { a, b int }	// extra indirection of the struct
-	struct { *a, **b int }	// extra indirection of the fields
-	struct { a, b int64 }	// different concrete value type; see below
+	struct { A, B int }	// the same
+	*struct { A, B int }	// extra indirection of the struct
+	struct { *A, **B int }	// extra indirection of the fields
+	struct { A, B int64 }	// different concrete value type; see below
 
 It may also be received into any of these:
 
-	struct { a, b int }	// the same
-	struct { b, a int }	// ordering doesn't matter; matching is by name
-	struct { a, b, c int }	// extra field (c) ignored
-	struct { b int }	// missing field (a) ignored; data will be dropped
-	struct { b, c int }	// missing field (a) ignored; extra field (c) ignored.
+	struct { A, B int }	// the same
+	struct { B, A int }	// ordering doesn't matter; matching is by name
+	struct { A, B, C int }	// extra field (C) ignored
+	struct { B int }	// missing field (A) ignored; data will be dropped
+	struct { B, C int }	// missing field (A) ignored; extra field (C) ignored.
 
 Attempting to receive into these types will draw a decode error:
 
-	struct { a int; b uint }	// change of signedness for b
-	struct { a int; b float }	// change of type for b
+	struct { A int; B uint }	// change of signedness for B
+	struct { A int; B float }	// change of type for B
 	struct { }			// no field names in common
-	struct { c, d int }		// no field names in common
+	struct { C, D int }		// no field names in common
 
 Integers are transmitted two ways: arbitrary precision signed integers or
 arbitrary precision unsigned integers.  There is no int8, int16 etc.
@@ -269,12 +269,12 @@ StructValue:
 
 /*
 For implementers and the curious, here is an encoded example.  Given
-	type Point struct {x, y int}
+	type Point struct {X, Y int}
 and the value
 	p := Point{22, 33}
 the bytes transmitted that encode p will be:
 	1f ff 81 03 01 01 05 50 6f 69 6e 74 01 ff 82 00
-	01 02 01 01 78 01 04 00 01 01 79 01 04 00 00 00
+	01 02 01 01 58 01 04 00 01 01 59 01 04 00 00 00
 	07 ff 82 01 2c 01 42 00
 They are determined as follows.
 
@@ -310,13 +310,13 @@ reserved).
 	02	// There are two fields in the type (len(structType.field))
 	01	// Start of first field structure; add 1 to get field number 0: field[0].name
 	01	// 1 byte
-	78	// structType.field[0].name = "x"
+	58	// structType.field[0].name = "X"
 	01	// Add 1 to get field number 1: field[0].id
 	04	// structType.field[0].typeId is 2 (signed int).
 	00	// End of structType.field[0]; start structType.field[1]; set field number to -1.
 	01	// Add 1 to get field number 0: field[1].name
 	01	// 1 byte
-	79	// structType.field[1].name = "y"
+	59	// structType.field[1].name = "Y"
 	01	// Add 1 to get field number 1: field[0].id
 	04	// struct.Type.field[1].typeId is 2 (signed int).
 	00	// End of structType.field[1]; end of structType.field.
diff --git a/src/pkg/gob/encode.go b/src/pkg/gob/encode.go
index 743e853..941e260 100644
--- a/src/pkg/gob/encode.go
+++ b/src/pkg/gob/encode.go
@@ -468,7 +468,7 @@ func (enc *Encoder) encodeInterface(b *bytes.Buffer, iv reflect.Value) {
 
 // encGobEncoder encodes a value that implements the GobEncoder interface.
 // The data is sent as a byte array.
-func (enc *Encoder) encodeGobEncoder(b *bytes.Buffer, v reflect.Value, index int) {
+func (enc *Encoder) encodeGobEncoder(b *bytes.Buffer, v reflect.Value) {
 	// TODO: should we catch panics from the called method?
 	// We know it's a GobEncoder, so just call the method directly.
 	data, err := v.Interface().(GobEncoder).GobEncode()
@@ -592,17 +592,6 @@ func (enc *Encoder) encOpFor(rt reflect.Type, inProgress map[reflect.Type]*encOp
 	return &op, indir
 }
 
-// methodIndex returns which method of rt implements the method.
-func methodIndex(rt reflect.Type, method string) int {
-	for i := 0; i < rt.NumMethod(); i++ {
-		if rt.Method(i).Name == method {
-			return i
-		}
-	}
-	errorf("internal error: can't find method %s", method)
-	return 0
-}
-
 // gobEncodeOpFor returns the op for a type that is known to implement
 // GobEncoder.
 func (enc *Encoder) gobEncodeOpFor(ut *userTypeInfo) (*encOp, int) {
@@ -624,7 +613,7 @@ func (enc *Encoder) gobEncodeOpFor(ut *userTypeInfo) (*encOp, int) {
 			v = reflect.ValueOf(unsafe.Unreflect(rt, p))
 		}
 		state.update(i)
-		state.enc.encodeGobEncoder(state.b, v, methodIndex(rt, gobEncodeMethodName))
+		state.enc.encodeGobEncoder(state.b, v)
 	}
 	return &op, int(ut.encIndir) // encIndir: op will get called with p == address of receiver.
 }
diff --git a/src/pkg/gob/type.go b/src/pkg/gob/type.go
index f8e3843..552faa4 100644
--- a/src/pkg/gob/type.go
+++ b/src/pkg/gob/type.go
@@ -80,11 +80,6 @@ func validUserType(rt reflect.Type) (ut *userTypeInfo, err os.Error) {
 	return
 }
 
-const (
-	gobEncodeMethodName = "GobEncode"
-	gobDecodeMethodName = "GobDecode"
-)
-
 var (
 	gobEncoderInterfaceType = reflect.TypeOf(new(GobEncoder)).Elem()
 	gobDecoderInterfaceType = reflect.TypeOf(new(GobDecoder)).Elem()
diff --git a/src/pkg/html/parse.go b/src/pkg/html/parse.go
index 2ef90a8..6a2bc1e 100644
--- a/src/pkg/html/parse.go
+++ b/src/pkg/html/parse.go
@@ -400,6 +400,7 @@ func inBodyIM(p *parser) (insertionMode, bool) {
 			p.framesetOK = false
 		default:
 			// TODO.
+			p.addElement(p.tok.Data, p.tok.Attr)
 		}
 	case EndTagToken:
 		switch p.tok.Data {
@@ -413,7 +414,10 @@ func inBodyIM(p *parser) (insertionMode, bool) {
 				p.pop()
 			}
 		default:
-			// TODO.
+			// TODO: any other end tag
+			if p.tok.Data == p.top().Data {
+				p.pop()
+			}
 		}
 	}
 	if endP {
diff --git a/src/pkg/html/token_test.go b/src/pkg/html/token_test.go
index c17b436..c794612 100644
--- a/src/pkg/html/token_test.go
+++ b/src/pkg/html/token_test.go
@@ -161,7 +161,7 @@ func TestTokenizer(t *testing.T) {
 loop:
 	for _, tt := range tokenTests {
 		z := NewTokenizer(bytes.NewBuffer([]byte(tt.html)))
-		for i, s := range strings.Split(tt.golden, "$", -1) {
+		for i, s := range strings.Split(tt.golden, "$") {
 			if z.Next() == ErrorToken {
 				t.Errorf("%s token %d: want %q got error %v", tt.desc, i, s, z.Error())
 				continue loop
diff --git a/src/pkg/http/cgi/host.go b/src/pkg/http/cgi/host.go
index 2be3ede..059fc75 100644
--- a/src/pkg/http/cgi/host.go
+++ b/src/pkg/http/cgi/host.go
@@ -46,6 +46,12 @@ type Handler struct {
 	Path string // path to the CGI executable
 	Root string // root URI prefix of handler or empty for "/"
 
+	// Dir specifies the CGI executable's working directory.
+	// If Dir is empty, the base directory of Path is used.
+	// If Path has no base directory, the current working
+	// directory is used.
+	Dir string
+
 	Env        []string    // extra environment variables to set, if any, as "key=value"
 	InheritEnv []string    // environment variables to inherit from host, as "key"
 	Logger     *log.Logger // optional log for errors or nil to use log.Print
@@ -125,11 +131,11 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
 		env = append(env, h.Env...)
 	}
 
-	path := os.Getenv("PATH")
-	if path == "" {
-		path = "/bin:/usr/bin:/usr/ucb:/usr/bsd:/usr/local/bin"
+	envPath := os.Getenv("PATH")
+	if envPath == "" {
+		envPath = "/bin:/usr/bin:/usr/ucb:/usr/bsd:/usr/local/bin"
 	}
-	env = append(env, "PATH="+path)
+	env = append(env, "PATH="+envPath)
 
 	for _, e := range h.InheritEnv {
 		if v := os.Getenv(e); v != "" {
@@ -143,7 +149,13 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
 		}
 	}
 
-	cwd, pathBase := filepath.Split(h.Path)
+	var cwd, path string
+	if h.Dir != "" {
+		path = h.Path
+		cwd = h.Dir
+	} else {
+		cwd, path = filepath.Split(h.Path)
+	}
 	if cwd == "" {
 		cwd = "."
 	}
@@ -154,7 +166,7 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
 	}
 
 	cmd := &exec.Cmd{
-		Path:   pathBase,
+		Path:   path,
 		Args:   append([]string{h.Path}, h.Args...),
 		Dir:    cwd,
 		Env:    env,
@@ -197,7 +209,7 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
 		if len(line) == 0 {
 			break
 		}
-		parts := strings.Split(string(line), ":", 2)
+		parts := strings.SplitN(string(line), ":", 2)
 		if len(parts) < 2 {
 			h.printf("cgi: bogus header line: %s", string(line))
 			continue
diff --git a/src/pkg/http/cgi/host_test.go b/src/pkg/http/cgi/host_test.go
index bbdb715..b08d8bb 100644
--- a/src/pkg/http/cgi/host_test.go
+++ b/src/pkg/http/cgi/host_test.go
@@ -13,8 +13,10 @@ import (
 	"http"
 	"http/httptest"
 	"os"
+	"path/filepath"
 	"strings"
 	"testing"
+	"runtime"
 )
 
 func newRequest(httpreq string) *http.Request {
@@ -46,7 +48,7 @@ readlines:
 		}
 		linesRead++
 		trimmedLine := strings.TrimRight(line, "\r\n")
-		split := strings.Split(trimmedLine, "=", 2)
+		split := strings.SplitN(trimmedLine, "=", 2)
 		if len(split) != 2 {
 			t.Fatalf("Unexpected %d parts from invalid line number %v: %q; existing map=%v",
 				len(split), linesRead, line, m)
@@ -301,3 +303,77 @@ func TestInternalRedirect(t *testing.T) {
 	}
 	runCgiTest(t, h, "GET /test.cgi?loc=/foo HTTP/1.0\nHost: example.com\n\n", expectedMap)
 }
+
+func TestDirUnix(t *testing.T) {
+	if runtime.GOOS == "windows" {
+		return
+	}
+
+	cwd, _ := os.Getwd()
+	h := &Handler{
+		Path: "testdata/test.cgi",
+		Root: "/test.cgi",
+		Dir:  cwd,
+	}
+	expectedMap := map[string]string{
+		"cwd": cwd,
+	}
+	runCgiTest(t, h, "GET /test.cgi HTTP/1.0\nHost: example.com\n\n", expectedMap)
+
+	cwd, _ = os.Getwd()
+	cwd = filepath.Join(cwd, "testdata")
+	h = &Handler{
+		Path: "testdata/test.cgi",
+		Root: "/test.cgi",
+	}
+	expectedMap = map[string]string{
+		"cwd": cwd,
+	}
+	runCgiTest(t, h, "GET /test.cgi HTTP/1.0\nHost: example.com\n\n", expectedMap)
+}
+
+func TestDirWindows(t *testing.T) {
+	if runtime.GOOS != "windows" {
+		return
+	}
+
+	cgifile, _ := filepath.Abs("testdata/test.cgi")
+
+	var perl string
+	var err os.Error
+	perl, err = exec.LookPath("perl")
+	if err != nil {
+		return
+	}
+	perl, _ = filepath.Abs(perl)
+
+	cwd, _ := os.Getwd()
+	h := &Handler{
+		Path: perl,
+		Root: "/test.cgi",
+		Dir:  cwd,
+		Args: []string{cgifile},
+		Env:  []string{"SCRIPT_FILENAME=" + cgifile},
+	}
+	expectedMap := map[string]string{
+		"cwd": cwd,
+	}
+	runCgiTest(t, h, "GET /test.cgi HTTP/1.0\nHost: example.com\n\n", expectedMap)
+
+	// If not specify Dir on windows, working directory should be
+	// base directory of perl.
+	cwd, _ = filepath.Split(perl)
+	if cwd != "" && cwd[len(cwd)-1] == filepath.Separator {
+		cwd = cwd[:len(cwd)-1]
+	}
+	h = &Handler{
+		Path: perl,
+		Root: "/test.cgi",
+		Args: []string{cgifile},
+		Env:  []string{"SCRIPT_FILENAME=" + cgifile},
+	}
+	expectedMap = map[string]string{
+		"cwd": cwd,
+	}
+	runCgiTest(t, h, "GET /test.cgi HTTP/1.0\nHost: example.com\n\n", expectedMap)
+}
diff --git a/src/pkg/http/cgi/testdata/test.cgi b/src/pkg/http/cgi/testdata/test.cgi
index a1b2ff8..36c107f 100755
--- a/src/pkg/http/cgi/testdata/test.cgi
+++ b/src/pkg/http/cgi/testdata/test.cgi
@@ -6,9 +6,9 @@
 # Test script run as a child process under cgi_test.go
 
 use strict;
-use CGI;
+use Cwd;
 
-my $q = CGI->new;
+my $q = MiniCGI->new;
 my $params = $q->Vars;
 
 if ($params->{"loc"}) {
@@ -39,3 +39,50 @@ foreach my $k (sort keys %ENV) {
   $clean_env =~ s/[\n\r]//g;
   print "env-$k=$clean_env\n";
 }
+
+# NOTE: don't call getcwd() for windows.
+# msys return /c/go/src/... not C:\go\...
+my $dir;
+if ($^O eq 'MSWin32' || $^O eq 'msys') {
+  my $cmd = $ENV{'COMSPEC'} || 'c:\\windows\\system32\\cmd.exe';
+  $cmd =~ s!\\!/!g;
+  $dir = `$cmd /c cd`;
+  chomp $dir;
+} else {
+  $dir = getcwd();
+}
+print "cwd=$dir\n";
+
+
+# A minimal version of CGI.pm, for people without the perl-modules
+# package installed.  (CGI.pm used to be part of the Perl core, but
+# some distros now bundle perl-base and perl-modules separately...)
+package MiniCGI;
+
+sub new {
+    my $class = shift;
+    return bless {}, $class;
+}
+
+sub Vars {
+    my $self = shift;
+    my $pairs;
+    if ($ENV{CONTENT_LENGTH}) {
+        $pairs = do { local $/; <STDIN> };
+    } else {
+        $pairs = $ENV{QUERY_STRING};
+    }
+    my $vars = {};
+    foreach my $kv (split(/&/, $pairs)) {
+        my ($k, $v) = split(/=/, $kv, 2);
+        $vars->{_urldecode($k)} = _urldecode($v);
+    }
+    return $vars;
+}
+
+sub _urldecode {
+    my $v = shift;
+    $v =~ tr/+/ /;
+    $v =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
+    return $v;
+}
diff --git a/src/pkg/http/chunked.go b/src/pkg/http/chunked.go
index 59121c5..6c23e69 100644
--- a/src/pkg/http/chunked.go
+++ b/src/pkg/http/chunked.go
@@ -9,6 +9,7 @@ import (
 	"log"
 	"os"
 	"strconv"
+	"bufio"
 )
 
 // NewChunkedWriter returns a new writer that translates writes into HTTP
@@ -64,3 +65,13 @@ func (cw *chunkedWriter) Close() os.Error {
 	_, err := io.WriteString(cw.Wire, "0\r\n")
 	return err
 }
+
+// NewChunkedReader returns a new reader that translates the data read from r
+// out of HTTP "chunked" format before returning it. 
+// The reader returns os.EOF when the final 0-length chunk is read.
+//
+// NewChunkedReader is not needed by normal applications. The http package
+// automatically decodes chunking when reading response bodies.
+func NewChunkedReader(r *bufio.Reader) io.Reader {
+	return &chunkedReader{r: r}
+}
diff --git a/src/pkg/http/cookie.go b/src/pkg/http/cookie.go
index 79c239b..fe70431 100644
--- a/src/pkg/http/cookie.go
+++ b/src/pkg/http/cookie.go
@@ -41,7 +41,7 @@ type Cookie struct {
 func readSetCookies(h Header) []*Cookie {
 	cookies := []*Cookie{}
 	for _, line := range h["Set-Cookie"] {
-		parts := strings.Split(strings.TrimSpace(line), ";", -1)
+		parts := strings.Split(strings.TrimSpace(line), ";")
 		if len(parts) == 1 && parts[0] == "" {
 			continue
 		}
@@ -175,7 +175,7 @@ func readCookies(h Header, filter string) []*Cookie {
 	}
 
 	for _, line := range lines {
-		parts := strings.Split(strings.TrimSpace(line), ";", -1)
+		parts := strings.Split(strings.TrimSpace(line), ";")
 		if len(parts) == 1 && parts[0] == "" {
 			continue
 		}
diff --git a/src/pkg/http/fs.go b/src/pkg/http/fs.go
index 5651298..0b83005 100644
--- a/src/pkg/http/fs.go
+++ b/src/pkg/http/fs.go
@@ -11,6 +11,7 @@ import (
 	"io"
 	"mime"
 	"os"
+	"path"
 	"path/filepath"
 	"strconv"
 	"strings"
@@ -18,6 +19,38 @@ import (
 	"utf8"
 )
 
+// A Dir implements http.FileSystem using the native file
+// system restricted to a specific directory tree.
+type Dir string
+
+func (d Dir) Open(name string) (File, os.Error) {
+	if filepath.Separator != '/' && strings.IndexRune(name, filepath.Separator) >= 0 {
+		return nil, os.NewError("http: invalid character in file path")
+	}
+	f, err := os.Open(filepath.Join(string(d), filepath.FromSlash(path.Clean("/"+name))))
+	if err != nil {
+		return nil, err
+	}
+	return f, nil
+}
+
+// A FileSystem implements access to a collection of named files.
+// The elements in a file path are separated by slash ('/', U+002F)
+// characters, regardless of host operating system convention.
+type FileSystem interface {
+	Open(name string) (File, os.Error)
+}
+
+// A File is returned by a FileSystem's Open method and can be
+// served by the FileServer implementation.
+type File interface {
+	Close() os.Error
+	Stat() (*os.FileInfo, os.Error)
+	Readdir(count int) ([]os.FileInfo, os.Error)
+	Read([]byte) (int, os.Error)
+	Seek(offset int64, whence int) (int64, os.Error)
+}
+
 // Heuristic: b is text if it is valid UTF-8 and doesn't
 // contain any unprintable ASCII or Unicode characters.
 func isText(b []byte) bool {
@@ -44,7 +77,7 @@ func isText(b []byte) bool {
 	return true
 }
 
-func dirList(w ResponseWriter, f *os.File) {
+func dirList(w ResponseWriter, f File) {
 	fmt.Fprintf(w, "<pre>\n")
 	for {
 		dirs, err := f.Readdir(100)
@@ -63,7 +96,8 @@ func dirList(w ResponseWriter, f *os.File) {
 	fmt.Fprintf(w, "</pre>\n")
 }
 
-func serveFile(w ResponseWriter, r *Request, name string, redirect bool) {
+// name is '/'-separated, not filepath.Separator.
+func serveFile(w ResponseWriter, r *Request, fs FileSystem, name string, redirect bool) {
 	const indexPage = "/index.html"
 
 	// redirect .../index.html to .../
@@ -72,7 +106,7 @@ func serveFile(w ResponseWriter, r *Request, name string, redirect bool) {
 		return
 	}
 
-	f, err := os.Open(name)
+	f, err := fs.Open(name)
 	if err != nil {
 		// TODO expose actual error?
 		NotFound(w, r)
@@ -113,7 +147,7 @@ func serveFile(w ResponseWriter, r *Request, name string, redirect bool) {
 	// use contents of index.html for directory, if present
 	if d.IsDirectory() {
 		index := name + filepath.FromSlash(indexPage)
-		ff, err := os.Open(index)
+		ff, err := fs.Open(index)
 		if err == nil {
 			defer ff.Close()
 			dd, err := ff.Stat()
@@ -188,28 +222,26 @@ func serveFile(w ResponseWriter, r *Request, name string, redirect bool) {
 
 // ServeFile replies to the request with the contents of the named file or directory.
 func ServeFile(w ResponseWriter, r *Request, name string) {
-	serveFile(w, r, name, false)
+	serveFile(w, r, Dir(name), "", false)
 }
 
 type fileHandler struct {
-	root   string
-	prefix string
+	root FileSystem
 }
 
 // FileServer returns a handler that serves HTTP requests
 // with the contents of the file system rooted at root.
-// It strips prefix from the incoming requests before
-// looking up the file name in the file system.
-func FileServer(root, prefix string) Handler { return &fileHandler{root, prefix} }
+//
+// To use the operating system's file system implementation,
+// use http.Dir:
+//
+//     http.Handle("/", http.FileServer(http.Dir("/tmp")))
+func FileServer(root FileSystem) Handler {
+	return &fileHandler{root}
+}
 
 func (f *fileHandler) ServeHTTP(w ResponseWriter, r *Request) {
-	path := r.URL.Path
-	if !strings.HasPrefix(path, f.prefix) {
-		NotFound(w, r)
-		return
-	}
-	path = path[len(f.prefix):]
-	serveFile(w, r, filepath.Join(f.root, filepath.FromSlash(path)), true)
+	serveFile(w, r, f.root, path.Clean(r.URL.Path), true)
 }
 
 // httpRange specifies the byte range to be sent to the client.
@@ -227,7 +259,7 @@ func parseRange(s string, size int64) ([]httpRange, os.Error) {
 		return nil, os.NewError("invalid range")
 	}
 	var ranges []httpRange
-	for _, ra := range strings.Split(s[len(b):], ",", -1) {
+	for _, ra := range strings.Split(s[len(b):], ",") {
 		i := strings.Index(ra, "-")
 		if i < 0 {
 			return nil, os.NewError("invalid range")
diff --git a/src/pkg/http/fs_test.go b/src/pkg/http/fs_test.go
index 5540534..dbbdf05 100644
--- a/src/pkg/http/fs_test.go
+++ b/src/pkg/http/fs_test.go
@@ -85,6 +85,72 @@ func TestServeFile(t *testing.T) {
 	}
 }
 
+type testFileSystem struct {
+	open func(name string) (File, os.Error)
+}
+
+func (fs *testFileSystem) Open(name string) (File, os.Error) {
+	return fs.open(name)
+}
+
+func TestFileServerCleans(t *testing.T) {
+	ch := make(chan string, 1)
+	fs := FileServer(&testFileSystem{func(name string) (File, os.Error) {
+		ch <- name
+		return nil, os.ENOENT
+	}})
+	tests := []struct {
+		reqPath, openArg string
+	}{
+		{"/foo.txt", "/foo.txt"},
+		{"//foo.txt", "/foo.txt"},
+		{"/../foo.txt", "/foo.txt"},
+	}
+	req, _ := NewRequest("GET", "http://example.com", nil)
+	for n, test := range tests {
+		rec := httptest.NewRecorder()
+		req.URL.Path = test.reqPath
+		fs.ServeHTTP(rec, req)
+		if got := <-ch; got != test.openArg {
+			t.Errorf("test %d: got %q, want %q", n, got, test.openArg)
+		}
+	}
+}
+
+func TestDirJoin(t *testing.T) {
+	wfi, err := os.Stat("/etc/hosts")
+	if err != nil {
+		t.Logf("skipping test; no /etc/hosts file")
+		return
+	}
+	test := func(d Dir, name string) {
+		f, err := d.Open(name)
+		if err != nil {
+			t.Fatalf("open of %s: %v", name, err)
+		}
+		defer f.Close()
+		gfi, err := f.Stat()
+		if err != nil {
+			t.Fatalf("stat of %s: %v", err)
+		}
+		if gfi.Ino != wfi.Ino {
+			t.Errorf("%s got different inode")
+		}
+	}
+	test(Dir("/etc/"), "/hosts")
+	test(Dir("/etc/"), "hosts")
+	test(Dir("/etc/"), "../../../../hosts")
+	test(Dir("/etc"), "/hosts")
+	test(Dir("/etc"), "hosts")
+	test(Dir("/etc"), "../../../../hosts")
+
+	// Not really directories, but since we use this trick in
+	// ServeFile, test it:
+	test(Dir("/etc/hosts"), "")
+	test(Dir("/etc/hosts"), "/")
+	test(Dir("/etc/hosts"), "../")
+}
+
 func TestServeFileContentType(t *testing.T) {
 	const ctype = "icecream/chocolate"
 	override := false
diff --git a/src/pkg/http/header.go b/src/pkg/http/header.go
index 95a25a8..08b0771 100644
--- a/src/pkg/http/header.go
+++ b/src/pkg/http/header.go
@@ -56,7 +56,7 @@ func (h Header) WriteSubset(w io.Writer, exclude map[string]bool) os.Error {
 			keys = append(keys, k)
 		}
 	}
-	sort.SortStrings(keys)
+	sort.Strings(keys)
 	for _, k := range keys {
 		for _, v := range h[k] {
 			v = strings.Replace(v, "\n", " ", -1)
diff --git a/src/pkg/http/persist.go b/src/pkg/http/persist.go
index 62f9ff1..78bf905 100644
--- a/src/pkg/http/persist.go
+++ b/src/pkg/http/persist.go
@@ -24,6 +24,9 @@ var (
 // to regain control over the connection. ServerConn supports pipe-lining,
 // i.e. requests can be read out of sync (but in the same order) while the
 // respective responses are sent.
+//
+// ServerConn is low-level and should not be needed by most applications.
+// See Server.
 type ServerConn struct {
 	lk              sync.Mutex // read-write protects the following fields
 	c               net.Conn
@@ -211,6 +214,9 @@ func (sc *ServerConn) Write(req *Request, resp *Response) os.Error {
 // connection, while respecting the HTTP keepalive logic. ClientConn
 // supports hijacking the connection calling Hijack to
 // regain control of the underlying net.Conn and deal with it as desired.
+//
+// ClientConn is low-level and should not be needed by most applications.
+// See Client.
 type ClientConn struct {
 	lk              sync.Mutex // read-write protects the following fields
 	c               net.Conn
diff --git a/src/pkg/http/readrequest_test.go b/src/pkg/http/readrequest_test.go
index 0b92b79..79f8de7 100644
--- a/src/pkg/http/readrequest_test.go
+++ b/src/pkg/http/readrequest_test.go
@@ -13,11 +13,15 @@ import (
 )
 
 type reqTest struct {
-	Raw  string
-	Req  Request
-	Body string
+	Raw   string
+	Req   *Request
+	Body  string
+	Error string
 }
 
+var noError = ""
+var noBody = ""
+
 var reqTests = []reqTest{
 	// Baseline test; All Request fields included for template use
 	{
@@ -33,7 +37,7 @@ var reqTests = []reqTest{
 			"Proxy-Connection: keep-alive\r\n\r\n" +
 			"abcdef\n???",
 
-		Request{
+		&Request{
 			Method: "GET",
 			RawURL: "http://www.techcrunch.com/",
 			URL: &URL{
@@ -67,6 +71,34 @@ var reqTests = []reqTest{
 		},
 
 		"abcdef\n",
+
+		noError,
+	},
+
+	// GET request with no body (the normal case)
+	{
+		"GET / HTTP/1.1\r\n" +
+			"Host: foo.com\r\n\r\n",
+
+		&Request{
+			Method: "GET",
+			RawURL: "/",
+			URL: &URL{
+				Raw:     "/",
+				Path:    "/",
+				RawPath: "/",
+			},
+			Proto:         "HTTP/1.1",
+			ProtoMajor:    1,
+			ProtoMinor:    1,
+			Close:         false,
+			ContentLength: 0,
+			Host:          "foo.com",
+			Form:          Values{},
+		},
+
+		noBody,
+		noError,
 	},
 
 	// Tests that we don't parse a path that looks like a
@@ -75,7 +107,7 @@ var reqTests = []reqTest{
 		"GET //user at host/is/actually/a/path/ HTTP/1.1\r\n" +
 			"Host: test\r\n\r\n",
 
-		Request{
+		&Request{
 			Method: "GET",
 			RawURL: "//user at host/is/actually/a/path/",
 			URL: &URL{
@@ -94,12 +126,31 @@ var reqTests = []reqTest{
 			ProtoMinor:    1,
 			Header:        Header{},
 			Close:         false,
-			ContentLength: -1,
+			ContentLength: 0,
 			Host:          "test",
 			Form:          Values{},
 		},
 
-		"",
+		noBody,
+		noError,
+	},
+
+	// Tests a bogus abs_path on the Request-Line (RFC 2616 section 5.1.2)
+	{
+		"GET ../../../../etc/passwd HTTP/1.1\r\n" +
+			"Host: test\r\n\r\n",
+		nil,
+		noBody,
+		"parse ../../../../etc/passwd: invalid URI for request",
+	},
+
+	// Tests missing URL:
+	{
+		"GET  HTTP/1.1\r\n" +
+			"Host: test\r\n\r\n",
+		nil,
+		noBody,
+		"parse : empty url",
 	},
 }
 
@@ -110,12 +161,14 @@ func TestReadRequest(t *testing.T) {
 		braw.WriteString(tt.Raw)
 		req, err := ReadRequest(bufio.NewReader(&braw))
 		if err != nil {
-			t.Errorf("#%d: %s", i, err)
+			if err.String() != tt.Error {
+				t.Errorf("#%d: error %q, want error %q", i, err.String(), tt.Error)
+			}
 			continue
 		}
 		rbody := req.Body
 		req.Body = nil
-		diff(t, fmt.Sprintf("#%d Request", i), req, &tt.Req)
+		diff(t, fmt.Sprintf("#%d Request", i), req, tt.Req)
 		var bout bytes.Buffer
 		if rbody != nil {
 			io.Copy(&bout, rbody)
diff --git a/src/pkg/http/request.go b/src/pkg/http/request.go
index 183a35c..2917cc1 100644
--- a/src/pkg/http/request.go
+++ b/src/pkg/http/request.go
@@ -428,10 +428,6 @@ type chunkedReader struct {
 	err os.Error
 }
 
-func newChunkedReader(r *bufio.Reader) *chunkedReader {
-	return &chunkedReader{r: r}
-}
-
 func (cr *chunkedReader) beginChunk() {
 	// chunk-size CRLF
 	var line string
@@ -511,13 +507,6 @@ func NewRequest(method, url string, body io.Reader) (*Request, os.Error) {
 			req.ContentLength = int64(v.Len())
 		case *bytes.Buffer:
 			req.ContentLength = int64(v.Len())
-		default:
-			req.ContentLength = -1 // chunked
-		}
-		if req.ContentLength == 0 {
-			// To prevent chunking and disambiguate this
-			// from the default ContentLength zero value.
-			req.TransferEncoding = []string{"identity"}
 		}
 	}
 
@@ -550,7 +539,7 @@ func ReadRequest(b *bufio.Reader) (req *Request, err os.Error) {
 	}
 
 	var f []string
-	if f = strings.Split(s, " ", 3); len(f) < 3 {
+	if f = strings.SplitN(s, " ", 3); len(f) < 3 {
 		return nil, &badStringError{"malformed HTTP request", s}
 	}
 	req.Method, req.RawURL, req.Proto = f[0], f[1], f[2]
@@ -669,11 +658,11 @@ func ParseQuery(query string) (m Values, err os.Error) {
 }
 
 func parseQuery(m Values, query string) (err os.Error) {
-	for _, kv := range strings.Split(query, "&", -1) {
+	for _, kv := range strings.Split(query, "&") {
 		if len(kv) == 0 {
 			continue
 		}
-		kvPair := strings.Split(kv, "=", 2)
+		kvPair := strings.SplitN(kv, "=", 2)
 
 		var key, value string
 		var e os.Error
@@ -710,7 +699,7 @@ func (r *Request) ParseForm() (err os.Error) {
 			return os.NewError("missing form body")
 		}
 		ct := r.Header.Get("Content-Type")
-		switch strings.Split(ct, ";", 2)[0] {
+		switch strings.SplitN(ct, ";", 2)[0] {
 		case "text/plain", "application/x-www-form-urlencoded", "":
 			const maxFormSize = int64(10 << 20) // 10 MB is a lot of text.
 			b, e := ioutil.ReadAll(io.LimitReader(r.Body, maxFormSize+1))
diff --git a/src/pkg/http/requestwrite_test.go b/src/pkg/http/requestwrite_test.go
index 43ad525..0052c0c 100644
--- a/src/pkg/http/requestwrite_test.go
+++ b/src/pkg/http/requestwrite_test.go
@@ -6,6 +6,7 @@ package http
 
 import (
 	"bytes"
+	"fmt"
 	"io"
 	"io/ioutil"
 	"os"
@@ -15,7 +16,7 @@ import (
 
 type reqWriteTest struct {
 	Req      Request
-	Body     []byte
+	Body     interface{} // optional []byte or func() io.ReadCloser to populate Req.Body
 	Raw      string
 	RawProxy string
 }
@@ -98,13 +99,13 @@ var reqWriteTests = []reqWriteTest{
 			"Host: www.google.com\r\n" +
 			"User-Agent: Go http package\r\n" +
 			"Transfer-Encoding: chunked\r\n\r\n" +
-			"6\r\nabcdef\r\n0\r\n\r\n",
+			chunk("abcdef") + chunk(""),
 
 		"GET http://www.google.com/search HTTP/1.1\r\n" +
 			"Host: www.google.com\r\n" +
 			"User-Agent: Go http package\r\n" +
 			"Transfer-Encoding: chunked\r\n\r\n" +
-			"6\r\nabcdef\r\n0\r\n\r\n",
+			chunk("abcdef") + chunk(""),
 	},
 	// HTTP/1.1 POST => chunked coding; body; empty trailer
 	{
@@ -129,14 +130,14 @@ var reqWriteTests = []reqWriteTest{
 			"User-Agent: Go http package\r\n" +
 			"Connection: close\r\n" +
 			"Transfer-Encoding: chunked\r\n\r\n" +
-			"6\r\nabcdef\r\n0\r\n\r\n",
+			chunk("abcdef") + chunk(""),
 
 		"POST http://www.google.com/search HTTP/1.1\r\n" +
 			"Host: www.google.com\r\n" +
 			"User-Agent: Go http package\r\n" +
 			"Connection: close\r\n" +
 			"Transfer-Encoding: chunked\r\n\r\n" +
-			"6\r\nabcdef\r\n0\r\n\r\n",
+			chunk("abcdef") + chunk(""),
 	},
 
 	// HTTP/1.1 POST with Content-Length, no chunking
@@ -224,13 +225,72 @@ var reqWriteTests = []reqWriteTest{
 			"User-Agent: Go http package\r\n" +
 			"\r\n",
 	},
+
+	// Request with a 0 ContentLength and a 0 byte body.
+	{
+		Request{
+			Method:        "POST",
+			RawURL:        "/",
+			Host:          "example.com",
+			ProtoMajor:    1,
+			ProtoMinor:    1,
+			ContentLength: 0, // as if unset by user
+		},
+
+		func() io.ReadCloser { return ioutil.NopCloser(io.LimitReader(strings.NewReader("xx"), 0)) },
+
+		"POST / HTTP/1.1\r\n" +
+			"Host: example.com\r\n" +
+			"User-Agent: Go http package\r\n" +
+			"\r\n",
+
+		"POST / HTTP/1.1\r\n" +
+			"Host: example.com\r\n" +
+			"User-Agent: Go http package\r\n" +
+			"\r\n",
+	},
+
+	// Request with a 0 ContentLength and a 1 byte body.
+	{
+		Request{
+			Method:        "POST",
+			RawURL:        "/",
+			Host:          "example.com",
+			ProtoMajor:    1,
+			ProtoMinor:    1,
+			ContentLength: 0, // as if unset by user
+		},
+
+		func() io.ReadCloser { return ioutil.NopCloser(io.LimitReader(strings.NewReader("xx"), 1)) },
+
+		"POST / HTTP/1.1\r\n" +
+			"Host: example.com\r\n" +
+			"User-Agent: Go http package\r\n" +
+			"Transfer-Encoding: chunked\r\n\r\n" +
+			chunk("x") + chunk(""),
+
+		"POST / HTTP/1.1\r\n" +
+			"Host: example.com\r\n" +
+			"User-Agent: Go http package\r\n" +
+			"Transfer-Encoding: chunked\r\n\r\n" +
+			chunk("x") + chunk(""),
+	},
 }
 
 func TestRequestWrite(t *testing.T) {
 	for i := range reqWriteTests {
 		tt := &reqWriteTests[i]
+
+		setBody := func() {
+			switch b := tt.Body.(type) {
+			case []byte:
+				tt.Req.Body = ioutil.NopCloser(bytes.NewBuffer(b))
+			case func() io.ReadCloser:
+				tt.Req.Body = b()
+			}
+		}
 		if tt.Body != nil {
-			tt.Req.Body = ioutil.NopCloser(bytes.NewBuffer(tt.Body))
+			setBody()
 		}
 		if tt.Req.Header == nil {
 			tt.Req.Header = make(Header)
@@ -248,7 +308,7 @@ func TestRequestWrite(t *testing.T) {
 		}
 
 		if tt.Body != nil {
-			tt.Req.Body = ioutil.NopCloser(bytes.NewBuffer(tt.Body))
+			setBody()
 		}
 		var praw bytes.Buffer
 		err = tt.Req.WriteProxy(&praw)
@@ -280,41 +340,30 @@ func (rc *closeChecker) Close() os.Error {
 func TestRequestWriteClosesBody(t *testing.T) {
 	rc := &closeChecker{Reader: strings.NewReader("my body")}
 	req, _ := NewRequest("POST", "http://foo.com/", rc)
-	if g, e := req.ContentLength, int64(-1); g != e {
-		t.Errorf("got req.ContentLength %d, want %d", g, e)
+	if req.ContentLength != 0 {
+		t.Errorf("got req.ContentLength %d, want 0", req.ContentLength)
 	}
 	buf := new(bytes.Buffer)
 	req.Write(buf)
 	if !rc.closed {
 		t.Error("body not closed after write")
 	}
-	if g, e := buf.String(), "POST / HTTP/1.1\r\nHost: foo.com\r\nUser-Agent: Go http package\r\nTransfer-Encoding: chunked\r\n\r\n7\r\nmy body\r\n0\r\n\r\n"; g != e {
-		t.Errorf("write:\n got: %s\nwant: %s", g, e)
+	expected := "POST / HTTP/1.1\r\n" +
+		"Host: foo.com\r\n" +
+		"User-Agent: Go http package\r\n" +
+		"Transfer-Encoding: chunked\r\n\r\n" +
+		// TODO: currently we don't buffer before chunking, so we get a
+		// single "m" chunk before the other chunks, as this was the 1-byte
+		// read from our MultiReader where we stiched the Body back together
+		// after sniffing whether the Body was 0 bytes or not.
+		chunk("m") +
+		chunk("y body") +
+		chunk("")
+	if buf.String() != expected {
+		t.Errorf("write:\n got: %s\nwant: %s", buf.String(), expected)
 	}
 }
 
-func TestZeroLengthNewRequest(t *testing.T) {
-	var buf bytes.Buffer
-
-	// Writing with default identity encoding
-	req, _ := NewRequest("PUT", "http://foo.com/", strings.NewReader(""))
-	if len(req.TransferEncoding) == 0 || req.TransferEncoding[0] != "identity" {
-		t.Fatalf("got req.TransferEncoding of %v, want %v", req.TransferEncoding, []string{"identity"})
-	}
-	if g, e := req.ContentLength, int64(0); g != e {
-		t.Errorf("got req.ContentLength %d, want %d", g, e)
-	}
-	req.Write(&buf)
-	if g, e := buf.String(), "PUT / HTTP/1.1\r\nHost: foo.com\r\nUser-Agent: Go http package\r\nContent-Length: 0\r\n\r\n"; g != e {
-		t.Errorf("identity write:\n got: %s\nwant: %s", g, e)
-	}
-
-	// Overriding identity encoding and forcing chunked.
-	req, _ = NewRequest("PUT", "http://foo.com/", strings.NewReader(""))
-	req.TransferEncoding = nil
-	buf.Reset()
-	req.Write(&buf)
-	if g, e := buf.String(), "PUT / HTTP/1.1\r\nHost: foo.com\r\nUser-Agent: Go http package\r\nTransfer-Encoding: chunked\r\n\r\n0\r\n\r\n"; g != e {
-		t.Errorf("chunked write:\n got: %s\nwant: %s", g, e)
-	}
+func chunk(s string) string {
+	return fmt.Sprintf("%x\r\n%s\r\n", len(s), s)
 }
diff --git a/src/pkg/http/response.go b/src/pkg/http/response.go
index 6c0c441..915327a 100644
--- a/src/pkg/http/response.go
+++ b/src/pkg/http/response.go
@@ -95,7 +95,7 @@ func ReadResponse(r *bufio.Reader, req *Request) (resp *Response, err os.Error)
 		}
 		return nil, err
 	}
-	f := strings.Split(line, " ", 3)
+	f := strings.SplitN(line, " ", 3)
 	if len(f) < 2 {
 		return nil, &badStringError{"malformed HTTP response", line}
 	}
diff --git a/src/pkg/http/reverseproxy_test.go b/src/pkg/http/reverseproxy_test.go
index bc08614..b2dd246 100644
--- a/src/pkg/http/reverseproxy_test.go
+++ b/src/pkg/http/reverseproxy_test.go
@@ -17,6 +17,9 @@ func TestReverseProxy(t *testing.T) {
 	const backendResponse = "I am the backend"
 	const backendStatus = 404
 	backend := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+		if len(r.TransferEncoding) > 0 {
+			t.Errorf("backend got unexpected TransferEncoding: %v", r.TransferEncoding)
+		}
 		if r.Header.Get("X-Forwarded-For") == "" {
 			t.Errorf("didn't get X-Forwarded-For header")
 		}
diff --git a/src/pkg/http/serve_test.go b/src/pkg/http/serve_test.go
index 40de547..55a9cbf 100644
--- a/src/pkg/http/serve_test.go
+++ b/src/pkg/http/serve_test.go
@@ -373,11 +373,8 @@ func TestIdentityResponse(t *testing.T) {
 	}
 }
 
-// TestServeHTTP10Close verifies that HTTP/1.0 requests won't be kept alive.
-func TestServeHTTP10Close(t *testing.T) {
-	s := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
-		ServeFile(w, r, "testdata/file")
-	}))
+func testTcpConnectionCloses(t *testing.T, req string, h Handler) {
+	s := httptest.NewServer(h)
 	defer s.Close()
 
 	conn, err := net.Dial("tcp", s.Listener.Addr().String())
@@ -386,7 +383,7 @@ func TestServeHTTP10Close(t *testing.T) {
 	}
 	defer conn.Close()
 
-	_, err = fmt.Fprint(conn, "GET / HTTP/1.0\r\n\r\n")
+	_, err = fmt.Fprint(conn, req)
 	if err != nil {
 		t.Fatal("print error:", err)
 	}
@@ -414,6 +411,27 @@ func TestServeHTTP10Close(t *testing.T) {
 	success <- true
 }
 
+// TestServeHTTP10Close verifies that HTTP/1.0 requests won't be kept alive.
+func TestServeHTTP10Close(t *testing.T) {
+	testTcpConnectionCloses(t, "GET / HTTP/1.0\r\n\r\n", HandlerFunc(func(w ResponseWriter, r *Request) {
+		ServeFile(w, r, "testdata/file")
+	}))
+}
+
+// TestHandlersCanSetConnectionClose verifies that handlers can force a connection to close,
+// even for HTTP/1.1 requests.
+func TestHandlersCanSetConnectionClose11(t *testing.T) {
+	testTcpConnectionCloses(t, "GET / HTTP/1.1\r\n\r\n", HandlerFunc(func(w ResponseWriter, r *Request) {
+		w.Header().Set("Connection", "close")
+	}))
+}
+
+func TestHandlersCanSetConnectionClose10(t *testing.T) {
+	testTcpConnectionCloses(t, "GET / HTTP/1.0\r\nConnection: keep-alive\r\n\r\n", HandlerFunc(func(w ResponseWriter, r *Request) {
+		w.Header().Set("Connection", "close")
+	}))
+}
+
 func TestSetsRemoteAddr(t *testing.T) {
 	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
 		fmt.Fprintf(w, "%s", r.RemoteAddr)
@@ -522,7 +540,12 @@ func TestHeadResponses(t *testing.T) {
 
 func TestTLSServer(t *testing.T) {
 	ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) {
-		fmt.Fprintf(w, "tls=%v", r.TLS != nil)
+		if r.TLS != nil {
+			w.Header().Set("X-TLS-Set", "true")
+			if r.TLS.HandshakeComplete {
+				w.Header().Set("X-TLS-HandshakeComplete", "true")
+			}
+		}
 	}))
 	defer ts.Close()
 	if !strings.HasPrefix(ts.URL, "https://") {
@@ -530,20 +553,17 @@ func TestTLSServer(t *testing.T) {
 	}
 	res, err := Get(ts.URL)
 	if err != nil {
-		t.Error(err)
+		t.Fatal(err)
 	}
 	if res == nil {
 		t.Fatalf("got nil Response")
 	}
-	if res.Body == nil {
-		t.Fatalf("got nil Response.Body")
-	}
-	body, err := ioutil.ReadAll(res.Body)
-	if err != nil {
-		t.Error(err)
+	defer res.Body.Close()
+	if res.Header.Get("X-TLS-Set") != "true" {
+		t.Errorf("expected X-TLS-Set response header")
 	}
-	if e, g := "tls=true", string(body); e != g {
-		t.Errorf("expected body %q; got %q", e, g)
+	if res.Header.Get("X-TLS-HandshakeComplete") != "true" {
+		t.Errorf("expected X-TLS-HandshakeComplete header")
 	}
 }
 
@@ -796,6 +816,30 @@ func TestNoDate(t *testing.T) {
 	}
 }
 
+func TestStripPrefix(t *testing.T) {
+	h := HandlerFunc(func(w ResponseWriter, r *Request) {
+		w.Header().Set("X-Path", r.URL.Path)
+	})
+	ts := httptest.NewServer(StripPrefix("/foo", h))
+	defer ts.Close()
+
+	res, err := Get(ts.URL + "/foo/bar")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if g, e := res.Header.Get("X-Path"), "/bar"; g != e {
+		t.Errorf("test 1: got %s, want %s", g, e)
+	}
+
+	res, err = Get(ts.URL + "/bar")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if g, e := res.StatusCode, 404; g != e {
+		t.Errorf("test 2: got status %v, want %v", g, e)
+	}
+}
+
 type errorListener struct {
 	errs []os.Error
 }
diff --git a/src/pkg/http/server.go b/src/pkg/http/server.go
index 7f1b8a2..ab960f4 100644
--- a/src/pkg/http/server.go
+++ b/src/pkg/http/server.go
@@ -152,6 +152,7 @@ func newConn(rwc net.Conn, handler Handler) (c *conn, err os.Error) {
 	c.buf = bufio.NewReadWriter(br, bw)
 
 	if tlsConn, ok := rwc.(*tls.Conn); ok {
+		tlsConn.Handshake()
 		c.tlsState = new(tls.ConnectionState)
 		*c.tlsState = tlsConn.ConnectionState()
 	}
@@ -314,6 +315,10 @@ func (w *response) WriteHeader(code int) {
 		w.closeAfterReply = true
 	}
 
+	if w.header.Get("Connection") == "close" {
+		w.closeAfterReply = true
+	}
+
 	// Cannot use Content-Length with non-identity Transfer-Encoding.
 	if w.chunking {
 		w.header.Del("Content-Length")
@@ -416,7 +421,7 @@ func errorKludge(w *response) {
 	msg += " would ignore this error page if this text weren't here.\n"
 
 	// Is it text?  ("Content-Type" is always in the map)
-	baseType := strings.Split(w.header.Get("Content-Type"), ";", 2)[0]
+	baseType := strings.SplitN(w.header.Get("Content-Type"), ";", 2)[0]
 	switch baseType {
 	case "text/html":
 		io.WriteString(w, "<!-- ")
@@ -591,6 +596,22 @@ func NotFound(w ResponseWriter, r *Request) { Error(w, "404 page not found", Sta
 // that replies to each request with a ``404 page not found'' reply.
 func NotFoundHandler() Handler { return HandlerFunc(NotFound) }
 
+// StripPrefix returns a handler that serves HTTP requests
+// by removing the given prefix from the request URL's Path
+// and invoking the handler h. StripPrefix handles a
+// request for a path that doesn't begin with prefix by
+// replying with an HTTP 404 not found error.
+func StripPrefix(prefix string, h Handler) Handler {
+	return HandlerFunc(func(w ResponseWriter, r *Request) {
+		if !strings.HasPrefix(r.URL.Path, prefix) {
+			NotFound(w, r)
+			return
+		}
+		r.URL.Path = r.URL.Path[len(prefix):]
+		h.ServeHTTP(w, r)
+	})
+}
+
 // Redirect replies to the request with a redirect to url,
 // which may be a path relative to the request path.
 func Redirect(w ResponseWriter, r *Request, url string, code int) {
diff --git a/src/pkg/http/spdy/read.go b/src/pkg/http/spdy/read.go
index 8adec7b..c6b6ab3 100644
--- a/src/pkg/http/spdy/read.go
+++ b/src/pkg/http/spdy/read.go
@@ -174,7 +174,7 @@ func parseHeaderValueBlock(r io.Reader, streamId uint32) (http.Header, os.Error)
 		if _, err := io.ReadFull(r, value); err != nil {
 			return nil, err
 		}
-		valueList := strings.Split(string(value), "\x00", -1)
+		valueList := strings.Split(string(value), "\x00")
 		for _, v := range valueList {
 			h.Add(name, v)
 		}
diff --git a/src/pkg/http/transfer.go b/src/pkg/http/transfer.go
index b54508e..b65d99a 100644
--- a/src/pkg/http/transfer.go
+++ b/src/pkg/http/transfer.go
@@ -5,6 +5,7 @@
 package http
 
 import (
+	"bytes"
 	"bufio"
 	"io"
 	"io/ioutil"
@@ -17,7 +18,8 @@ import (
 // sanitizes them without changing the user object and provides methods for
 // writing the respective header, body and trailer in wire format.
 type transferWriter struct {
-	Body             io.ReadCloser
+	Body             io.Reader
+	BodyCloser       io.Closer
 	ResponseToHEAD   bool
 	ContentLength    int64
 	Close            bool
@@ -33,16 +35,37 @@ func newTransferWriter(r interface{}) (t *transferWriter, err os.Error) {
 	switch rr := r.(type) {
 	case *Request:
 		t.Body = rr.Body
+		t.BodyCloser = rr.Body
 		t.ContentLength = rr.ContentLength
 		t.Close = rr.Close
 		t.TransferEncoding = rr.TransferEncoding
 		t.Trailer = rr.Trailer
 		atLeastHTTP11 = rr.ProtoAtLeast(1, 1)
-		if t.Body != nil && t.ContentLength <= 0 && len(t.TransferEncoding) == 0 && atLeastHTTP11 {
-			t.TransferEncoding = []string{"chunked"}
+		if t.Body != nil && len(t.TransferEncoding) == 0 && atLeastHTTP11 {
+			if t.ContentLength == 0 {
+				// Test to see if it's actually zero or just unset.
+				var buf [1]byte
+				n, _ := io.ReadFull(t.Body, buf[:])
+				if n == 1 {
+					// Oh, guess there is data in this Body Reader after all.
+					// The ContentLength field just wasn't set.
+					// Stich the Body back together again, re-attaching our
+					// consumed byte.
+					t.ContentLength = -1
+					t.Body = io.MultiReader(bytes.NewBuffer(buf[:]), t.Body)
+				} else {
+					// Body is actually empty.
+					t.Body = nil
+					t.BodyCloser = nil
+				}
+			}
+			if t.ContentLength < 0 {
+				t.TransferEncoding = []string{"chunked"}
+			}
 		}
 	case *Response:
 		t.Body = rr.Body
+		t.BodyCloser = rr.Body
 		t.ContentLength = rr.ContentLength
 		t.Close = rr.Close
 		t.TransferEncoding = rr.TransferEncoding
@@ -147,7 +170,7 @@ func (t *transferWriter) WriteBody(w io.Writer) (err os.Error) {
 		if err != nil {
 			return err
 		}
-		if err = t.Body.Close(); err != nil {
+		if err = t.BodyCloser.Close(); err != nil {
 			return err
 		}
 	}
@@ -195,6 +218,7 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err os.Error) {
 	t := &transferReader{}
 
 	// Unify input
+	isResponse := false
 	switch rr := msg.(type) {
 	case *Response:
 		t.Header = rr.Header
@@ -203,6 +227,7 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err os.Error) {
 		t.ProtoMajor = rr.ProtoMajor
 		t.ProtoMinor = rr.ProtoMinor
 		t.Close = shouldClose(t.ProtoMajor, t.ProtoMinor, t.Header)
+		isResponse = true
 	case *Request:
 		t.Header = rr.Header
 		t.ProtoMajor = rr.ProtoMajor
@@ -211,6 +236,8 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err os.Error) {
 		// Responses with status code 200, responding to a GET method
 		t.StatusCode = 200
 		t.RequestMethod = "GET"
+	default:
+		panic("unexpected type")
 	}
 
 	// Default to HTTP/1.1
@@ -224,7 +251,7 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err os.Error) {
 		return err
 	}
 
-	t.ContentLength, err = fixLength(t.StatusCode, t.RequestMethod, t.Header, t.TransferEncoding)
+	t.ContentLength, err = fixLength(isResponse, t.StatusCode, t.RequestMethod, t.Header, t.TransferEncoding)
 	if err != nil {
 		return err
 	}
@@ -252,7 +279,7 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err os.Error) {
 	// or close connection when finished, since multipart is not supported yet
 	switch {
 	case chunked(t.TransferEncoding):
-		t.Body = &body{Reader: newChunkedReader(r), hdr: msg, r: r, closing: t.Close}
+		t.Body = &body{Reader: NewChunkedReader(r), hdr: msg, r: r, closing: t.Close}
 	case t.ContentLength >= 0:
 		// TODO: limit the Content-Length. This is an easy DoS vector.
 		t.Body = &body{Reader: io.LimitReader(r, t.ContentLength), closing: t.Close}
@@ -265,9 +292,6 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err os.Error) {
 			// Persistent connection (i.e. HTTP/1.1)
 			t.Body = &body{Reader: io.LimitReader(r, 0), closing: t.Close}
 		}
-		// TODO(petar): It may be a good idea, for extra robustness, to
-		// assume ContentLength=0 for GET requests (and other special
-		// cases?). This logic should be in fixLength().
 	}
 
 	// Unify output
@@ -310,7 +334,7 @@ func fixTransferEncoding(requestMethod string, header Header) ([]string, os.Erro
 		return nil, nil
 	}
 
-	encodings := strings.Split(raw[0], ",", -1)
+	encodings := strings.Split(raw[0], ",")
 	te := make([]string, 0, len(encodings))
 	// TODO: Even though we only support "identity" and "chunked"
 	// encodings, the loop below is designed with foresight. One
@@ -345,7 +369,7 @@ func fixTransferEncoding(requestMethod string, header Header) ([]string, os.Erro
 // Determine the expected body length, using RFC 2616 Section 4.4. This
 // function is not a method, because ultimately it should be shared by
 // ReadResponse and ReadRequest.
-func fixLength(status int, requestMethod string, header Header, te []string) (int64, os.Error) {
+func fixLength(isResponse bool, status int, requestMethod string, header Header, te []string) (int64, os.Error) {
 
 	// Logic based on response type or status
 	if noBodyExpected(requestMethod) {
@@ -376,6 +400,14 @@ func fixLength(status int, requestMethod string, header Header, te []string) (in
 		header.Del("Content-Length")
 	}
 
+	if !isResponse && requestMethod == "GET" {
+		// RFC 2616 doesn't explicitly permit nor forbid an
+		// entity-body on a GET request so we permit one if
+		// declared, but we default to 0 here (not -1 below)
+		// if there's no mention of a body.
+		return 0, nil
+	}
+
 	// Logic based on media type. The purpose of the following code is just
 	// to detect whether the unsupported "multipart/byteranges" is being
 	// used. A proper Content-Type parser is needed in the future.
@@ -418,7 +450,7 @@ func fixTrailer(header Header, te []string) (Header, os.Error) {
 
 	header.Del("Trailer")
 	trailer := make(Header)
-	keys := strings.Split(raw, ",", -1)
+	keys := strings.Split(raw, ",")
 	for _, key := range keys {
 		key = CanonicalHeaderKey(strings.TrimSpace(key))
 		switch key {
diff --git a/src/pkg/http/transport.go b/src/pkg/http/transport.go
index 9ad1590..3c16c88 100644
--- a/src/pkg/http/transport.go
+++ b/src/pkg/http/transport.go
@@ -329,7 +329,7 @@ func (t *Transport) getConn(cm *connectMethod) (*persistConn, os.Error) {
 			return nil, err
 		}
 		if resp.StatusCode != 200 {
-			f := strings.Split(resp.Status, " ", 2)
+			f := strings.SplitN(resp.Status, " ", 2)
 			conn.Close()
 			return nil, os.NewError(f[1])
 		}
@@ -383,7 +383,7 @@ func useProxy(addr string) bool {
 		addr = addr[:strings.LastIndex(addr, ":")]
 	}
 
-	for _, p := range strings.Split(no_proxy, ",", -1) {
+	for _, p := range strings.Split(no_proxy, ",") {
 		p = strings.ToLower(strings.TrimSpace(p))
 		if len(p) == 0 {
 			continue
diff --git a/src/pkg/http/url.go b/src/pkg/http/url.go
index beb0b82..e934b27 100644
--- a/src/pkg/http/url.go
+++ b/src/pkg/http/url.go
@@ -508,8 +508,8 @@ func (v Values) Encode() string {
 // resolvePath applies special path segments from refs and applies
 // them to base, per RFC 2396.
 func resolvePath(basepath string, refpath string) string {
-	base := strings.Split(basepath, "/", -1)
-	refs := strings.Split(refpath, "/", -1)
+	base := strings.Split(basepath, "/")
+	refs := strings.Split(refpath, "/")
 	if len(base) == 0 {
 		base = []string{""}
 	}
diff --git a/src/pkg/image/draw/draw_test.go b/src/pkg/image/draw/draw_test.go
index 6db5672..55435cc 100644
--- a/src/pkg/image/draw/draw_test.go
+++ b/src/pkg/image/draw/draw_test.go
@@ -154,22 +154,32 @@ var drawTests = []drawTest{
 	{"genericSrc", fillBlue(255), vgradAlpha(192), Src, image.RGBAColor{0, 0, 102, 102}},
 }
 
-func makeGolden(dst, src, mask image.Image, op Op) image.Image {
+func makeGolden(dst image.Image, r image.Rectangle, src image.Image, sp image.Point, mask image.Image, mp image.Point, op Op) image.Image {
 	// Since golden is a newly allocated image, we don't have to check if the
 	// input source and mask images and the output golden image overlap.
 	b := dst.Bounds()
-	sx0 := src.Bounds().Min.X - b.Min.X
-	sy0 := src.Bounds().Min.Y - b.Min.Y
-	var mx0, my0 int
+	sb := src.Bounds()
+	mb := image.Rect(-1e9, -1e9, 1e9, 1e9)
 	if mask != nil {
-		mx0 = mask.Bounds().Min.X - b.Min.X
-		my0 = mask.Bounds().Min.Y - b.Min.Y
+		mb = mask.Bounds()
 	}
 	golden := image.NewRGBA(b.Max.X, b.Max.Y)
-	for y := b.Min.Y; y < b.Max.Y; y++ {
-		my, sy := my0+y, sy0+y
-		for x := b.Min.X; x < b.Max.X; x++ {
-			mx, sx := mx0+x, sx0+x
+	for y := r.Min.Y; y < r.Max.Y; y++ {
+		sy := y + sp.Y - r.Min.Y
+		my := y + mp.Y - r.Min.Y
+		for x := r.Min.X; x < r.Max.X; x++ {
+			if !(image.Point{x, y}.In(b)) {
+				continue
+			}
+			sx := x + sp.X - r.Min.X
+			if !(image.Point{sx, sy}.In(sb)) {
+				continue
+			}
+			mx := x + mp.X - r.Min.X
+			if !(image.Point{mx, my}.In(mb)) {
+				continue
+			}
+
 			const M = 1<<16 - 1
 			var dr, dg, db, da uint32
 			if op == Over {
@@ -189,35 +199,49 @@ func makeGolden(dst, src, mask image.Image, op Op) image.Image {
 			})
 		}
 	}
-	golden.Rect = b
-	return golden
+	return golden.SubImage(b)
 }
 
 func TestDraw(t *testing.T) {
-loop:
-	for _, test := range drawTests {
-		dst := hgradRed(255)
-		// Draw the (src, mask, op) onto a copy of dst using a slow but obviously correct implementation.
-		golden := makeGolden(dst, test.src, test.mask, test.op)
-		b := dst.Bounds()
-		if !b.Eq(golden.Bounds()) {
-			t.Errorf("draw %s: bounds %v versus %v", test.desc, dst.Bounds(), golden.Bounds())
-			continue
-		}
-		// Draw the same combination onto the actual dst using the optimized DrawMask implementation.
-		DrawMask(dst, b, test.src, image.ZP, test.mask, image.ZP, test.op)
-		// Check that the resultant pixel at (8, 8) matches what we expect
-		// (the expected value can be verified by hand).
-		if !eq(dst.At(8, 8), test.expected) {
-			t.Errorf("draw %s: at (8, 8) %v versus %v", test.desc, dst.At(8, 8), test.expected)
-			continue
-		}
-		// Check that the resultant dst image matches the golden output.
-		for y := b.Min.Y; y < b.Max.Y; y++ {
-			for x := b.Min.X; x < b.Max.X; x++ {
-				if !eq(dst.At(x, y), golden.At(x, y)) {
-					t.Errorf("draw %s: at (%d, %d), %v versus golden %v", test.desc, x, y, dst.At(x, y), golden.At(x, y))
-					continue loop
+	rr := []image.Rectangle{
+		image.Rect(0, 0, 0, 0),
+		image.Rect(0, 0, 16, 16),
+		image.Rect(3, 5, 12, 10),
+		image.Rect(0, 0, 9, 9),
+		image.Rect(8, 8, 16, 16),
+		image.Rect(8, 0, 9, 16),
+		image.Rect(0, 8, 16, 9),
+		image.Rect(8, 8, 9, 9),
+		image.Rect(8, 8, 8, 8),
+	}
+	for _, r := range rr {
+	loop:
+		for _, test := range drawTests {
+			dst := hgradRed(255).(*image.RGBA).SubImage(r).(Image)
+			// Draw the (src, mask, op) onto a copy of dst using a slow but obviously correct implementation.
+			golden := makeGolden(dst, image.Rect(0, 0, 16, 16), test.src, image.ZP, test.mask, image.ZP, test.op)
+			b := dst.Bounds()
+			if !b.Eq(golden.Bounds()) {
+				t.Errorf("draw %v %s: bounds %v versus %v", r, test.desc, dst.Bounds(), golden.Bounds())
+				continue
+			}
+			// Draw the same combination onto the actual dst using the optimized DrawMask implementation.
+			DrawMask(dst, image.Rect(0, 0, 16, 16), test.src, image.ZP, test.mask, image.ZP, test.op)
+			if image.Pt(8, 8).In(r) {
+				// Check that the resultant pixel at (8, 8) matches what we expect
+				// (the expected value can be verified by hand).
+				if !eq(dst.At(8, 8), test.expected) {
+					t.Errorf("draw %v %s: at (8, 8) %v versus %v", r, test.desc, dst.At(8, 8), test.expected)
+					continue
+				}
+			}
+			// Check that the resultant dst image matches the golden output.
+			for y := b.Min.Y; y < b.Max.Y; y++ {
+				for x := b.Min.X; x < b.Max.X; x++ {
+					if !eq(dst.At(x, y), golden.At(x, y)) {
+						t.Errorf("draw %v %s: at (%d, %d), %v versus golden %v", r, test.desc, x, y, dst.At(x, y), golden.At(x, y))
+						continue loop
+					}
 				}
 			}
 		}
@@ -230,19 +254,11 @@ func TestDrawOverlap(t *testing.T) {
 		loop:
 			for xoff := -2; xoff <= 2; xoff++ {
 				m := gradYellow(127).(*image.RGBA)
-				dst := &image.RGBA{
-					Pix:    m.Pix,
-					Stride: m.Stride,
-					Rect:   image.Rect(5, 5, 10, 10),
-				}
-				src := &image.RGBA{
-					Pix:    m.Pix,
-					Stride: m.Stride,
-					Rect:   image.Rect(5+xoff, 5+yoff, 10+xoff, 10+yoff),
-				}
-				// Draw the (src, mask, op) onto a copy of dst using a slow but obviously correct implementation.
-				golden := makeGolden(dst, src, nil, op)
+				dst := m.SubImage(image.Rect(5, 5, 10, 10)).(*image.RGBA)
+				src := m.SubImage(image.Rect(5+xoff, 5+yoff, 10+xoff, 10+yoff)).(*image.RGBA)
 				b := dst.Bounds()
+				// Draw the (src, mask, op) onto a copy of dst using a slow but obviously correct implementation.
+				golden := makeGolden(dst, b, src, src.Bounds().Min, nil, image.ZP, op)
 				if !b.Eq(golden.Bounds()) {
 					t.Errorf("drawOverlap xoff=%d,yoff=%d: bounds %v versus %v", xoff, yoff, dst.Bounds(), golden.Bounds())
 					continue
@@ -276,3 +292,63 @@ func TestNonZeroSrcPt(t *testing.T) {
 		t.Errorf("non-zero src pt: want %v got %v", image.RGBAColor{5, 0, 0, 5}, a.At(0, 0))
 	}
 }
+
+func TestFill(t *testing.T) {
+	rr := []image.Rectangle{
+		image.Rect(0, 0, 0, 0),
+		image.Rect(0, 0, 40, 30),
+		image.Rect(10, 0, 40, 30),
+		image.Rect(0, 20, 40, 30),
+		image.Rect(10, 20, 40, 30),
+		image.Rect(10, 20, 15, 25),
+		image.Rect(10, 0, 35, 30),
+		image.Rect(0, 15, 40, 16),
+		image.Rect(24, 24, 25, 25),
+		image.Rect(23, 23, 26, 26),
+		image.Rect(22, 22, 27, 27),
+		image.Rect(21, 21, 28, 28),
+		image.Rect(20, 20, 29, 29),
+	}
+	for _, r := range rr {
+		m := image.NewRGBA(40, 30).SubImage(r).(*image.RGBA)
+		b := m.Bounds()
+		c := image.RGBAColor{11, 0, 0, 255}
+		src := &image.ColorImage{c}
+		check := func(desc string) {
+			for y := b.Min.Y; y < b.Max.Y; y++ {
+				for x := b.Min.X; x < b.Max.X; x++ {
+					if !eq(c, m.At(x, y)) {
+						t.Errorf("%s fill: at (%d, %d), sub-image bounds=%v: want %v got %v", desc, x, y, r, c, m.At(x, y))
+						return
+					}
+				}
+			}
+		}
+		// Draw 1 pixel at a time.
+		for y := b.Min.Y; y < b.Max.Y; y++ {
+			for x := b.Min.X; x < b.Max.X; x++ {
+				DrawMask(m, image.Rect(x, y, x+1, y+1), src, image.ZP, nil, image.ZP, Src)
+			}
+		}
+		check("pixel")
+		// Draw 1 row at a time.
+		c = image.RGBAColor{0, 22, 0, 255}
+		src = &image.ColorImage{c}
+		for y := b.Min.Y; y < b.Max.Y; y++ {
+			DrawMask(m, image.Rect(b.Min.X, y, b.Max.X, y+1), src, image.ZP, nil, image.ZP, Src)
+		}
+		check("row")
+		// Draw 1 column at a time.
+		c = image.RGBAColor{0, 0, 33, 255}
+		src = &image.ColorImage{c}
+		for x := b.Min.X; x < b.Max.X; x++ {
+			DrawMask(m, image.Rect(x, b.Min.Y, x+1, b.Max.Y), src, image.ZP, nil, image.ZP, Src)
+		}
+		check("column")
+		// Draw the whole image at once.
+		c = image.RGBAColor{44, 55, 66, 77}
+		src = &image.ColorImage{c}
+		DrawMask(m, b, src, image.ZP, nil, image.ZP, Src)
+		check("whole")
+	}
+}
diff --git a/src/pkg/image/image.go b/src/pkg/image/image.go
index f4c38d2..5ea302d 100644
--- a/src/pkg/image/image.go
+++ b/src/pkg/image/image.go
@@ -548,7 +548,7 @@ func NewGray16(w, h int) *Gray16 {
 	return &Gray16{pix, w, Rectangle{ZP, Point{w, h}}}
 }
 
-// A PalettedColorModel represents a fixed palette of colors.
+// A PalettedColorModel represents a fixed palette of at most 256 colors.
 type PalettedColorModel []Color
 
 func diff(a, b uint32) uint32 {
@@ -648,7 +648,20 @@ func (p *Paletted) SubImage(r Rectangle) Image {
 
 // Opaque scans the entire image and returns whether or not it is fully opaque.
 func (p *Paletted) Opaque() bool {
-	for _, c := range p.Palette {
+	var present [256]bool
+	base := p.Rect.Min.Y * p.Stride
+	i0, i1 := base+p.Rect.Min.X, base+p.Rect.Max.X
+	for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
+		for _, c := range p.Pix[i0:i1] {
+			present[c] = true
+		}
+		i0 += p.Stride
+		i1 += p.Stride
+	}
+	for i, c := range p.Palette {
+		if !present[i] {
+			continue
+		}
 		_, _, _, a := c.RGBA()
 		if a != 0xffff {
 			return false
diff --git a/src/pkg/image/image_test.go b/src/pkg/image/image_test.go
index f167f7f..5469d64 100644
--- a/src/pkg/image/image_test.go
+++ b/src/pkg/image/image_test.go
@@ -10,6 +10,7 @@ import (
 
 type image interface {
 	Image
+	Opaque() bool
 	Set(int, int, Color)
 	SubImage(Rectangle) Image
 }
@@ -49,6 +50,10 @@ func TestImage(t *testing.T) {
 			t.Errorf("%T: at (6, 3), want a non-zero color, got %v", m, m.At(6, 3))
 			continue
 		}
+		if !m.SubImage(Rect(6, 3, 7, 4)).(image).Opaque() {
+			t.Errorf("%T: at (6, 3) was not opaque", m)
+			continue
+		}
 		m = m.SubImage(Rect(3, 2, 9, 8)).(image)
 		if !Rect(3, 2, 9, 8).Eq(m.Bounds()) {
 			t.Errorf("%T: sub-image want bounds %v, got %v", m, Rect(3, 2, 9, 8), m.Bounds())
diff --git a/src/pkg/index/suffixarray/suffixarray.go b/src/pkg/index/suffixarray/suffixarray.go
index 079b7d8..9d4e932 100644
--- a/src/pkg/index/suffixarray/suffixarray.go
+++ b/src/pkg/index/suffixarray/suffixarray.go
@@ -115,7 +115,7 @@ func (x *Index) FindAllIndex(r *regexp.Regexp, n int) (result [][]int) {
 			if len(indices) == 0 {
 				return
 			}
-			sort.SortInts(indices)
+			sort.Ints(indices)
 			pairs := make([]int, 2*len(indices))
 			result = make([][]int, len(indices))
 			count := 0
@@ -159,7 +159,7 @@ func (x *Index) FindAllIndex(r *regexp.Regexp, n int) (result [][]int) {
 		if len(indices) == 0 {
 			return
 		}
-		sort.SortInts(indices)
+		sort.Ints(indices)
 		result = result[0:0]
 		prev := 0
 		for _, i := range indices {
diff --git a/src/pkg/index/suffixarray/suffixarray_test.go b/src/pkg/index/suffixarray/suffixarray_test.go
index b149902..385ff0e 100644
--- a/src/pkg/index/suffixarray/suffixarray_test.go
+++ b/src/pkg/index/suffixarray/suffixarray_test.go
@@ -141,7 +141,7 @@ func testLookup(t *testing.T, tc *testCase, x *Index, s string, n int) {
 	// we cannot simply check that the res and exp lists are equal
 
 	// check that each result is in fact a correct match and there are no duplicates
-	sort.SortInts(res)
+	sort.Ints(res)
 	for i, r := range res {
 		if r < 0 || len(tc.source) <= r {
 			t.Errorf("test %q, lookup %q, result %d (n = %d): index %d out of range [0, %d[", tc.name, s, i, n, r, len(tc.source))
diff --git a/src/pkg/io/io.go b/src/pkg/io/io.go
index 790cf94..b879fe5 100644
--- a/src/pkg/io/io.go
+++ b/src/pkg/io/io.go
@@ -209,8 +209,16 @@ type RuneScanner interface {
 	UnreadRune() os.Error
 }
 
+// stringWriter is the interface that wraps the WriteString method.
+type stringWriter interface {
+	WriteString(s string) (n int, err os.Error)
+}
+
 // WriteString writes the contents of the string s to w, which accepts an array of bytes.
 func WriteString(w Writer, s string) (n int, err os.Error) {
+	if sw, ok := w.(stringWriter); ok {
+		return sw.WriteString(s)
+	}
 	return w.Write([]byte(s))
 }
 
diff --git a/src/pkg/json/decode.go b/src/pkg/json/decode.go
index e78b60c..35a06b0 100644
--- a/src/pkg/json/decode.go
+++ b/src/pkg/json/decode.go
@@ -482,7 +482,7 @@ func (d *decodeState) object(v reflect.Value) {
 			if isValidTag(key) {
 				for i := 0; i < sv.NumField(); i++ {
 					f = st.Field(i)
-					if f.Tag == key {
+					if f.Tag.Get("json") == key {
 						ok = true
 						break
 					}
diff --git a/src/pkg/json/decode_test.go b/src/pkg/json/decode_test.go
index bf8bf10..9b84bc7 100644
--- a/src/pkg/json/decode_test.go
+++ b/src/pkg/json/decode_test.go
@@ -42,8 +42,9 @@ var (
 
 type badTag struct {
 	X string
-	Y string "y"
-	Z string "@#*%(#@"
+	Y string `json:"y"`
+	Z string `x:"@#*%(#@"`
+	W string `json:"@#$@#$"`
 }
 
 type unmarshalTest struct {
@@ -68,7 +69,7 @@ var unmarshalTests = []unmarshalTest{
 	{`{"x": 1}`, new(tx), tx{}, &UnmarshalFieldError{"x", txType, txType.Field(0)}},
 
 	// skip invalid tags
-	{`{"X":"a", "y":"b", "Z":"c"}`, new(badTag), badTag{"a", "b", "c"}, nil},
+	{`{"X":"a", "y":"b", "Z":"c", "W":"d"}`, new(badTag), badTag{"a", "b", "c", "d"}, nil},
 
 	// syntax errors
 	{`{"X": "foo", "Y"}`, nil, nil, &SyntaxError{"invalid character '}' after object key", 17}},
@@ -250,7 +251,7 @@ type All struct {
 	Float32 float32
 	Float64 float64
 
-	Foo string "bar"
+	Foo string `json:"bar"`
 
 	PBool    *bool
 	PInt     *int
diff --git a/src/pkg/json/encode.go b/src/pkg/json/encode.go
index ec0a14a..adc0f0f 100644
--- a/src/pkg/json/encode.go
+++ b/src/pkg/json/encode.go
@@ -36,11 +36,13 @@ import (
 // Array and slice values encode as JSON arrays, except that
 // []byte encodes as a base64-encoded string.
 //
-// Struct values encode as JSON objects.  Each struct field becomes
-// a member of the object.  By default the object's key name is the
-// struct field name.  If the struct field has a non-empty tag consisting
-// of only Unicode letters, digits, and underscores, that tag will be used
-// as the name instead.  Only exported fields will be encoded.
+// Struct values encode as JSON objects.  Each exported struct field
+// becomes a member of the object.  By default the object's key string
+// is the struct field name.  If the struct field's tag has a "json" key with a
+// value that is a non-empty string consisting of only Unicode letters,
+// digits, and underscores, that value will be used as the object key.
+// For example, the field tag `json:"myName"` says to use "myName"
+// as the object key.
 //
 // Map values encode as JSON objects.
 // The map's key type must be string; the object keys are used directly
@@ -236,8 +238,8 @@ func (e *encodeState) reflectValue(v reflect.Value) {
 			} else {
 				e.WriteByte(',')
 			}
-			if isValidTag(f.Tag) {
-				e.string(f.Tag)
+			if tag := f.Tag.Get("json"); tag != "" && isValidTag(tag) {
+				e.string(tag)
 			} else {
 				e.string(f.Name)
 			}
diff --git a/src/pkg/json/scanner_test.go b/src/pkg/json/scanner_test.go
index 0d4de32..023e7c8 100644
--- a/src/pkg/json/scanner_test.go
+++ b/src/pkg/json/scanner_test.go
@@ -252,7 +252,10 @@ func genArray(n int) []interface{} {
 	if f > n {
 		f = n
 	}
-	x := make([]interface{}, int(f))
+	if n > 0 && f == 0 {
+		f = 1
+	}
+	x := make([]interface{}, f)
 	for i := range x {
 		x[i] = genValue(((i+1)*n)/f - (i*n)/f)
 	}
diff --git a/src/pkg/mail/message.go b/src/pkg/mail/message.go
index fce287b..e227d17 100644
--- a/src/pkg/mail/message.go
+++ b/src/pkg/mail/message.go
@@ -425,7 +425,7 @@ func (p *addrParser) len() int {
 }
 
 func decodeRFC2047Word(s string) (string, os.Error) {
-	fields := strings.Split(s, "?", -1)
+	fields := strings.Split(s, "?")
 	if len(fields) != 5 || fields[0] != "=" || fields[4] != "=" {
 		return "", os.NewError("mail: address not RFC 2047 encoded")
 	}
diff --git a/src/pkg/mime/mediatype.go b/src/pkg/mime/mediatype.go
index a270cb9..40c735c 100644
--- a/src/pkg/mime/mediatype.go
+++ b/src/pkg/mime/mediatype.go
@@ -32,10 +32,12 @@ func validMediaTypeOrDisposition(s string) bool {
 
 // ParseMediaType parses a media type value and any optional
 // parameters, per RFC 1521.  Media types are the values in
-// Content-Type and Content-Disposition headers (RFC 2183).  On
-// success, ParseMediaType returns the media type converted to
-// lowercase and trimmed of white space and a non-nil params.  On
-// error, it returns an empty string and a nil params.
+// Content-Type and Content-Disposition headers (RFC 2183).
+// On success, ParseMediaType returns the media type converted
+// to lowercase and trimmed of white space. The returned params
+// is always a non-nil map. Params maps from the lowercase
+// attribute to the attribute value with its case preserved.
+// On error, it returns an empty string and a nil params.
 func ParseMediaType(v string) (mediatype string, params map[string]string) {
 	i := strings.Index(v, ";")
 	if i == -1 {
@@ -132,7 +134,7 @@ func ParseMediaType(v string) (mediatype string, params map[string]string) {
 }
 
 func decode2231Enc(v string) string {
-	sv := strings.Split(v, "'", 3)
+	sv := strings.SplitN(v, "'", 3)
 	if len(sv) != 3 {
 		return ""
 	}
@@ -211,6 +213,7 @@ func consumeMediaParam(v string) (param, value, rest string) {
 	rest = rest[1:] // consume semicolon
 	rest = strings.TrimLeftFunc(rest, unicode.IsSpace)
 	param, rest = consumeToken(rest)
+	param = strings.ToLower(param)
 	if param == "" {
 		return "", "", v
 	}
diff --git a/src/pkg/mime/mediatype_test.go b/src/pkg/mime/mediatype_test.go
index 454ddd0..93264bd 100644
--- a/src/pkg/mime/mediatype_test.go
+++ b/src/pkg/mime/mediatype_test.go
@@ -60,6 +60,7 @@ func TestConsumeMediaParam(t *testing.T) {
 		{" ; foo=bar", "foo", "bar", ""},
 		{"; foo=bar", "foo", "bar", ""},
 		{";foo=bar", "foo", "bar", ""},
+		{";FOO=bar", "foo", "bar", ""},
 		{`;foo="bar"`, "foo", "bar", ""},
 		{`;foo="bar"; `, "foo", "bar", "; "},
 		{`;foo="bar"; foo=baz`, "foo", "bar", "; foo=baz"},
@@ -127,7 +128,7 @@ func TestParseMediaType(t *testing.T) {
 			`URL*1="cs.utk.edu/pub/moore/bulk-mailer/bulk-mailer.tar"`,
 			"message/external-body",
 			m("access-type", "URL",
-				"URL", "ftp://cs.utk.edu/pub/moore/bulk-mailer/bulk-mailer.tar")},
+				"url", "ftp://cs.utk.edu/pub/moore/bulk-mailer/bulk-mailer.tar")},
 
 		{`application/x-stuff; ` +
 			`title*0*=us-ascii'en'This%20is%20even%20more%20; ` +
diff --git a/src/pkg/mime/multipart/multipart.go b/src/pkg/mime/multipart/multipart.go
index 5c173f2..4711fd7 100644
--- a/src/pkg/mime/multipart/multipart.go
+++ b/src/pkg/mime/multipart/multipart.go
@@ -24,6 +24,11 @@ import (
 	"regexp"
 )
 
+// TODO(bradfitz): inline these once the compiler can inline them in
+// read-only situation (such as bytes.HasSuffix)
+var lf = []byte("\n")
+var crlf = []byte("\r\n")
+
 var headerRegexp *regexp.Regexp = regexp.MustCompile("^([a-zA-Z0-9\\-]+): *([^\r\n]+)")
 
 var emptyParams = make(map[string]string)
@@ -81,6 +86,7 @@ func NewReader(reader io.Reader, boundary string) *Reader {
 	return &Reader{
 		bufReader: bufio.NewReader(reader),
 
+		nl:               b[:2],
 		nlDashBoundary:   b[:len(b)-2],
 		dashBoundaryDash: b[2:],
 		dashBoundary:     b[2 : len(b)-2],
@@ -180,7 +186,7 @@ type Reader struct {
 	currentPart *Part
 	partsRead   int
 
-	nlDashBoundary, dashBoundaryDash, dashBoundary []byte
+	nl, nlDashBoundary, dashBoundaryDash, dashBoundary []byte
 }
 
 // NextPart returns the next part in the multipart or an error.
@@ -221,11 +227,11 @@ func (mr *Reader) NextPart() (*Part, os.Error) {
 			continue
 		}
 
-		if bytes.Equal(line, []byte("\r\n")) {
-			// Consume the "\r\n" separator between the
-			// body of the previous part and the boundary
-			// line we now expect will follow. (either a
-			// new part or the end boundary)
+		// Consume the "\n" or "\r\n" separator between the
+		// body of the previous part and the boundary line we
+		// now expect will follow. (either a new part or the
+		// end boundary)
+		if bytes.Equal(line, mr.nl) {
 			expectNewPart = true
 			continue
 		}
@@ -245,13 +251,17 @@ func (mr *Reader) isBoundaryDelimiterLine(line []byte) bool {
 	if !bytes.HasPrefix(line, mr.dashBoundary) {
 		return false
 	}
-	if bytes.HasSuffix(line, []byte("\r\n")) {
-		return onlyHorizontalWhitespace(line[len(mr.dashBoundary) : len(line)-2])
+	if bytes.HasSuffix(line, mr.nl) {
+		return onlyHorizontalWhitespace(line[len(mr.dashBoundary) : len(line)-len(mr.nl)])
 	}
 	// Violate the spec and also support newlines without the
 	// carriage return...
-	if bytes.HasSuffix(line, []byte("\n")) {
-		return onlyHorizontalWhitespace(line[len(mr.dashBoundary) : len(line)-1])
+	if mr.partsRead == 0 && bytes.HasSuffix(line, lf) {
+		if onlyHorizontalWhitespace(line[len(mr.dashBoundary) : len(line)-1]) {
+			mr.nl = mr.nl[1:]
+			mr.nlDashBoundary = mr.nlDashBoundary[1:]
+			return true
+		}
 	}
 	return false
 }
@@ -268,5 +278,5 @@ func onlyHorizontalWhitespace(s []byte) bool {
 func hasPrefixThenNewline(s, prefix []byte) bool {
 	return bytes.HasPrefix(s, prefix) &&
 		(len(s) == len(prefix)+1 && s[len(s)-1] == '\n' ||
-			len(s) == len(prefix)+2 && bytes.HasSuffix(s, []byte("\r\n")))
+			len(s) == len(prefix)+2 && bytes.HasSuffix(s, crlf))
 }
diff --git a/src/pkg/mime/multipart/multipart_test.go b/src/pkg/mime/multipart/multipart_test.go
index 8bc16bb..1357466 100644
--- a/src/pkg/mime/multipart/multipart_test.go
+++ b/src/pkg/mime/multipart/multipart_test.go
@@ -81,7 +81,7 @@ func TestNameAccessors(t *testing.T) {
 
 var longLine = strings.Repeat("\n\n\r\r\r\n\r\000", (1<<20)/8)
 
-func testMultipartBody() string {
+func testMultipartBody(sep string) string {
 	testBody := `
 This is a multi-part message.  This line is ignored.
 --MyBoundary
@@ -112,21 +112,26 @@ never read data
 
 useless trailer
 `
-	testBody = strings.Replace(testBody, "\n", "\r\n", -1)
+	testBody = strings.Replace(testBody, "\n", sep, -1)
 	return strings.Replace(testBody, "[longline]", longLine, 1)
 }
 
 func TestMultipart(t *testing.T) {
-	bodyReader := strings.NewReader(testMultipartBody())
-	testMultipart(t, bodyReader)
+	bodyReader := strings.NewReader(testMultipartBody("\r\n"))
+	testMultipart(t, bodyReader, false)
+}
+
+func TestMultipartOnlyNewlines(t *testing.T) {
+	bodyReader := strings.NewReader(testMultipartBody("\n"))
+	testMultipart(t, bodyReader, true)
 }
 
 func TestMultipartSlowInput(t *testing.T) {
-	bodyReader := strings.NewReader(testMultipartBody())
-	testMultipart(t, &slowReader{bodyReader})
+	bodyReader := strings.NewReader(testMultipartBody("\r\n"))
+	testMultipart(t, &slowReader{bodyReader}, false)
 }
 
-func testMultipart(t *testing.T, r io.Reader) {
+func testMultipart(t *testing.T, r io.Reader, onlyNewlines bool) {
 	reader := NewReader(r, "MyBoundary")
 	buf := new(bytes.Buffer)
 
@@ -149,8 +154,15 @@ func testMultipart(t *testing.T, r io.Reader) {
 	if _, err := io.Copy(buf, part); err != nil {
 		t.Errorf("part 1 copy: %v", err)
 	}
-	expectEq(t, "My value\r\nThe end.",
-		buf.String(), "Value of first part")
+
+	adjustNewlines := func(s string) string {
+		if onlyNewlines {
+			return strings.Replace(s, "\r\n", "\n", -1)
+		}
+		return s
+	}
+
+	expectEq(t, adjustNewlines("My value\r\nThe end."), buf.String(), "Value of first part")
 
 	// Part2
 	part, err = reader.NextPart()
@@ -187,7 +199,7 @@ func testMultipart(t *testing.T, r io.Reader) {
 	if _, err := io.Copy(buf, part); err != nil {
 		t.Errorf("part 3 copy: %v", err)
 	}
-	expectEq(t, "Line 1\r\nLine 2\r\nLine 3 ends in a newline, but just one.\r\n",
+	expectEq(t, adjustNewlines("Line 1\r\nLine 2\r\nLine 3 ends in a newline, but just one.\r\n"),
 		buf.String(), "body of part 3")
 
 	// Part4
diff --git a/src/pkg/net/dial.go b/src/pkg/net/dial.go
index ead775f..10c67dc 100644
--- a/src/pkg/net/dial.go
+++ b/src/pkg/net/dial.go
@@ -6,6 +6,28 @@ package net
 
 import "os"
 
+func resolveNetAddr(op, net, addr string) (a Addr, err os.Error) {
+	if addr == "" {
+		return nil, &OpError{op, net, nil, errMissingAddress}
+	}
+	switch net {
+	case "tcp", "tcp4", "tcp6":
+		a, err = ResolveTCPAddr(net, addr)
+	case "udp", "udp4", "udp6":
+		a, err = ResolveUDPAddr(net, addr)
+	case "unix", "unixgram", "unixpacket":
+		a, err = ResolveUnixAddr(net, addr)
+	case "ip", "ip4", "ip6":
+		a, err = ResolveIPAddr(net, addr)
+	default:
+		err = UnknownNetworkError(net)
+	}
+	if err != nil {
+		return nil, &OpError{op, net + " " + addr, nil, err}
+	}
+	return
+}
+
 // Dial connects to the address addr on the network net.
 //
 // Known networks are "tcp", "tcp4" (IPv4-only), "tcp6" (IPv6-only),
@@ -23,56 +45,26 @@ import "os"
 //	Dial("tcp", "[de:ad:be:ef::ca:fe]:80")
 //
 func Dial(net, addr string) (c Conn, err os.Error) {
-	raddr := addr
-	if raddr == "" {
-		return nil, &OpError{"dial", net, nil, errMissingAddress}
+	addri, err := resolveNetAddr("dial", net, addr)
+	if err != nil {
+		return nil, err
 	}
-	switch net {
-	case "tcp", "tcp4", "tcp6":
-		var ra *TCPAddr
-		if ra, err = ResolveTCPAddr(net, raddr); err != nil {
-			goto Error
-		}
-		c, err := DialTCP(net, nil, ra)
-		if err != nil {
-			return nil, err
-		}
-		return c, nil
-	case "udp", "udp4", "udp6":
-		var ra *UDPAddr
-		if ra, err = ResolveUDPAddr(net, raddr); err != nil {
-			goto Error
-		}
-		c, err := DialUDP(net, nil, ra)
-		if err != nil {
-			return nil, err
-		}
-		return c, nil
-	case "unix", "unixgram", "unixpacket":
-		var ra *UnixAddr
-		if ra, err = ResolveUnixAddr(net, raddr); err != nil {
-			goto Error
-		}
+	switch ra := addri.(type) {
+	case *TCPAddr:
+		c, err = DialTCP(net, nil, ra)
+	case *UDPAddr:
+		c, err = DialUDP(net, nil, ra)
+	case *UnixAddr:
 		c, err = DialUnix(net, nil, ra)
-		if err != nil {
-			return nil, err
-		}
-		return c, nil
-	case "ip", "ip4", "ip6":
-		var ra *IPAddr
-		if ra, err = ResolveIPAddr(net, raddr); err != nil {
-			goto Error
-		}
-		c, err := DialIP(net, nil, ra)
-		if err != nil {
-			return nil, err
-		}
-		return c, nil
-
+	case *IPAddr:
+		c, err = DialIP(net, nil, ra)
+	default:
+		err = UnknownNetworkError(net)
+	}
+	if err != nil {
+		return nil, &OpError{"dial", net + " " + addr, nil, err}
 	}
-	err = UnknownNetworkError(net)
-Error:
-	return nil, &OpError{"dial", net + " " + raddr, nil, err}
+	return
 }
 
 // Listen announces on the local network address laddr.
diff --git a/src/pkg/net/dnsmsg.go b/src/pkg/net/dnsmsg.go
index ade1bb3..640973b 100644
--- a/src/pkg/net/dnsmsg.go
+++ b/src/pkg/net/dnsmsg.go
@@ -93,7 +93,7 @@ const (
 
 // DNS queries.
 type dnsQuestion struct {
-	Name   string "domain-name" // "domain-name" specifies encoding; see packers below
+	Name   string `net:"domain-name"` // `net:"domain-name"` specifies encoding; see packers below
 	Qtype  uint16
 	Qclass uint16
 }
@@ -102,7 +102,7 @@ type dnsQuestion struct {
 // There are many types of messages,
 // but they all share the same header.
 type dnsRR_Header struct {
-	Name     string "domain-name"
+	Name     string `net:"domain-name"`
 	Rrtype   uint16
 	Class    uint16
 	Ttl      uint32
@@ -121,7 +121,7 @@ type dnsRR interface {
 
 type dnsRR_CNAME struct {
 	Hdr   dnsRR_Header
-	Cname string "domain-name"
+	Cname string `net:"domain-name"`
 }
 
 func (rr *dnsRR_CNAME) Header() *dnsRR_Header {
@@ -140,7 +140,7 @@ func (rr *dnsRR_HINFO) Header() *dnsRR_Header {
 
 type dnsRR_MB struct {
 	Hdr dnsRR_Header
-	Mb  string "domain-name"
+	Mb  string `net:"domain-name"`
 }
 
 func (rr *dnsRR_MB) Header() *dnsRR_Header {
@@ -149,7 +149,7 @@ func (rr *dnsRR_MB) Header() *dnsRR_Header {
 
 type dnsRR_MG struct {
 	Hdr dnsRR_Header
-	Mg  string "domain-name"
+	Mg  string `net:"domain-name"`
 }
 
 func (rr *dnsRR_MG) Header() *dnsRR_Header {
@@ -158,8 +158,8 @@ func (rr *dnsRR_MG) Header() *dnsRR_Header {
 
 type dnsRR_MINFO struct {
 	Hdr   dnsRR_Header
-	Rmail string "domain-name"
-	Email string "domain-name"
+	Rmail string `net:"domain-name"`
+	Email string `net:"domain-name"`
 }
 
 func (rr *dnsRR_MINFO) Header() *dnsRR_Header {
@@ -168,7 +168,7 @@ func (rr *dnsRR_MINFO) Header() *dnsRR_Header {
 
 type dnsRR_MR struct {
 	Hdr dnsRR_Header
-	Mr  string "domain-name"
+	Mr  string `net:"domain-name"`
 }
 
 func (rr *dnsRR_MR) Header() *dnsRR_Header {
@@ -178,7 +178,7 @@ func (rr *dnsRR_MR) Header() *dnsRR_Header {
 type dnsRR_MX struct {
 	Hdr  dnsRR_Header
 	Pref uint16
-	Mx   string "domain-name"
+	Mx   string `net:"domain-name"`
 }
 
 func (rr *dnsRR_MX) Header() *dnsRR_Header {
@@ -187,7 +187,7 @@ func (rr *dnsRR_MX) Header() *dnsRR_Header {
 
 type dnsRR_NS struct {
 	Hdr dnsRR_Header
-	Ns  string "domain-name"
+	Ns  string `net:"domain-name"`
 }
 
 func (rr *dnsRR_NS) Header() *dnsRR_Header {
@@ -196,7 +196,7 @@ func (rr *dnsRR_NS) Header() *dnsRR_Header {
 
 type dnsRR_PTR struct {
 	Hdr dnsRR_Header
-	Ptr string "domain-name"
+	Ptr string `net:"domain-name"`
 }
 
 func (rr *dnsRR_PTR) Header() *dnsRR_Header {
@@ -205,8 +205,8 @@ func (rr *dnsRR_PTR) Header() *dnsRR_Header {
 
 type dnsRR_SOA struct {
 	Hdr     dnsRR_Header
-	Ns      string "domain-name"
-	Mbox    string "domain-name"
+	Ns      string `net:"domain-name"`
+	Mbox    string `net:"domain-name"`
 	Serial  uint32
 	Refresh uint32
 	Retry   uint32
@@ -232,7 +232,7 @@ type dnsRR_SRV struct {
 	Priority uint16
 	Weight   uint16
 	Port     uint16
-	Target   string "domain-name"
+	Target   string `net:"domain-name"`
 }
 
 func (rr *dnsRR_SRV) Header() *dnsRR_Header {
@@ -241,7 +241,7 @@ func (rr *dnsRR_SRV) Header() *dnsRR_Header {
 
 type dnsRR_A struct {
 	Hdr dnsRR_Header
-	A   uint32 "ipv4"
+	A   uint32 `net:"ipv4"`
 }
 
 func (rr *dnsRR_A) Header() *dnsRR_Header {
@@ -250,7 +250,7 @@ func (rr *dnsRR_A) Header() *dnsRR_Header {
 
 type dnsRR_AAAA struct {
 	Hdr  dnsRR_Header
-	AAAA [16]byte "ipv6"
+	AAAA [16]byte `net:"ipv6"`
 }
 
 func (rr *dnsRR_AAAA) Header() *dnsRR_Header {
@@ -435,7 +435,7 @@ func packStructValue(val reflect.Value, msg []byte, off int) (off1 int, ok bool)
 			default:
 				fmt.Fprintf(os.Stderr, "net: dns: unknown string tag %v", f.Tag)
 				return len(msg), false
-			case "domain-name":
+			case `net:"domain-name"`:
 				off, ok = packDomainName(s, msg, off)
 				if !ok {
 					return len(msg), false
@@ -506,7 +506,7 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, ok boo
 			default:
 				fmt.Fprintf(os.Stderr, "net: dns: unknown string tag %v", f.Tag)
 				return len(msg), false
-			case "domain-name":
+			case `net:"domain-name"`:
 				s, off, ok = unpackDomainName(msg, off)
 				if !ok {
 					return len(msg), false
@@ -536,9 +536,9 @@ func unpackStruct(any interface{}, msg []byte, off int) (off1 int, ok bool) {
 }
 
 // Generic struct printer.
-// Doesn't care about the string tag "domain-name",
-// but does look for an "ipv4" tag on uint32 variables
-// and the "ipv6" tag on array variables,
+// Doesn't care about the string tag `net:"domain-name"`,
+// but does look for an `net:"ipv4"` tag on uint32 variables
+// and the `net:"ipv6"` tag on array variables,
 // printing them as IP addresses.
 func printStructValue(val reflect.Value) string {
 	s := "{"
@@ -553,10 +553,10 @@ func printStructValue(val reflect.Value) string {
 		fval := val.Field(i)
 		if fv := fval; fv.Kind() == reflect.Struct {
 			s += printStructValue(fv)
-		} else if fv := fval; (fv.Kind() == reflect.Uint || fv.Kind() == reflect.Uint8 || fv.Kind() == reflect.Uint16 || fv.Kind() == reflect.Uint32 || fv.Kind() == reflect.Uint64 || fv.Kind() == reflect.Uintptr) && f.Tag == "ipv4" {
+		} else if fv := fval; (fv.Kind() == reflect.Uint || fv.Kind() == reflect.Uint8 || fv.Kind() == reflect.Uint16 || fv.Kind() == reflect.Uint32 || fv.Kind() == reflect.Uint64 || fv.Kind() == reflect.Uintptr) && f.Tag == `net:"ipv4"` {
 			i := fv.Uint()
 			s += IPv4(byte(i>>24), byte(i>>16), byte(i>>8), byte(i)).String()
-		} else if fv := fval; fv.Kind() == reflect.Array && f.Tag == "ipv6" {
+		} else if fv := fval; fv.Kind() == reflect.Array && f.Tag == `net:"ipv6"` {
 			i := fv.Interface().([]byte)
 			s += IP(i).String()
 		} else {
diff --git a/src/pkg/net/fd_windows.go b/src/pkg/net/fd_windows.go
index 9ed7801..41d0612 100644
--- a/src/pkg/net/fd_windows.go
+++ b/src/pkg/net/fd_windows.go
@@ -29,8 +29,8 @@ func init() {
 	}
 }
 
-func closesocket(s int) (errno int) {
-	return syscall.Closesocket(int32(s))
+func closesocket(s syscall.Handle) (errno int) {
+	return syscall.Closesocket(s)
 }
 
 // Interface for all io operations.
@@ -88,7 +88,7 @@ func (o *bufOp) Init(fd *netFD, buf []byte) {
 // iocp and send them to the correspondent waiting client
 // goroutine via channel supplied in the request.
 type resultSrv struct {
-	iocp int32
+	iocp syscall.Handle
 }
 
 func (s *resultSrv) Run() {
@@ -132,7 +132,7 @@ func (s *ioSrv) ProcessRemoteIO() {
 		case o := <-s.submchan:
 			o.Op().errnoc <- o.Submit()
 		case o := <-s.canchan:
-			o.Op().errnoc <- syscall.CancelIo(uint32(o.Op().fd.sysfd))
+			o.Op().errnoc <- syscall.CancelIo(syscall.Handle(o.Op().fd.sysfd))
 		}
 	}
 }
@@ -189,7 +189,7 @@ var onceStartServer sync.Once
 func startServer() {
 	resultsrv = new(resultSrv)
 	var errno int
-	resultsrv.iocp, errno = syscall.CreateIoCompletionPort(-1, 0, 0, 1)
+	resultsrv.iocp, errno = syscall.CreateIoCompletionPort(syscall.InvalidHandle, 0, 0, 1)
 	if errno != 0 {
 		panic("CreateIoCompletionPort failed " + syscall.Errstr(errno))
 	}
@@ -209,7 +209,7 @@ type netFD struct {
 	closing bool
 
 	// immutable until Close
-	sysfd  int
+	sysfd  syscall.Handle
 	family int
 	proto  int
 	net    string
@@ -225,7 +225,7 @@ type netFD struct {
 	wio             sync.Mutex
 }
 
-func allocFD(fd, family, proto int, net string) (f *netFD) {
+func allocFD(fd syscall.Handle, family, proto int, net string) (f *netFD) {
 	f = &netFD{
 		sysfd:  fd,
 		family: family,
@@ -236,13 +236,13 @@ func allocFD(fd, family, proto int, net string) (f *netFD) {
 	return f
 }
 
-func newFD(fd, family, proto int, net string) (f *netFD, err os.Error) {
+func newFD(fd syscall.Handle, family, proto int, net string) (f *netFD, err os.Error) {
 	if initErr != nil {
 		return nil, initErr
 	}
 	onceStartServer.Do(startServer)
 	// Associate our socket with resultsrv.iocp.
-	if _, e := syscall.CreateIoCompletionPort(int32(fd), resultsrv.iocp, 0, 0); e != 0 {
+	if _, e := syscall.CreateIoCompletionPort(syscall.Handle(fd), resultsrv.iocp, 0, 0); e != 0 {
 		return nil, os.Errno(e)
 	}
 	return allocFD(fd, family, proto, net), nil
@@ -280,7 +280,7 @@ func (fd *netFD) decref() {
 		// use the resultsrv for Close too.  Sigh.
 		syscall.SetNonblock(fd.sysfd, false)
 		closesocket(fd.sysfd)
-		fd.sysfd = -1
+		fd.sysfd = syscall.InvalidHandle
 		// no need for a finalizer anymore
 		runtime.SetFinalizer(fd, nil)
 	}
@@ -288,7 +288,7 @@ func (fd *netFD) decref() {
 }
 
 func (fd *netFD) Close() os.Error {
-	if fd == nil || fd.sysfd == -1 {
+	if fd == nil || fd.sysfd == syscall.InvalidHandle {
 		return os.EINVAL
 	}
 
@@ -307,7 +307,7 @@ type readOp struct {
 
 func (o *readOp) Submit() (errno int) {
 	var d, f uint32
-	return syscall.WSARecv(uint32(o.fd.sysfd), &o.buf, 1, &d, &f, &o.o, nil)
+	return syscall.WSARecv(syscall.Handle(o.fd.sysfd), &o.buf, 1, &d, &f, &o.o, nil)
 }
 
 func (o *readOp) Name() string {
@@ -322,7 +322,7 @@ func (fd *netFD) Read(buf []byte) (n int, err os.Error) {
 	defer fd.rio.Unlock()
 	fd.incref()
 	defer fd.decref()
-	if fd.sysfd == -1 {
+	if fd.sysfd == syscall.InvalidHandle {
 		return 0, os.EINVAL
 	}
 	var o readOp
@@ -344,7 +344,7 @@ type readFromOp struct {
 func (o *readFromOp) Submit() (errno int) {
 	var d, f uint32
 	l := int32(unsafe.Sizeof(o.rsa))
-	return syscall.WSARecvFrom(uint32(o.fd.sysfd), &o.buf, 1, &d, &f, &o.rsa, &l, &o.o, nil)
+	return syscall.WSARecvFrom(o.fd.sysfd, &o.buf, 1, &d, &f, &o.rsa, &l, &o.o, nil)
 }
 
 func (o *readFromOp) Name() string {
@@ -362,7 +362,7 @@ func (fd *netFD) ReadFrom(buf []byte) (n int, sa syscall.Sockaddr, err os.Error)
 	defer fd.rio.Unlock()
 	fd.incref()
 	defer fd.decref()
-	if fd.sysfd == -1 {
+	if fd.sysfd == syscall.InvalidHandle {
 		return 0, nil, os.EINVAL
 	}
 	var o readFromOp
@@ -380,7 +380,7 @@ type writeOp struct {
 
 func (o *writeOp) Submit() (errno int) {
 	var d uint32
-	return syscall.WSASend(uint32(o.fd.sysfd), &o.buf, 1, &d, 0, &o.o, nil)
+	return syscall.WSASend(o.fd.sysfd, &o.buf, 1, &d, 0, &o.o, nil)
 }
 
 func (o *writeOp) Name() string {
@@ -395,7 +395,7 @@ func (fd *netFD) Write(buf []byte) (n int, err os.Error) {
 	defer fd.wio.Unlock()
 	fd.incref()
 	defer fd.decref()
-	if fd.sysfd == -1 {
+	if fd.sysfd == syscall.InvalidHandle {
 		return 0, os.EINVAL
 	}
 	var o writeOp
@@ -412,7 +412,7 @@ type writeToOp struct {
 
 func (o *writeToOp) Submit() (errno int) {
 	var d uint32
-	return syscall.WSASendto(uint32(o.fd.sysfd), &o.buf, 1, &d, 0, o.sa, &o.o, nil)
+	return syscall.WSASendto(o.fd.sysfd, &o.buf, 1, &d, 0, o.sa, &o.o, nil)
 }
 
 func (o *writeToOp) Name() string {
@@ -430,7 +430,7 @@ func (fd *netFD) WriteTo(buf []byte, sa syscall.Sockaddr) (n int, err os.Error)
 	defer fd.wio.Unlock()
 	fd.incref()
 	defer fd.decref()
-	if fd.sysfd == -1 {
+	if fd.sysfd == syscall.InvalidHandle {
 		return 0, os.EINVAL
 	}
 	var o writeToOp
@@ -443,14 +443,14 @@ func (fd *netFD) WriteTo(buf []byte, sa syscall.Sockaddr) (n int, err os.Error)
 
 type acceptOp struct {
 	anOp
-	newsock int
+	newsock syscall.Handle
 	attrs   [2]syscall.RawSockaddrAny // space for local and remote address only
 }
 
 func (o *acceptOp) Submit() (errno int) {
 	var d uint32
 	l := uint32(unsafe.Sizeof(o.attrs[0]))
-	return syscall.AcceptEx(uint32(o.fd.sysfd), uint32(o.newsock),
+	return syscall.AcceptEx(o.fd.sysfd, o.newsock,
 		(*byte)(unsafe.Pointer(&o.attrs[0])), 0, l, l, &d, &o.o)
 }
 
@@ -459,7 +459,7 @@ func (o *acceptOp) Name() string {
 }
 
 func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os.Error) {
-	if fd == nil || fd.sysfd == -1 {
+	if fd == nil || fd.sysfd == syscall.InvalidHandle {
 		return nil, os.EINVAL
 	}
 	fd.incref()
@@ -478,7 +478,7 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os.
 
 	// Associate our new socket with IOCP.
 	onceStartServer.Do(startServer)
-	if _, e = syscall.CreateIoCompletionPort(int32(s), resultsrv.iocp, 0, 0); e != 0 {
+	if _, e = syscall.CreateIoCompletionPort(s, resultsrv.iocp, 0, 0); e != 0 {
 		return nil, &OpError{"CreateIoCompletionPort", fd.net, fd.laddr, os.Errno(e)}
 	}
 
@@ -493,7 +493,7 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os.
 	}
 
 	// Inherit properties of the listening socket.
-	e = syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_UPDATE_ACCEPT_CONTEXT, fd.sysfd)
+	e = syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_UPDATE_ACCEPT_CONTEXT, int(fd.sysfd))
 	if e != 0 {
 		closesocket(s)
 		return nil, err
diff --git a/src/pkg/net/hosts_test.go b/src/pkg/net/hosts_test.go
index e5793ee..1bd0054 100644
--- a/src/pkg/net/hosts_test.go
+++ b/src/pkg/net/hosts_test.go
@@ -59,7 +59,7 @@ func TestLookupHost(t *testing.T) {
 	// duplicate addresses (a common bug due to the way
 	// getaddrinfo works).
 	addrs, _ := LookupHost("localhost")
-	sort.SortStrings(addrs)
+	sort.Strings(addrs)
 	for i := 0; i+1 < len(addrs); i++ {
 		if addrs[i] == addrs[i+1] {
 			t.Fatalf("LookupHost(\"localhost\") = %v, has duplicate addresses", addrs)
diff --git a/src/pkg/net/interface_windows.go b/src/pkg/net/interface_windows.go
index f54ffed..198e409 100644
--- a/src/pkg/net/interface_windows.go
+++ b/src/pkg/net/interface_windows.go
@@ -42,12 +42,12 @@ func getInterfaceList() ([]syscall.InterfaceInfo, os.Error) {
 	if e != 0 {
 		return nil, os.NewSyscallError("Socket", e)
 	}
-	defer syscall.Closesocket(int32(s))
+	defer syscall.Closesocket(s)
 
 	ii := [20]syscall.InterfaceInfo{}
 	ret := uint32(0)
 	size := uint32(unsafe.Sizeof(ii))
-	e = syscall.WSAIoctl(int32(s), syscall.SIO_GET_INTERFACE_LIST, nil, 0, (*byte)(unsafe.Pointer(&ii[0])), size, &ret, nil, 0)
+	e = syscall.WSAIoctl(s, syscall.SIO_GET_INTERFACE_LIST, nil, 0, (*byte)(unsafe.Pointer(&ii[0])), size, &ret, nil, 0)
 	if e != 0 {
 		return nil, os.NewSyscallError("WSAIoctl", e)
 	}
diff --git a/src/pkg/net/ipsock.go b/src/pkg/net/ipsock.go
index 5d56520..e831d9a 100644
--- a/src/pkg/net/ipsock.go
+++ b/src/pkg/net/ipsock.go
@@ -26,28 +26,26 @@ import (
 // boolean value is true, kernel supports IPv6 IPv4-mapping.
 func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
 	var probes = []struct {
-		s  int
 		la TCPAddr
 		ok bool
 	}{
 		// IPv6 communication capability
-		{-1, TCPAddr{IP: ParseIP("::1")}, false},
+		{TCPAddr{IP: ParseIP("::1")}, false},
 		// IPv6 IPv4-mapped address communication capability
-		{-1, TCPAddr{IP: IPv4(127, 0, 0, 1)}, false},
+		{TCPAddr{IP: IPv4(127, 0, 0, 1)}, false},
 	}
-	var errno int
 
 	for i := range probes {
-		probes[i].s, errno = syscall.Socket(syscall.AF_INET6, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
+		s, errno := syscall.Socket(syscall.AF_INET6, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
 		if errno != 0 {
 			continue
 		}
-		defer closesocket(probes[i].s)
+		defer closesocket(s)
 		sa, err := probes[i].la.toAddr().sockaddr(syscall.AF_INET6)
 		if err != nil {
 			continue
 		}
-		errno = syscall.Bind(probes[i].s, sa)
+		errno = syscall.Bind(s, sa)
 		if errno != 0 {
 			continue
 		}
diff --git a/src/pkg/net/sendfile_windows.go b/src/pkg/net/sendfile_windows.go
index 34abc54..3772eee 100644
--- a/src/pkg/net/sendfile_windows.go
+++ b/src/pkg/net/sendfile_windows.go
@@ -12,12 +12,12 @@ import (
 
 type sendfileOp struct {
 	anOp
-	src int32 // source
+	src syscall.Handle // source
 	n   uint32
 }
 
 func (o *sendfileOp) Submit() (errno int) {
-	return syscall.TransmitFile(int32(o.fd.sysfd), o.src, o.n, 0, &o.o, nil, syscall.TF_WRITE_BEHIND)
+	return syscall.TransmitFile(o.fd.sysfd, o.src, o.n, 0, &o.o, nil, syscall.TF_WRITE_BEHIND)
 }
 
 func (o *sendfileOp) Name() string {
@@ -56,7 +56,7 @@ func sendFile(c *netFD, r io.Reader) (written int64, err os.Error, handled bool)
 	var o sendfileOp
 	o.Init(c)
 	o.n = uint32(n)
-	o.src = int32(f.Fd())
+	o.src = f.Fd()
 	done, err := iosrv.ExecIO(&o, 0)
 	if err != nil {
 		return 0, err, false
diff --git a/src/pkg/net/sock.go b/src/pkg/net/sock.go
index eae7f37..821716e 100644
--- a/src/pkg/net/sock.go
+++ b/src/pkg/net/sock.go
@@ -50,8 +50,7 @@ func socket(net string, f, p, t int, la, ra syscall.Sockaddr, toAddr func(syscal
 
 	if ra != nil {
 		if err = fd.connect(ra); err != nil {
-			fd.sysfd = -1
-			closesocket(s)
+			fd.Close()
 			return nil, err
 		}
 	}
@@ -65,25 +64,25 @@ func socket(net string, f, p, t int, la, ra syscall.Sockaddr, toAddr func(syscal
 	return fd, nil
 }
 
-func setsockoptInt(fd, level, opt int, value int) os.Error {
-	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, level, opt, value))
+func setsockoptInt(fd *netFD, level, opt int, value int) os.Error {
+	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, level, opt, value))
 }
 
-func setsockoptNsec(fd, level, opt int, nsec int64) os.Error {
+func setsockoptNsec(fd *netFD, level, opt int, nsec int64) os.Error {
 	var tv = syscall.NsecToTimeval(nsec)
-	return os.NewSyscallError("setsockopt", syscall.SetsockoptTimeval(fd, level, opt, &tv))
+	return os.NewSyscallError("setsockopt", syscall.SetsockoptTimeval(fd.sysfd, level, opt, &tv))
 }
 
 func setReadBuffer(fd *netFD, bytes int) os.Error {
 	fd.incref()
 	defer fd.decref()
-	return setsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_RCVBUF, bytes)
+	return setsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_RCVBUF, bytes)
 }
 
 func setWriteBuffer(fd *netFD, bytes int) os.Error {
 	fd.incref()
 	defer fd.decref()
-	return setsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_SNDBUF, bytes)
+	return setsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_SNDBUF, bytes)
 }
 
 func setReadTimeout(fd *netFD, nsec int64) os.Error {
@@ -106,7 +105,7 @@ func setTimeout(fd *netFD, nsec int64) os.Error {
 func setReuseAddr(fd *netFD, reuse bool) os.Error {
 	fd.incref()
 	defer fd.decref()
-	return setsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, boolint(reuse))
+	return setsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, boolint(reuse))
 }
 
 func bindToDevice(fd *netFD, dev string) os.Error {
@@ -117,19 +116,19 @@ func bindToDevice(fd *netFD, dev string) os.Error {
 func setDontRoute(fd *netFD, dontroute bool) os.Error {
 	fd.incref()
 	defer fd.decref()
-	return setsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_DONTROUTE, boolint(dontroute))
+	return setsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_DONTROUTE, boolint(dontroute))
 }
 
 func setKeepAlive(fd *netFD, keepalive bool) os.Error {
 	fd.incref()
 	defer fd.decref()
-	return setsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_KEEPALIVE, boolint(keepalive))
+	return setsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_KEEPALIVE, boolint(keepalive))
 }
 
 func setNoDelay(fd *netFD, noDelay bool) os.Error {
 	fd.incref()
 	defer fd.decref()
-	return setsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.TCP_NODELAY, boolint(noDelay))
+	return setsockoptInt(fd, syscall.IPPROTO_TCP, syscall.TCP_NODELAY, boolint(noDelay))
 }
 
 func setLinger(fd *netFD, sec int) os.Error {
diff --git a/src/pkg/net/sock_windows.go b/src/pkg/net/sock_windows.go
index e17c60b..c6dbd04 100644
--- a/src/pkg/net/sock_windows.go
+++ b/src/pkg/net/sock_windows.go
@@ -10,7 +10,7 @@ import (
 	"syscall"
 )
 
-func setKernelSpecificSockopt(s, f int) {
+func setKernelSpecificSockopt(s syscall.Handle, f int) {
 	// Allow reuse of recently-used addresses and ports.
 	syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
 
diff --git a/src/pkg/os/Makefile b/src/pkg/os/Makefile
index 060cc97..354e1e8 100644
--- a/src/pkg/os/Makefile
+++ b/src/pkg/os/Makefile
@@ -84,5 +84,5 @@ include ../../Make.pkg
 signal_unix.go: ../syscall/zerrors_$(GOOS)_$(GOARCH).go
 	./mkunixsignals.sh $< > $@ || rm -f $@
 
-signal_windows.go: ../syscall/ztypes_$(GOOS)_$(GOARCH).go
+signal_windows.go: ../syscall/ztypes_$(GOOS).go
 	./mkunixsignals.sh $< > $@ || rm -f $@
diff --git a/src/pkg/os/env_windows.go b/src/pkg/os/env_windows.go
index a45d79b..e6ddc40 100644
--- a/src/pkg/os/env_windows.go
+++ b/src/pkg/os/env_windows.go
@@ -119,7 +119,7 @@ func init() {
 	if e != 0 {
 		return
 	}
-	defer syscall.LocalFree(uint32(uintptr(unsafe.Pointer(argv))))
+	defer syscall.LocalFree(syscall.Handle(uintptr(unsafe.Pointer(argv))))
 	Args = make([]string, argc)
 	for i, v := range (*argv)[:argc] {
 		Args[i] = string(syscall.UTF16ToString((*v)[:]))
diff --git a/src/pkg/os/exec_posix.go b/src/pkg/os/exec_posix.go
index 7dfcdd4..e209770 100644
--- a/src/pkg/os/exec_posix.go
+++ b/src/pkg/os/exec_posix.go
@@ -35,16 +35,9 @@ func StartProcess(name string, argv []string, attr *ProcAttr) (p *Process, err E
 	if sysattr.Env == nil {
 		sysattr.Env = Environ()
 	}
-	// Create array of integer (system) fds.
-	intfd := make([]int, len(attr.Files))
-	for i, f := range attr.Files {
-		if f == nil {
-			intfd[i] = -1
-		} else {
-			intfd[i] = f.Fd()
-		}
+	for _, f := range attr.Files {
+		sysattr.Files = append(sysattr.Files, f.Fd())
 	}
-	sysattr.Files = intfd
 
 	pid, h, e := syscall.StartProcess(name, argv, sysattr)
 	if iserror(e) {
diff --git a/src/pkg/os/exec_windows.go b/src/pkg/os/exec_windows.go
index 991099d..5b432d3 100644
--- a/src/pkg/os/exec_windows.go
+++ b/src/pkg/os/exec_windows.go
@@ -10,7 +10,7 @@ import (
 )
 
 func (p *Process) Wait(options int) (w *Waitmsg, err Error) {
-	s, e := syscall.WaitForSingleObject(int32(p.handle), syscall.INFINITE)
+	s, e := syscall.WaitForSingleObject(syscall.Handle(p.handle), syscall.INFINITE)
 	switch s {
 	case syscall.WAIT_OBJECT_0:
 		break
@@ -20,7 +20,7 @@ func (p *Process) Wait(options int) (w *Waitmsg, err Error) {
 		return nil, NewError("os: unexpected result from WaitForSingleObject")
 	}
 	var ec uint32
-	e = syscall.GetExitCodeProcess(int32(p.handle), &ec)
+	e = syscall.GetExitCodeProcess(syscall.Handle(p.handle), &ec)
 	if e != 0 {
 		return nil, NewSyscallError("GetExitCodeProcess", e)
 	}
@@ -31,7 +31,7 @@ func (p *Process) Wait(options int) (w *Waitmsg, err Error) {
 func (p *Process) Signal(sig Signal) Error {
 	switch sig.(UnixSignal) {
 	case SIGKILL:
-		e := syscall.TerminateProcess(int32(p.handle), 1)
+		e := syscall.TerminateProcess(syscall.Handle(p.handle), 1)
 		return NewSyscallError("TerminateProcess", e)
 	}
 	return Errno(syscall.EWINDOWS)
@@ -41,7 +41,7 @@ func (p *Process) Release() Error {
 	if p.handle == -1 {
 		return EINVAL
 	}
-	e := syscall.CloseHandle(int32(p.handle))
+	e := syscall.CloseHandle(syscall.Handle(p.handle))
 	if e != 0 {
 		return NewSyscallError("CloseHandle", e)
 	}
diff --git a/src/pkg/os/file.go b/src/pkg/os/file.go
index 0e97e0b..4335d45 100644
--- a/src/pkg/os/file.go
+++ b/src/pkg/os/file.go
@@ -9,36 +9,12 @@
 package os
 
 import (
-	"runtime"
-	"sync"
 	"syscall"
 )
 
-// File represents an open file descriptor.
-type File struct {
-	fd      int
-	name    string
-	dirinfo *dirInfo   // nil unless directory being read
-	nepipe  int        // number of consecutive EPIPE in Write
-	l       sync.Mutex // used to implement windows pread/pwrite
-}
-
-// Fd returns the integer Unix file descriptor referencing the open file.
-func (file *File) Fd() int { return file.fd }
-
 // Name returns the name of the file as presented to Open.
 func (file *File) Name() string { return file.name }
 
-// NewFile returns a new File with the given file descriptor and name.
-func NewFile(fd int, name string) *File {
-	if fd < 0 {
-		return nil
-	}
-	f := &File{fd: fd, name: name}
-	runtime.SetFinalizer(f, (*File).Close)
-	return f
-}
-
 // Stdin, Stdout, and Stderr are open Files pointing to the standard input,
 // standard output, and standard error file descriptors.
 var (
@@ -187,9 +163,7 @@ func (file *File) WriteString(s string) (ret int, err Error) {
 	if file == nil {
 		return 0, EINVAL
 	}
-	b := syscall.StringByteSlice(s)
-	b = b[0 : len(b)-1]
-	return file.Write(b)
+	return file.Write([]byte(s))
 }
 
 // Mkdir creates a new directory with the specified name and permission bits.
diff --git a/src/pkg/os/file_plan9.go b/src/pkg/os/file_plan9.go
index b0c42d1..0379219 100644
--- a/src/pkg/os/file_plan9.go
+++ b/src/pkg/os/file_plan9.go
@@ -9,6 +9,32 @@ import (
 	"syscall"
 )
 
+// File represents an open file descriptor.
+type File struct {
+	fd      int
+	name    string
+	dirinfo *dirInfo // nil unless directory being read
+	nepipe  int      // number of consecutive EPIPE in Write
+}
+
+// Fd returns the integer Unix file descriptor referencing the open file.
+func (file *File) Fd() int {
+	if file == nil {
+		return -1
+	}
+	return file.fd
+}
+
+// NewFile returns a new File with the given file descriptor and name.
+func NewFile(fd int, name string) *File {
+	if fd < 0 {
+		return nil
+	}
+	f := &File{fd: fd, name: name}
+	runtime.SetFinalizer(f, (*File).Close)
+	return f
+}
+
 // Auxiliary information if the File describes a directory
 type dirInfo struct {
 	buf  [syscall.STATMAX]byte // buffer for directory I/O
diff --git a/src/pkg/os/file_posix.go b/src/pkg/os/file_posix.go
index f1191d6..0791a0d 100644
--- a/src/pkg/os/file_posix.go
+++ b/src/pkg/os/file_posix.go
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// The os package provides a platform-independent interface to operating
-// system functionality.  The design is Unix-like.
 package os
 
 import (
@@ -23,26 +21,6 @@ func epipecheck(file *File, e int) {
 	}
 }
 
-
-// Pipe returns a connected pair of Files; reads from r return bytes written to w.
-// It returns the files and an Error, if any.
-func Pipe() (r *File, w *File, err Error) {
-	var p [2]int
-
-	// See ../syscall/exec.go for description of lock.
-	syscall.ForkLock.RLock()
-	e := syscall.Pipe(p[0:])
-	if iserror(e) {
-		syscall.ForkLock.RUnlock()
-		return nil, nil, NewSyscallError("pipe", e)
-	}
-	syscall.CloseOnExec(p[0])
-	syscall.CloseOnExec(p[1])
-	syscall.ForkLock.RUnlock()
-
-	return NewFile(p[0], "|0"), NewFile(p[1], "|1"), nil
-}
-
 // Stat returns a FileInfo structure describing the named file and an error, if any.
 // If name names a valid symbolic link, the returned FileInfo describes
 // the file pointed at by the link and has fi.FollowedSymlink set to true.
diff --git a/src/pkg/os/file_unix.go b/src/pkg/os/file_unix.go
index def9b3b..301c2f4 100644
--- a/src/pkg/os/file_unix.go
+++ b/src/pkg/os/file_unix.go
@@ -9,6 +9,32 @@ import (
 	"syscall"
 )
 
+// File represents an open file descriptor.
+type File struct {
+	fd      int
+	name    string
+	dirinfo *dirInfo // nil unless directory being read
+	nepipe  int      // number of consecutive EPIPE in Write
+}
+
+// Fd returns the integer Unix file descriptor referencing the open file.
+func (file *File) Fd() int {
+	if file == nil {
+		return -1
+	}
+	return file.fd
+}
+
+// NewFile returns a new File with the given file descriptor and name.
+func NewFile(fd int, name string) *File {
+	if fd < 0 {
+		return nil
+	}
+	f := &File{fd: fd, name: name}
+	runtime.SetFinalizer(f, (*File).Close)
+	return f
+}
+
 // Auxiliary information if the File describes a directory
 type dirInfo struct {
 	buf  []byte // buffer for directory I/O
@@ -161,3 +187,22 @@ func basename(name string) string {
 
 	return name
 }
+
+// Pipe returns a connected pair of Files; reads from r return bytes written to w.
+// It returns the files and an Error, if any.
+func Pipe() (r *File, w *File, err Error) {
+	var p [2]int
+
+	// See ../syscall/exec.go for description of lock.
+	syscall.ForkLock.RLock()
+	e := syscall.Pipe(p[0:])
+	if iserror(e) {
+		syscall.ForkLock.RUnlock()
+		return nil, nil, NewSyscallError("pipe", e)
+	}
+	syscall.CloseOnExec(p[0])
+	syscall.CloseOnExec(p[1])
+	syscall.ForkLock.RUnlock()
+
+	return NewFile(p[0], "|0"), NewFile(p[1], "|1"), nil
+}
diff --git a/src/pkg/os/file_windows.go b/src/pkg/os/file_windows.go
index 80886f6..70dd6e2 100644
--- a/src/pkg/os/file_windows.go
+++ b/src/pkg/os/file_windows.go
@@ -6,9 +6,37 @@ package os
 
 import (
 	"runtime"
+	"sync"
 	"syscall"
 )
 
+// File represents an open file descriptor.
+type File struct {
+	fd      syscall.Handle
+	name    string
+	dirinfo *dirInfo   // nil unless directory being read
+	nepipe  int        // number of consecutive EPIPE in Write
+	l       sync.Mutex // used to implement windows pread/pwrite
+}
+
+// Fd returns the Windows handle referencing the open file.
+func (file *File) Fd() syscall.Handle {
+	if file == nil {
+		return syscall.InvalidHandle
+	}
+	return file.fd
+}
+
+// NewFile returns a new File with the given file descriptor and name.
+func NewFile(fd syscall.Handle, name string) *File {
+	if fd < 0 {
+		return nil
+	}
+	f := &File{fd: fd, name: name}
+	runtime.SetFinalizer(f, (*File).Close)
+	return f
+}
+
 // Auxiliary information if the File describes a directory
 type dirInfo struct {
 	stat         syscall.Stat_t
@@ -40,7 +68,7 @@ func openDir(name string) (file *File, err Error) {
 	if e != 0 {
 		return nil, &PathError{"open", name, Errno(e)}
 	}
-	f := NewFile(int(r), name)
+	f := NewFile(r, name)
 	d.usefirststat = true
 	f.dirinfo = d
 	return f, nil
@@ -85,15 +113,15 @@ func (file *File) Close() Error {
 	}
 	var e int
 	if file.isdir() {
-		e = syscall.FindClose(int32(file.fd))
+		e = syscall.FindClose(syscall.Handle(file.fd))
 	} else {
-		e = syscall.CloseHandle(int32(file.fd))
+		e = syscall.CloseHandle(syscall.Handle(file.fd))
 	}
 	var err Error
 	if e != 0 {
 		err = &PathError{"close", file.name, Errno(e)}
 	}
-	file.fd = -1 // so it can't be closed again
+	file.fd = syscall.InvalidHandle // so it can't be closed again
 
 	// no need for a finalizer anymore
 	runtime.SetFinalizer(file, nil)
@@ -102,7 +130,7 @@ func (file *File) Close() Error {
 
 func (file *File) statFile(name string) (fi *FileInfo, err Error) {
 	var stat syscall.ByHandleFileInformation
-	e := syscall.GetFileInformationByHandle(int32(file.fd), &stat)
+	e := syscall.GetFileInformationByHandle(syscall.Handle(file.fd), &stat)
 	if e != 0 {
 		return nil, &PathError{"stat", file.name, Errno(e)}
 	}
@@ -156,7 +184,7 @@ func (file *File) Readdir(n int) (fi []FileInfo, err Error) {
 		if di.usefirststat {
 			di.usefirststat = false
 		} else {
-			e := syscall.FindNextFile(int32(file.fd), &di.stat.Windata)
+			e := syscall.FindNextFile(syscall.Handle(file.fd), &di.stat.Windata)
 			if e != 0 {
 				if e == syscall.ERROR_NO_MORE_FILES {
 					break
@@ -207,7 +235,7 @@ func (f *File) pread(b []byte, off int64) (n int, err int) {
 		Offset:     uint32(off),
 	}
 	var done uint32
-	e = syscall.ReadFile(int32(f.fd), b, &done, &o)
+	e = syscall.ReadFile(syscall.Handle(f.fd), b, &done, &o)
 	if e != 0 {
 		return 0, e
 	}
@@ -237,7 +265,7 @@ func (f *File) pwrite(b []byte, off int64) (n int, err int) {
 		Offset:     uint32(off),
 	}
 	var done uint32
-	e = syscall.WriteFile(int32(f.fd), b, &done, &o)
+	e = syscall.WriteFile(syscall.Handle(f.fd), b, &done, &o)
 	if e != 0 {
 		return 0, e
 	}
@@ -268,3 +296,22 @@ func Truncate(name string, size int64) Error {
 	}
 	return nil
 }
+
+// Pipe returns a connected pair of Files; reads from r return bytes written to w.
+// It returns the files and an Error, if any.
+func Pipe() (r *File, w *File, err Error) {
+	var p [2]syscall.Handle
+
+	// See ../syscall/exec.go for description of lock.
+	syscall.ForkLock.RLock()
+	e := syscall.Pipe(p[0:])
+	if iserror(e) {
+		syscall.ForkLock.RUnlock()
+		return nil, nil, NewSyscallError("pipe", e)
+	}
+	syscall.CloseOnExec(p[0])
+	syscall.CloseOnExec(p[1])
+	syscall.ForkLock.RUnlock()
+
+	return NewFile(p[0], "|0"), NewFile(p[1], "|1"), nil
+}
diff --git a/src/pkg/os/mkunixsignals.sh b/src/pkg/os/mkunixsignals.sh
index 6ec764c..4bbc43f 100755
--- a/src/pkg/os/mkunixsignals.sh
+++ b/src/pkg/os/mkunixsignals.sh
@@ -14,7 +14,7 @@ import (
   "syscall"
 )
 
-var _ = syscall.Syscall  // in case there are zero signals
+var _ = syscall.Open  // in case there are zero signals
 
 const (
 EOH
diff --git a/src/pkg/os/types.go b/src/pkg/os/types.go
index 79f6e9d..df57b59 100644
--- a/src/pkg/os/types.go
+++ b/src/pkg/os/types.go
@@ -27,7 +27,7 @@ type FileInfo struct {
 	Atime_ns        int64  // access time; nanoseconds since epoch.
 	Mtime_ns        int64  // modified time; nanoseconds since epoch.
 	Ctime_ns        int64  // status change time; nanoseconds since epoch.
-	Name            string // name of file as presented to Open.
+	Name            string // base name of the file name provided in Open, Stat, etc.
 	FollowedSymlink bool   // followed a symlink to get this information
 }
 
diff --git a/src/pkg/patch/patch.go b/src/pkg/patch/patch.go
index d4977dc..fcc8307 100644
--- a/src/pkg/patch/patch.go
+++ b/src/pkg/patch/patch.go
@@ -319,4 +319,4 @@ func hasPrefix(s []byte, t string) bool {
 
 // splitLines returns the result of splitting s into lines.
 // The \n on each line is preserved.
-func splitLines(s []byte) [][]byte { return bytes.SplitAfter(s, newline, -1) }
+func splitLines(s []byte) [][]byte { return bytes.SplitAfter(s, newline) }
diff --git a/src/pkg/path/filepath/match.go b/src/pkg/path/filepath/match.go
index 9c34430..7fcc214 100644
--- a/src/pkg/path/filepath/match.go
+++ b/src/pkg/path/filepath/match.go
@@ -272,7 +272,7 @@ func glob(dir, pattern string, matches []string) (m []string, e os.Error) {
 	if err != nil {
 		return
 	}
-	sort.SortStrings(names)
+	sort.Strings(names)
 
 	for _, n := range names {
 		matched, err := Match(pattern, n)
diff --git a/src/pkg/path/filepath/path.go b/src/pkg/path/filepath/path.go
index dcd8017..b181483 100644
--- a/src/pkg/path/filepath/path.go
+++ b/src/pkg/path/filepath/path.go
@@ -136,7 +136,7 @@ func SplitList(path string) []string {
 	if path == "" {
 		return []string{}
 	}
-	return strings.Split(path, string(ListSeparator), -1)
+	return strings.Split(path, string(ListSeparator))
 }
 
 // Split splits path immediately following the final Separator,
diff --git a/src/pkg/path/filepath/path_test.go b/src/pkg/path/filepath/path_test.go
index 6a5dd5b..58c4c03 100644
--- a/src/pkg/path/filepath/path_test.go
+++ b/src/pkg/path/filepath/path_test.go
@@ -293,10 +293,6 @@ func (v *TestVisitor) VisitFile(path string, f *os.FileInfo) {
 }
 
 func TestWalk(t *testing.T) {
-	// TODO(brainman): enable test once Windows version is implemented.
-	if runtime.GOOS == "windows" {
-		return
-	}
 	makeTree(t)
 
 	// 1) ignore error handling, expect none
diff --git a/src/pkg/reflect/all_test.go b/src/pkg/reflect/all_test.go
index c83a9b7..34d74b3 100644
--- a/src/pkg/reflect/all_test.go
+++ b/src/pkg/reflect/all_test.go
@@ -127,17 +127,17 @@ var typeTests = []pair{
 	},
 	{struct {
 		x struct {
-			a int8 "hi there"
+			a int8 `reflect:"hi there"`
 		}
 	}{},
-		`struct { a int8 "hi there" }`,
+		`struct { a int8 "reflect:\"hi there\"" }`,
 	},
 	{struct {
 		x struct {
-			a int8 "hi \x00there\t\n\"\\"
+			a int8 `reflect:"hi \x00there\t\n\"\\"`
 		}
 	}{},
-		`struct { a int8 "hi \x00there\t\n\"\\" }`,
+		`struct { a int8 "reflect:\"hi \\x00there\\t\\n\\\"\\\\\"" }`,
 	},
 	{struct {
 		x struct {
@@ -423,7 +423,7 @@ func TestAll(t *testing.T) {
 
 	// make sure tag strings are not part of element type
 	typ = TypeOf(struct {
-		d []uint32 "TAG"
+		d []uint32 `reflect:"TAG"`
 	}{}).Field(0).Type
 	testType(t, 14, typ, "[]uint32")
 }
@@ -1050,6 +1050,12 @@ type Point struct {
 	x, y int
 }
 
+// This will be index 0.
+func (p Point) AnotherMethod(scale int) int {
+	return -1
+}
+
+// This will be index 1.
 func (p Point) Dist(scale int) int {
 	//	println("Point.Dist", p.x, p.y, scale)
 	return p.x*p.x*scale + p.y*p.y*scale
@@ -1058,26 +1064,52 @@ func (p Point) Dist(scale int) int {
 func TestMethod(t *testing.T) {
 	// Non-curried method of type.
 	p := Point{3, 4}
-	i := TypeOf(p).Method(0).Func.Call([]Value{ValueOf(p), ValueOf(10)})[0].Int()
+	i := TypeOf(p).Method(1).Func.Call([]Value{ValueOf(p), ValueOf(10)})[0].Int()
 	if i != 250 {
 		t.Errorf("Type Method returned %d; want 250", i)
 	}
 
-	i = TypeOf(&p).Method(0).Func.Call([]Value{ValueOf(&p), ValueOf(10)})[0].Int()
+	m, ok := TypeOf(p).MethodByName("Dist")
+	if !ok {
+		t.Fatalf("method by name failed")
+	}
+	m.Func.Call([]Value{ValueOf(p), ValueOf(10)})[0].Int()
+	if i != 250 {
+		t.Errorf("Type MethodByName returned %d; want 250", i)
+	}
+
+	i = TypeOf(&p).Method(1).Func.Call([]Value{ValueOf(&p), ValueOf(10)})[0].Int()
 	if i != 250 {
 		t.Errorf("Pointer Type Method returned %d; want 250", i)
 	}
 
+	m, ok = TypeOf(&p).MethodByName("Dist")
+	if !ok {
+		t.Fatalf("ptr method by name failed")
+	}
+	i = m.Func.Call([]Value{ValueOf(&p), ValueOf(10)})[0].Int()
+	if i != 250 {
+		t.Errorf("Pointer Type MethodByName returned %d; want 250", i)
+	}
+
 	// Curried method of value.
-	i = ValueOf(p).Method(0).Call([]Value{ValueOf(10)})[0].Int()
+	i = ValueOf(p).Method(1).Call([]Value{ValueOf(10)})[0].Int()
 	if i != 250 {
 		t.Errorf("Value Method returned %d; want 250", i)
 	}
+	i = ValueOf(p).MethodByName("Dist").Call([]Value{ValueOf(10)})[0].Int()
+	if i != 250 {
+		t.Errorf("Value MethodByName returned %d; want 250", i)
+	}
 
 	// Curried method of pointer.
-	i = ValueOf(&p).Method(0).Call([]Value{ValueOf(10)})[0].Int()
+	i = ValueOf(&p).Method(1).Call([]Value{ValueOf(10)})[0].Int()
 	if i != 250 {
-		t.Errorf("Value Method returned %d; want 250", i)
+		t.Errorf("Pointer Value Method returned %d; want 250", i)
+	}
+	i = ValueOf(&p).MethodByName("Dist").Call([]Value{ValueOf(10)})[0].Int()
+	if i != 250 {
+		t.Errorf("Pointer Value MethodByName returned %d; want 250", i)
 	}
 
 	// Curried method of interface value.
@@ -1094,6 +1126,10 @@ func TestMethod(t *testing.T) {
 	if i != 250 {
 		t.Errorf("Interface Method returned %d; want 250", i)
 	}
+	i = pv.MethodByName("Dist").Call([]Value{ValueOf(10)})[0].Int()
+	if i != 250 {
+		t.Errorf("Interface MethodByName returned %d; want 250", i)
+	}
 }
 
 func TestInterfaceSet(t *testing.T) {
@@ -1508,3 +1544,23 @@ func TestVariadic(t *testing.T) {
 		t.Errorf("after Fprintf CallSlice: %q != %q", b.String(), "hello 42 world")
 	}
 }
+
+var tagGetTests = []struct {
+	Tag   StructTag
+	Key   string
+	Value string
+}{
+	{`protobuf:"PB(1,2)"`, `protobuf`, `PB(1,2)`},
+	{`protobuf:"PB(1,2)"`, `foo`, ``},
+	{`protobuf:"PB(1,2)"`, `rotobuf`, ``},
+	{`protobuf:"PB(1,2)" json:"name"`, `json`, `name`},
+	{`protobuf:"PB(1,2)" json:"name"`, `protobuf`, `PB(1,2)`},
+}
+
+func TestTagGet(t *testing.T) {
+	for _, tt := range tagGetTests {
+		if v := tt.Tag.Get(tt.Key); v != tt.Value {
+			t.Errorf("StructTag(%#q).Get(%#q) = %#q, want %#q", tt.Tag, tt.Key, v, tt.Value)
+		}
+	}
+}
diff --git a/src/pkg/reflect/type.go b/src/pkg/reflect/type.go
index 6c1ab60..a120da7 100644
--- a/src/pkg/reflect/type.go
+++ b/src/pkg/reflect/type.go
@@ -47,6 +47,16 @@ type Type interface {
 	// method signature, without a receiver, and the Func field is nil.
 	Method(int) Method
 
+	// MethodByName returns the method with that name in the type's
+	// method set and a boolean indicating if the method was found.
+	//
+	// For a non-interface type T or *T, the returned Method's Type and Func
+	// fields describe a function whose first argument is the receiver.
+	//
+	// For an interface type, the returned Method's Type field gives the
+	// method signature, without a receiver, and the Func field is nil.
+	MethodByName(string) (Method, bool)
+
 	// NumMethod returns the number of methods in the type's method set.
 	NumMethod() int
 
@@ -264,7 +274,7 @@ const (
 
 // arrayType represents a fixed array type.
 type arrayType struct {
-	commonType "array"
+	commonType `reflect:"array"`
 	elem       *runtime.Type
 	slice      *runtime.Type
 	len        uintptr
@@ -272,14 +282,14 @@ type arrayType struct {
 
 // chanType represents a channel type.
 type chanType struct {
-	commonType "chan"
+	commonType `reflect:"chan"`
 	elem       *runtime.Type
 	dir        uintptr
 }
 
 // funcType represents a function type.
 type funcType struct {
-	commonType "func"
+	commonType `reflect:"func"`
 	dotdotdot  bool
 	in         []*runtime.Type
 	out        []*runtime.Type
@@ -294,26 +304,26 @@ type imethod struct {
 
 // interfaceType represents an interface type.
 type interfaceType struct {
-	commonType "interface"
+	commonType `reflect:"interface"`
 	methods    []imethod
 }
 
 // mapType represents a map type.
 type mapType struct {
-	commonType "map"
+	commonType `reflect:"map"`
 	key        *runtime.Type
 	elem       *runtime.Type
 }
 
 // ptrType represents a pointer type.
 type ptrType struct {
-	commonType "ptr"
+	commonType `reflect:"ptr"`
 	elem       *runtime.Type
 }
 
 // sliceType represents a slice type.
 type sliceType struct {
-	commonType "slice"
+	commonType `reflect:"slice"`
 	elem       *runtime.Type
 }
 
@@ -328,7 +338,7 @@ type structField struct {
 
 // structType represents a struct type.
 type structType struct {
-	commonType "struct"
+	commonType `reflect:"struct"`
 	fields     []structField
 }
 
@@ -344,6 +354,7 @@ type Method struct {
 	Name    string
 	Type    Type
 	Func    Value
+	Index   int
 }
 
 // High bit says whether type has
@@ -451,6 +462,7 @@ func (t *uncommonType) Method(i int) (m Method) {
 	m.Type = toType(p.typ)
 	fn := p.tfn
 	m.Func = valueFromIword(flag, m.Type, iword(fn))
+	m.Index = i
 	return
 }
 
@@ -461,6 +473,20 @@ func (t *uncommonType) NumMethod() int {
 	return len(t.methods)
 }
 
+func (t *uncommonType) MethodByName(name string) (m Method, ok bool) {
+	if t == nil {
+		return
+	}
+	var p *method
+	for i := range t.methods {
+		p = &t.methods[i]
+		if p.name != nil && *p.name == name {
+			return t.Method(i), true
+		}
+	}
+	return
+}
+
 // TODO(rsc): 6g supplies these, but they are not
 // as efficient as they could be: they have commonType
 // as the receiver instead of *commonType.
@@ -480,6 +506,14 @@ func (t *commonType) Method(i int) (m Method) {
 	return t.uncommonType.Method(i)
 }
 
+func (t *commonType) MethodByName(name string) (m Method, ok bool) {
+	if t.Kind() == Interface {
+		tt := (*interfaceType)(unsafe.Pointer(t))
+		return tt.MethodByName(name)
+	}
+	return t.uncommonType.MethodByName(name)
+}
+
 func (t *commonType) PkgPath() string {
 	return t.uncommonType.PkgPath()
 }
@@ -636,22 +670,98 @@ func (t *interfaceType) Method(i int) (m Method) {
 		m.PkgPath = *p.pkgPath
 	}
 	m.Type = toType(p.typ)
+	m.Index = i
 	return
 }
 
 // NumMethod returns the number of interface methods in the type's method set.
 func (t *interfaceType) NumMethod() int { return len(t.methods) }
 
+// MethodByName method with the given name in the type's method set.
+func (t *interfaceType) MethodByName(name string) (m Method, ok bool) {
+	if t == nil {
+		return
+	}
+	var p *imethod
+	for i := range t.methods {
+		p = &t.methods[i]
+		if *p.name == name {
+			return t.Method(i), true
+		}
+	}
+	return
+}
+
 type StructField struct {
 	PkgPath   string // empty for uppercase Name
 	Name      string
 	Type      Type
-	Tag       string
+	Tag       StructTag
 	Offset    uintptr
 	Index     []int
 	Anonymous bool
 }
 
+// A StructTag is the tag string in a struct field.
+//
+// By convention, tag strings are a concatenation of
+// optionally space-separated key:"value" pairs.
+// Each key is a non-empty string consisting of non-control
+// characters other than space (U+0020 ' '), quote (U+0022 '"'),
+// and colon (U+003A ':').  Each value is quoted using U+0022 '"'
+// characters and Go string literal syntax.
+type StructTag string
+
+// Get returns the value associated with key in the tag string.
+// If there is no such key in the tag, Get returns the empty string.
+// If the tag does not have the conventional format, the value
+// returned by Get is unspecified, 
+func (tag StructTag) Get(key string) string {
+	for tag != "" {
+		// skip leading space
+		i := 0
+		for i < len(tag) && tag[i] == ' ' {
+			i++
+		}
+		tag = tag[i:]
+		if tag == "" {
+			break
+		}
+
+		// scan to colon.
+		// a space or a quote is a syntax error
+		i = 0
+		for i < len(tag) && tag[i] != ' ' && tag[i] != ':' && tag[i] != '"' {
+			i++
+		}
+		if i+1 >= len(tag) || tag[i] != ':' || tag[i+1] != '"' {
+			break
+		}
+		name := string(tag[:i])
+		tag = tag[i+1:]
+
+		// scan quoted string to find value
+		i = 1
+		for i < len(tag) && tag[i] != '"' {
+			if tag[i] == '\\' {
+				i++
+			}
+			i++
+		}
+		if i >= len(tag) {
+			break
+		}
+		qvalue := string(tag[:i+1])
+		tag = tag[i+1:]
+
+		if key == name {
+			value, _ := strconv.Unquote(qvalue)
+			return value
+		}
+	}
+	return ""
+}
+
 // Field returns the i'th struct field.
 func (t *structType) Field(i int) (f StructField) {
 	if i < 0 || i >= len(t.fields) {
@@ -673,7 +783,7 @@ func (t *structType) Field(i int) (f StructField) {
 		f.PkgPath = *p.pkgPath
 	}
 	if p.tag != nil {
-		f.Tag = *p.tag
+		f.Tag = StructTag(*p.tag)
 	}
 	f.Offset = p.offset
 	f.Index = []int{i}
diff --git a/src/pkg/reflect/value.go b/src/pkg/reflect/value.go
index b1999aa..bfeb326 100644
--- a/src/pkg/reflect/value.go
+++ b/src/pkg/reflect/value.go
@@ -933,7 +933,7 @@ func (v Value) Kind() Kind {
 }
 
 // Len returns v's length.
-// It panics if v's Kind is not Array, Chan, Map, or Slice.
+// It panics if v's Kind is not Array, Chan, Map, Slice, or String.
 func (v Value) Len() int {
 	iv := v.internal()
 	switch iv.kind {
@@ -945,6 +945,8 @@ func (v Value) Len() int {
 		return int(maplen(iv.word))
 	case Slice:
 		return (*SliceHeader)(iv.addr).Len
+	case String:
+		return (*StringHeader)(iv.addr).Len
 	}
 	panic(&ValueError{"reflect.Value.Len", iv.kind})
 }
@@ -1023,6 +1025,23 @@ func (v Value) Method(i int) Value {
 	return Value{v.Internal, i + 1}
 }
 
+// MethodByName returns a function value corresponding to the method
+// of v with the given name.
+// The arguments to a Call on the returned function should not include
+// a receiver; the returned function will always use v as the receiver.
+// It returns the zero Value if no method was found.
+func (v Value) MethodByName(name string) Value {
+	iv := v.internal()
+	if iv.kind == Invalid {
+		panic(&ValueError{"reflect.Value.MethodByName", Invalid})
+	}
+	m, ok := iv.typ.MethodByName(name)
+	if ok {
+		return Value{v.Internal, m.Index + 1}
+	}
+	return Value{}
+}
+
 // NumField returns the number of fields in the struct v.
 // It panics if v's Kind is not Struct.
 func (v Value) NumField() int {
diff --git a/src/pkg/regexp/regexp.go b/src/pkg/regexp/regexp.go
index 44da8b6..e8d4c08 100644
--- a/src/pkg/regexp/regexp.go
+++ b/src/pkg/regexp/regexp.go
@@ -158,6 +158,7 @@ func (i *instr) print() {
 
 // Regexp is the representation of a compiled regular expression.
 // The public interface is entirely through methods.
+// A Regexp is safe for concurrent use by multiple goroutines.
 type Regexp struct {
 	expr        string // the original expression
 	prefix      string // initial plain text string
diff --git a/src/pkg/rpc/jsonrpc/all_test.go b/src/pkg/rpc/jsonrpc/all_test.go
index 02b9735..c1a9e8e 100644
--- a/src/pkg/rpc/jsonrpc/all_test.go
+++ b/src/pkg/rpc/jsonrpc/all_test.go
@@ -51,9 +51,9 @@ func init() {
 
 func TestServer(t *testing.T) {
 	type addResp struct {
-		Id     interface{} "id"
-		Result Reply       "result"
-		Error  interface{} "error"
+		Id     interface{} `json:"id"`
+		Result Reply       `json:"result"`
+		Error  interface{} `json:"error"`
 	}
 
 	cli, srv := net.Pipe()
diff --git a/src/pkg/rpc/jsonrpc/client.go b/src/pkg/rpc/jsonrpc/client.go
index 57e977d..577d0ce 100644
--- a/src/pkg/rpc/jsonrpc/client.go
+++ b/src/pkg/rpc/jsonrpc/client.go
@@ -44,9 +44,9 @@ func NewClientCodec(conn io.ReadWriteCloser) rpc.ClientCodec {
 }
 
 type clientRequest struct {
-	Method string         "method"
-	Params [1]interface{} "params"
-	Id     uint64         "id"
+	Method string         `json:"method"`
+	Params [1]interface{} `json:"params"`
+	Id     uint64         `json:"id"`
 }
 
 func (c *clientCodec) WriteRequest(r *rpc.Request, param interface{}) os.Error {
@@ -60,9 +60,9 @@ func (c *clientCodec) WriteRequest(r *rpc.Request, param interface{}) os.Error {
 }
 
 type clientResponse struct {
-	Id     uint64           "id"
-	Result *json.RawMessage "result"
-	Error  interface{}      "error"
+	Id     uint64           `json:"id"`
+	Result *json.RawMessage `json:"result"`
+	Error  interface{}      `json:"error"`
 }
 
 func (r *clientResponse) reset() {
diff --git a/src/pkg/rpc/jsonrpc/server.go b/src/pkg/rpc/jsonrpc/server.go
index 9c6b8b4..9801fdf 100644
--- a/src/pkg/rpc/jsonrpc/server.go
+++ b/src/pkg/rpc/jsonrpc/server.go
@@ -43,9 +43,9 @@ func NewServerCodec(conn io.ReadWriteCloser) rpc.ServerCodec {
 }
 
 type serverRequest struct {
-	Method string           "method"
-	Params *json.RawMessage "params"
-	Id     *json.RawMessage "id"
+	Method string           `json:"method"`
+	Params *json.RawMessage `json:"params"`
+	Id     *json.RawMessage `json:"id"`
 }
 
 func (r *serverRequest) reset() {
@@ -59,9 +59,9 @@ func (r *serverRequest) reset() {
 }
 
 type serverResponse struct {
-	Id     *json.RawMessage "id"
-	Result interface{}      "result"
-	Error  interface{}      "error"
+	Id     *json.RawMessage `json:"id"`
+	Result interface{}      `json:"result"`
+	Error  interface{}      `json:"error"`
 }
 
 func (c *serverCodec) ReadRequestHeader(r *rpc.Request) os.Error {
diff --git a/src/pkg/rpc/server.go b/src/pkg/rpc/server.go
index 17ba6a4..07845d1 100644
--- a/src/pkg/rpc/server.go
+++ b/src/pkg/rpc/server.go
@@ -495,7 +495,7 @@ func (server *Server) readRequest(codec ServerCodec) (req *Request, service *ser
 		return
 	}
 
-	serviceMethod := strings.Split(req.ServiceMethod, ".", -1)
+	serviceMethod := strings.Split(req.ServiceMethod, ".")
 	if len(serviceMethod) != 2 {
 		err = os.NewError("rpc: service/method request ill-formed: " + req.ServiceMethod)
 		return
diff --git a/src/pkg/runtime/386/atomic.c b/src/pkg/runtime/386/atomic.c
new file mode 100644
index 0000000..c031cc4
--- /dev/null
+++ b/src/pkg/runtime/386/atomic.c
@@ -0,0 +1,12 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+
+#pragma textflag 7
+uint32
+runtime·atomicload(uint32 volatile* addr)
+{
+	return *addr;
+}
diff --git a/src/pkg/runtime/Makefile b/src/pkg/runtime/Makefile
index 79f847e..03f960c 100644
--- a/src/pkg/runtime/Makefile
+++ b/src/pkg/runtime/Makefile
@@ -47,6 +47,7 @@ OFILES_arm=\
 
 OFILES=\
 	asm.$O\
+	atomic.$O\
 	cgocall.$O\
 	chan.$O\
 	closure.$O\
diff --git a/src/pkg/runtime/amd64/atomic.c b/src/pkg/runtime/amd64/atomic.c
new file mode 100644
index 0000000..c031cc4
--- /dev/null
+++ b/src/pkg/runtime/amd64/atomic.c
@@ -0,0 +1,12 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+
+#pragma textflag 7
+uint32
+runtime·atomicload(uint32 volatile* addr)
+{
+	return *addr;
+}
diff --git a/src/pkg/runtime/arm/atomic.c b/src/pkg/runtime/arm/atomic.c
new file mode 100644
index 0000000..9fd47ba
--- /dev/null
+++ b/src/pkg/runtime/arm/atomic.c
@@ -0,0 +1,12 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+
+#pragma textflag 7
+uint32
+runtime·atomicload(uint32 volatile* addr)
+{
+	return runtime·xadd(addr, 0);
+}
diff --git a/src/pkg/runtime/cgo/darwin_386.c b/src/pkg/runtime/cgo/darwin_386.c
index 13184f3..6d4e259 100644
--- a/src/pkg/runtime/cgo/darwin_386.c
+++ b/src/pkg/runtime/cgo/darwin_386.c
@@ -113,11 +113,16 @@ libcgo_sys_thread_start(ThreadStart *ts)
 	pthread_attr_t attr;
 	pthread_t p;
 	size_t size;
+	int err;
 
 	pthread_attr_init(&attr);
 	pthread_attr_getstacksize(&attr, &size);
 	ts->g->stackguard = size;
-	pthread_create(&p, &attr, threadentry, ts);
+	err = pthread_create(&p, &attr, threadentry, ts);
+	if (err != 0) {
+		fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
+		abort();
+	}
 }
 
 static void*
diff --git a/src/pkg/runtime/cgo/darwin_amd64.c b/src/pkg/runtime/cgo/darwin_amd64.c
index 38cd80a..3471044 100644
--- a/src/pkg/runtime/cgo/darwin_amd64.c
+++ b/src/pkg/runtime/cgo/darwin_amd64.c
@@ -83,11 +83,16 @@ libcgo_sys_thread_start(ThreadStart *ts)
 	pthread_attr_t attr;
 	pthread_t p;
 	size_t size;
+	int err;
 
 	pthread_attr_init(&attr);
 	pthread_attr_getstacksize(&attr, &size);
 	ts->g->stackguard = size;
-	pthread_create(&p, &attr, threadentry, ts);
+	err = pthread_create(&p, &attr, threadentry, ts);
+	if (err != 0) {
+		fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
+		abort();
+	}
 }
 
 static void*
diff --git a/src/pkg/runtime/cgo/freebsd_386.c b/src/pkg/runtime/cgo/freebsd_386.c
index d08e1de..ae53201 100644
--- a/src/pkg/runtime/cgo/freebsd_386.c
+++ b/src/pkg/runtime/cgo/freebsd_386.c
@@ -20,11 +20,16 @@ libcgo_sys_thread_start(ThreadStart *ts)
 	pthread_attr_t attr;
 	pthread_t p;
 	size_t size;
+	int err;
 
 	pthread_attr_init(&attr);
 	pthread_attr_getstacksize(&attr, &size);
 	ts->g->stackguard = size;
-	pthread_create(&p, &attr, threadentry, ts);
+	err = pthread_create(&p, &attr, threadentry, ts);
+	if (err != 0) {
+		fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
+		abort();
+	}
 }
 
 static void*
diff --git a/src/pkg/runtime/cgo/freebsd_amd64.c b/src/pkg/runtime/cgo/freebsd_amd64.c
index fe6ce39..5afc1df 100644
--- a/src/pkg/runtime/cgo/freebsd_amd64.c
+++ b/src/pkg/runtime/cgo/freebsd_amd64.c
@@ -20,11 +20,16 @@ libcgo_sys_thread_start(ThreadStart *ts)
 	pthread_attr_t attr;
 	pthread_t p;
 	size_t size;
+	int err;
 
 	pthread_attr_init(&attr);
 	pthread_attr_getstacksize(&attr, &size);
 	ts->g->stackguard = size;
-	pthread_create(&p, &attr, threadentry, ts);
+	err = pthread_create(&p, &attr, threadentry, ts);
+	if (err != 0) {
+		fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
+		abort();
+	}
 }
 
 static void*
diff --git a/src/pkg/runtime/cgo/linux_386.c b/src/pkg/runtime/cgo/linux_386.c
index 00322d4..e9df5ff 100644
--- a/src/pkg/runtime/cgo/linux_386.c
+++ b/src/pkg/runtime/cgo/linux_386.c
@@ -21,6 +21,7 @@ libcgo_sys_thread_start(ThreadStart *ts)
 	pthread_attr_t attr;
 	pthread_t p;
 	size_t size;
+	int err;
 
 	// Not sure why the memset is necessary here,
 	// but without it, we get a bogus stack size
@@ -30,7 +31,11 @@ libcgo_sys_thread_start(ThreadStart *ts)
 	size = 0;
 	pthread_attr_getstacksize(&attr, &size);
 	ts->g->stackguard = size;
-	pthread_create(&p, &attr, threadentry, ts);
+	err = pthread_create(&p, &attr, threadentry, ts);
+	if (err != 0) {
+		fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
+		abort();
+	}
 }
 
 static void*
diff --git a/src/pkg/runtime/cgo/linux_amd64.c b/src/pkg/runtime/cgo/linux_amd64.c
index e77c5dd..d9b8b37 100644
--- a/src/pkg/runtime/cgo/linux_amd64.c
+++ b/src/pkg/runtime/cgo/linux_amd64.c
@@ -20,11 +20,16 @@ libcgo_sys_thread_start(ThreadStart *ts)
 	pthread_attr_t attr;
 	pthread_t p;
 	size_t size;
+	int err;
 
 	pthread_attr_init(&attr);
 	pthread_attr_getstacksize(&attr, &size);
 	ts->g->stackguard = size;
-	pthread_create(&p, &attr, threadentry, ts);
+	err = pthread_create(&p, &attr, threadentry, ts);
+	if (err != 0) {
+		fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
+		abort();
+	}
 }
 
 static void*
diff --git a/src/pkg/runtime/cgo/windows_amd64.c b/src/pkg/runtime/cgo/windows_amd64.c
index dafe8cd..fd5b397 100755
--- a/src/pkg/runtime/cgo/windows_amd64.c
+++ b/src/pkg/runtime/cgo/windows_amd64.c
@@ -37,11 +37,21 @@ threadentry(void *v)
 	ts.g->stackbase = (uintptr)&ts;
 
 	/*
-	* libcgo_sys_thread_start set stackguard to stack size;
-	* change to actual guard pointer.
-	*/
+	 * libcgo_sys_thread_start set stackguard to stack size;
+	 * change to actual guard pointer.
+	 */
 	ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096;
 
-	crosscall_386(ts.fn);
+	/*
+	 * Set specific keys in thread local storage.
+	 */
+	asm volatile (
+	  "movq %%gs:0x58, %%rax\n" // MOVQ 0x58(GS), tmp
+	  "movq %0, 0(%%rax)\n" // MOVQ g, 0(GS)
+	  "movq %1, 8(%%rax)\n" // MOVQ m, 8(GS)
+	  :: "r"(ts.g), "r"(ts.m) : "%rax"
+	);
+
+	crosscall_amd64(ts.fn);
 	return nil;
 }
diff --git a/src/pkg/runtime/debug/stack.go b/src/pkg/runtime/debug/stack.go
index e5fae63..a533a5c 100644
--- a/src/pkg/runtime/debug/stack.go
+++ b/src/pkg/runtime/debug/stack.go
@@ -52,7 +52,7 @@ func stack() []byte {
 			if err != nil {
 				continue
 			}
-			lines = bytes.Split(data, []byte{'\n'}, -1)
+			lines = bytes.Split(data, []byte{'\n'})
 			lastFile = file
 		}
 		line-- // in stack trace, lines are 1-indexed but our array is 0-indexed
diff --git a/src/pkg/runtime/debug/stack_test.go b/src/pkg/runtime/debug/stack_test.go
index f4bdc46..4aeea13 100644
--- a/src/pkg/runtime/debug/stack_test.go
+++ b/src/pkg/runtime/debug/stack_test.go
@@ -35,7 +35,7 @@ func (t T) method() []byte {
 */
 func TestStack(t *testing.T) {
 	b := T(0).method()
-	lines := strings.Split(string(b), "\n", -1)
+	lines := strings.Split(string(b), "\n")
 	if len(lines) <= 6 {
 		t.Fatal("too few lines")
 	}
diff --git a/src/pkg/runtime/mkasmh.sh b/src/pkg/runtime/mkasmh.sh
index 00b5b3c..328e2d5 100755
--- a/src/pkg/runtime/mkasmh.sh
+++ b/src/pkg/runtime/mkasmh.sh
@@ -61,14 +61,23 @@ case "$GOARCH" in
 	esac
 	;;
 amd64)
-	# The offsets 0 and 8 are known to:
-	#	../../cmd/6l/pass.c:/D_GS
-	#	../../libcgo/linux_amd64.c:/^threadentry
-	#	../../libcgo/darwin_amd64.c:/^threadentry
-	#
-	echo '#define	get_tls(r)'
-	echo '#define	g(r) 0(GS)'
-	echo '#define	m(r) 8(GS)'
+	case "$GOOS" in
+	windows)
+		echo '#define	get_tls(r) MOVQ 0x58(GS), r'
+		echo '#define	g(r) 0(r)'
+		echo '#define	m(r) 8(r)'
+		;;
+	*)
+		# The offsets 0 and 8 are known to:
+		#	../../cmd/6l/pass.c:/D_GS
+		#	../../libcgo/linux_amd64.c:/^threadentry
+		#	../../libcgo/darwin_amd64.c:/^threadentry
+		#
+		echo '#define	get_tls(r)'
+		echo '#define	g(r) 0(GS)'
+		echo '#define	m(r) 8(GS)'
+		;;
+	esac
 	;;
 arm)
 	echo '#define	g	R10'
diff --git a/src/pkg/runtime/proc.c b/src/pkg/runtime/proc.c
index c5af8b7..a8f3a79 100644
--- a/src/pkg/runtime/proc.c
+++ b/src/pkg/runtime/proc.c
@@ -77,7 +77,7 @@ struct Sched {
 };
 
 Sched runtime·sched;
-int32 gomaxprocs;
+int32 runtime·gomaxprocs;
 
 // An m that is waiting for notewakeup(&m->havenextg).  This may be
 // only be accessed while the scheduler lock is held.  This is used to
diff --git a/src/pkg/runtime/runtime.h b/src/pkg/runtime/runtime.h
index f3ccff1..ad5da0a 100644
--- a/src/pkg/runtime/runtime.h
+++ b/src/pkg/runtime/runtime.h
@@ -242,6 +242,11 @@ struct	M
 	uint32	fflag;		// floating point compare flags
 #ifdef __WINDOWS__
 	void*	sehframe;
+
+#ifdef _64BIT	
+	void*	gostack;
+#endif
+
 #endif
 };
 
@@ -416,7 +421,10 @@ int32	runtime·write(int32, void*, int32);
 int32	runtime·mincore(void*, uintptr, byte*);
 bool	runtime·cas(uint32*, uint32, uint32);
 bool	runtime·casp(void**, void*, void*);
+// Don't confuse with XADD x86 instruction,
+// this one is actually 'addx', that is, add-and-fetch.
 uint32	runtime·xadd(uint32 volatile*, int32);
+uint32  runtime·atomicload(uint32 volatile*);
 void	runtime·jmpdefer(byte*, void*);
 void	runtime·exit1(int32);
 void	runtime·ready(G*);
diff --git a/src/pkg/runtime/sema.goc b/src/pkg/runtime/sema.goc
index 1c77e87..ae84351 100644
--- a/src/pkg/runtime/sema.goc
+++ b/src/pkg/runtime/sema.goc
@@ -23,104 +23,68 @@ package runtime
 typedef struct Sema Sema;
 struct Sema
 {
-	uint32 *addr;
+	uint32 volatile *addr;
 	G *g;
 	Sema *prev;
 	Sema *next;
 };
 
-// TODO: For now, a linked list; maybe a hash table of linked lists later.
-static Sema *semfirst, *semlast;
-static Lock semlock;
+typedef struct SemaRoot SemaRoot;
+struct SemaRoot
+{
+        Lock;
+	Sema *head;
+	Sema *tail;
+	// Number of waiters. Read w/o the lock.
+	uint32 volatile nwait;
+};
+
+// Prime to not correlate with any user patterns.
+#define SEMTABLESZ 251
+
+static union
+{
+	SemaRoot;
+	// Modern processors tend to have 64-byte cache lines,
+	// potentially with 128-byte effective cache line size for reading.
+	// While there are hypothetical architectures
+	// with 16-4096 byte cache lines, 128 looks like a good compromise.
+	uint8 pad[128];
+} semtable[SEMTABLESZ];
+
+static SemaRoot*
+semroot(uint32 *addr)
+{
+	return &semtable[((uintptr)addr >> 3) % SEMTABLESZ];
+}
 
 static void
-semqueue(uint32 *addr, Sema *s)
+semqueue(SemaRoot *root, uint32 volatile *addr, Sema *s)
 {
+	s->g = g;
 	s->addr = addr;
-	s->g = nil;
-
-	runtime·lock(&semlock);
-	s->prev = semlast;
 	s->next = nil;
-	if(semlast)
-		semlast->next = s;
+	s->prev = root->tail;
+	if(root->tail)
+		root->tail->next = s;
 	else
-		semfirst = s;
-	semlast = s;
-	runtime·unlock(&semlock);
+		root->head = s;
+	root->tail = s;
 }
 
 static void
-semdequeue(Sema *s)
+semdequeue(SemaRoot *root, Sema *s)
 {
-	runtime·lock(&semlock);
 	if(s->next)
 		s->next->prev = s->prev;
 	else
-		semlast = s->prev;
+		root->tail = s->prev;
 	if(s->prev)
 		s->prev->next = s->next;
 	else
-		semfirst = s->next;
+		root->head = s->next;
 	s->prev = nil;
 	s->next = nil;
-	runtime·unlock(&semlock);
-}
-
-static void
-semwakeup(uint32 *addr)
-{
-	Sema *s;
-
-	runtime·lock(&semlock);
-	for(s=semfirst; s; s=s->next) {
-		if(s->addr == addr && s->g) {
-			runtime·ready(s->g);
-			s->g = nil;
-			break;
-		}
-	}
-	runtime·unlock(&semlock);
-}
-
-// Step 1 of sleep: make ourselves available for wakeup.
-// TODO(rsc): Maybe we can write a version without
-// locks by using cas on s->g.  Maybe not: I need to
-// think more about whether it would be correct.
-static void
-semsleep1(Sema *s)
-{
-	runtime·lock(&semlock);
-	s->g = g;
-	runtime·unlock(&semlock);
-}
-
-// Decided not to go through with it: undo step 1.
-static void
-semsleepundo1(Sema *s)
-{
-	runtime·lock(&semlock);
-	if(s->g != nil) {
-		s->g = nil;	// back ourselves out
-	} else {
-		// If s->g == nil already, semwakeup
-		// already readied us.  Since we never stopped
-		// running, readying us just set g->readyonstop.
-		// Clear it.
-		if(g->readyonstop == 0)
-			*(int32*)0x555 = 555;
-		g->readyonstop = 0;
-	}
-	runtime·unlock(&semlock);
-}
-
-// Step 2: wait for the wakeup.
-static void
-semsleep2(Sema *s)
-{
-	USED(s);
-	g->status = Gwaiting;
-	runtime·gosched();
 }
 
 static int32
@@ -128,52 +92,83 @@ cansemacquire(uint32 *addr)
 {
 	uint32 v;
 
-	while((v = *addr) > 0)
+	while((v = runtime·atomicload(addr)) > 0)
 		if(runtime·cas(addr, v, v-1))
 			return 1;
 	return 0;
 }
 
-// For now has no return value.
-// Might return an ok (not interrupted) bool in the future?
 void
-runtime·semacquire(uint32 *addr)
+runtime·semacquire(uint32 volatile *addr)
 {
 	Sema s;
+	SemaRoot *root;
 
 	// Easy case.
 	if(cansemacquire(addr))
 		return;
 
 	// Harder case:
-	//	queue
-	//	try semacquire one more time, sleep if failed
-	//	dequeue
-	//	wake up one more guy to avoid races (TODO(rsc): maybe unnecessary?)
-	semqueue(addr, &s);
+	//	increment waiter count
+	//	try cansemacquire one more time, return if succeeded
+	//	enqueue itself as a waiter
+	//	sleep
+	//	(waiter descriptor is dequeued by signaler)
+	root = semroot(addr);
 	for(;;) {
-		semsleep1(&s);
+		runtime·lock(root);
+		// Add ourselves to nwait to disable "easy case" in semrelease.
+		runtime·xadd(&root->nwait, 1);
+		// Check cansemacquire to avoid missed wakeup.
 		if(cansemacquire(addr)) {
-			semsleepundo1(&s);
-			break;
+			runtime·xadd(&root->nwait, -1);
+			runtime·unlock(root);
+			return;
 		}
-		semsleep2(&s);
+		// Any semrelease after the cansemacquire knows we're waiting
+		// (we set nwait above), so go to sleep.
+		semqueue(root, addr, &s);
+		g->status = Gwaiting;
+		runtime·unlock(root);
+		runtime·gosched();
+		if(cansemacquire(addr))
+			return;
 	}
-	semdequeue(&s);
-	semwakeup(addr);
 }
 
 void
-runtime·semrelease(uint32 *addr)
+runtime·semrelease(uint32 volatile *addr)
 {
-	uint32 v;
+	Sema *s;
+	SemaRoot *root;
 
-	for(;;) {
-		v = *addr;
-		if(runtime·cas(addr, v, v+1))
+	root = semroot(addr);
+	runtime·xadd(addr, 1);
+
+	// Easy case: no waiters?
+	// This check must happen after the xadd, to avoid a missed wakeup
+	// (see loop in semacquire).
+	if(runtime·atomicload(&root->nwait) == 0)
+		return;
+
+	// Harder case: search for a waiter and wake it.
+	runtime·lock(root);
+	if(runtime·atomicload(&root->nwait) == 0) {
+		// The count is already consumed by another goroutine,
+		// so no need to wake up another goroutine.
+		runtime·unlock(root);
+		return;
+	}
+	for(s = root->head; s; s = s->next) {
+		if(s->addr == addr) {
+			runtime·xadd(&root->nwait, -1);
+			semdequeue(root, s);
 			break;
+		}
 	}
-	semwakeup(addr);
+	runtime·unlock(root);
+	if(s)
+		runtime·ready(s->g);
 }
 
 func Semacquire(addr *uint32) {
diff --git a/src/pkg/runtime/sema_test.go b/src/pkg/runtime/sema_test.go
new file mode 100644
index 0000000..d95bb1e
--- /dev/null
+++ b/src/pkg/runtime/sema_test.go
@@ -0,0 +1,100 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime_test
+
+import (
+	"runtime"
+	"sync/atomic"
+	"testing"
+)
+
+func BenchmarkSemaUncontended(b *testing.B) {
+	type PaddedSem struct {
+		sem uint32
+		pad [32]uint32
+	}
+	const CallsPerSched = 1000
+	procs := runtime.GOMAXPROCS(-1)
+	N := int32(b.N / CallsPerSched)
+	c := make(chan bool, procs)
+	for p := 0; p < procs; p++ {
+		go func() {
+			sem := new(PaddedSem)
+			for atomic.AddInt32(&N, -1) >= 0 {
+				runtime.Gosched()
+				for g := 0; g < CallsPerSched; g++ {
+					runtime.Semrelease(&sem.sem)
+					runtime.Semacquire(&sem.sem)
+				}
+			}
+			c <- true
+		}()
+	}
+	for p := 0; p < procs; p++ {
+		<-c
+	}
+}
+
+func benchmarkSema(b *testing.B, block, work bool) {
+	const CallsPerSched = 1000
+	const LocalWork = 100
+	procs := runtime.GOMAXPROCS(-1)
+	N := int32(b.N / CallsPerSched)
+	c := make(chan bool, procs)
+	c2 := make(chan bool, procs/2)
+	sem := uint32(0)
+	if block {
+		for p := 0; p < procs/2; p++ {
+			go func() {
+				runtime.Semacquire(&sem)
+				c2 <- true
+			}()
+		}
+	}
+	for p := 0; p < procs; p++ {
+		go func() {
+			foo := 0
+			for atomic.AddInt32(&N, -1) >= 0 {
+				runtime.Gosched()
+				for g := 0; g < CallsPerSched; g++ {
+					runtime.Semrelease(&sem)
+					if work {
+						for i := 0; i < LocalWork; i++ {
+							foo *= 2
+							foo /= 2
+						}
+					}
+					runtime.Semacquire(&sem)
+				}
+			}
+			c <- foo == 42
+			runtime.Semrelease(&sem)
+		}()
+	}
+	if block {
+		for p := 0; p < procs/2; p++ {
+			<-c2
+		}
+	}
+	for p := 0; p < procs; p++ {
+		<-c
+	}
+}
+
+func BenchmarkSemaSyntNonblock(b *testing.B) {
+	benchmarkSema(b, false, false)
+}
+
+func BenchmarkSemaSyntBlock(b *testing.B) {
+	benchmarkSema(b, true, false)
+}
+
+func BenchmarkSemaWorkNonblock(b *testing.B) {
+	benchmarkSema(b, false, true)
+}
+
+func BenchmarkSemaWorkBlock(b *testing.B) {
+	benchmarkSema(b, true, true)
+}
diff --git a/src/pkg/runtime/windows/amd64/defs.h b/src/pkg/runtime/windows/amd64/defs.h
new file mode 100644
index 0000000..830c6a8
--- /dev/null
+++ b/src/pkg/runtime/windows/amd64/defs.h
@@ -0,0 +1,40 @@
+// g:\opensource\go\bin\godefs.exe -f -m64 defs.c
+
+// MACHINE GENERATED - DO NOT EDIT.
+
+// Constants
+enum {
+	PROT_NONE = 0,
+	PROT_READ = 0x1,
+	PROT_WRITE = 0x2,
+	PROT_EXEC = 0x4,
+	MAP_ANON = 0x1,
+	MAP_PRIVATE = 0x2,
+	SIGINT = 0x2,
+	CTRL_C_EVENT = 0,
+	CTRL_BREAK_EVENT = 0x1,
+	EXCEPTION_ACCESS_VIOLATION = 0xc0000005,
+	EXCEPTION_BREAKPOINT = 0x80000003,
+	EXCEPTION_FLT_DENORMAL_OPERAND = 0xc000008d,
+	EXCEPTION_FLT_DIVIDE_BY_ZERO = 0xc000008e,
+	EXCEPTION_FLT_INEXACT_RESULT = 0xc000008f,
+	EXCEPTION_FLT_OVERFLOW = 0xc0000091,
+	EXCEPTION_FLT_UNDERFLOW = 0xc0000093,
+	EXCEPTION_INT_DIVIDE_BY_ZERO = 0xc0000094,
+	EXCEPTION_INT_OVERFLOW = 0xc0000095,
+};
+
+// Types
+#pragma pack on
+
+typedef struct ExceptionRecord ExceptionRecord;
+struct ExceptionRecord {
+	uint32 ExceptionCode;
+	uint32 ExceptionFlags;
+	ExceptionRecord *ExceptionRecord;
+	void *ExceptionAddress;
+	uint32 NumberParameters;
+	byte pad_godefs_0[4];
+	uint64 ExceptionInformation[15];
+};
+#pragma pack off
diff --git a/src/pkg/runtime/windows/amd64/rt0.s b/src/pkg/runtime/windows/amd64/rt0.s
new file mode 100644
index 0000000..e54e7ed
--- /dev/null
+++ b/src/pkg/runtime/windows/amd64/rt0.s
@@ -0,0 +1,10 @@
+// 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.
+
+#include "amd64/asm.h"
+
+TEXT	_rt0_amd64_windows(SB),7,$-8
+	MOVQ	$_rt0_amd64(SB), AX
+	MOVQ	SP, DI
+	JMP	AX
diff --git a/src/pkg/runtime/windows/amd64/signal.c b/src/pkg/runtime/windows/amd64/signal.c
new file mode 100644
index 0000000..1fc3eb0
--- /dev/null
+++ b/src/pkg/runtime/windows/amd64/signal.c
@@ -0,0 +1,20 @@
+// 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.
+
+#include "runtime.h"
+#include "defs.h"
+#include "os.h"
+
+void
+runtime·initsig(int32 queue)
+{
+}
+
+void
+runtime·resetcpuprofiler(int32 hz)
+{
+	// TODO: Enable profiling interrupts.
+	
+	m->profilehz = hz;
+}
diff --git a/src/pkg/runtime/windows/amd64/sys.s b/src/pkg/runtime/windows/amd64/sys.s
new file mode 100644
index 0000000..b1eacfc
--- /dev/null
+++ b/src/pkg/runtime/windows/amd64/sys.s
@@ -0,0 +1,129 @@
+// 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.
+
+#include "amd64/asm.h"
+
+// void *stdcall_raw(void *fn, uintptr nargs, void *args)
+TEXT runtime·stdcall_raw(SB),7,$8
+	MOVQ	fn+0(FP), AX
+	MOVQ	nargs+8(FP), CX
+	MOVQ	args+16(FP), R11
+
+	// Switch to m->g0 if needed.
+	get_tls(DI)
+	MOVQ	m(DI), DX
+	MOVQ	g(DI), SI
+	MOVQ	SI, 0(SP)		// save g
+	MOVQ	SP, m_gostack(DX)	// save SP
+	MOVQ	m_g0(DX), SI
+	CMPQ	g(DI), SI
+	JEQ 3(PC)
+	MOVQ	(g_sched+gobuf_sp)(SI), SP
+	MOVQ	SI, g(DI)
+	
+	SUBQ	$0x60, SP
+	
+	// Copy args to new stack.
+	MOVQ	SP, DI
+	MOVQ	R11, SI
+	CLD
+	REP; MOVSQ
+	MOVQ	0(R11), CX
+	MOVQ	8(R11), DX
+	MOVQ	16(R11), R8
+	MOVQ	24(R11), R9
+
+	// Call stdcall function.
+	CALL	AX
+	
+	// Restore original SP, g.
+	get_tls(DI)
+	MOVQ	m(DI), DX
+	MOVQ	m_gostack(DX), SP	// restore SP
+	MOVQ	0(SP), SI		// restore g
+	MOVQ	SI, g(DI)
+
+	RET
+
+// faster get/set last error
+TEXT runtime·getlasterror(SB),7,$0
+	MOVQ	0x30(GS), AX
+	MOVL	0x68(AX), AX
+	RET
+
+TEXT runtime·setlasterror(SB),7,$0
+	MOVL	err+0(FP), AX
+	MOVQ	0x30(GS),	CX
+	MOVL	AX, 0x68(CX)
+	RET
+
+// Windows runs the ctrl handler in a new thread.
+TEXT runtime·ctrlhandler(SB),7,$0
+	// TODO
+	RET
+	
+TEXT runtime·callbackasm(SB),7,$0
+	// TODO
+	RET
+
+// void tstart(M *newm);
+TEXT runtime·tstart(SB),7,$0
+	MOVQ	newm+8(SP), CX		// m
+	MOVQ	m_g0(CX), DX		// g
+
+	MOVQ	SP, DI			// remember stack
+
+	// Layout new m scheduler stack on os stack.
+	MOVQ	SP, AX
+	MOVQ	AX, g_stackbase(DX)
+	SUBQ	$(64*1024), AX	// stack size
+	MOVQ	AX, g_stackguard(DX)
+
+	// Set up tls.
+	LEAQ	m_tls(CX), SI
+	MOVQ	SI, 0x58(GS)
+	MOVQ	CX, m(SI)
+	MOVQ	DX, g(SI)
+
+	// Someday the convention will be D is always cleared.
+	CLD
+
+	PUSHQ	DI			// original stack
+
+	CALL	runtime·stackcheck(SB)		// clobbers AX,CX
+
+	CALL	runtime·mstart(SB)
+
+	POPQ	DI			// original stack
+	MOVQ	DI, SP
+	
+	RET
+
+// uint32 tstart_stdcall(M *newm);
+TEXT runtime·tstart_stdcall(SB),7,$0
+	MOVQ CX, BX // stdcall first arg in RCX
+
+	PUSHQ	BX
+	CALL	runtime·tstart+0(SB)
+	POPQ	BX
+
+	// Adjust stack for stdcall to return properly.
+	MOVQ	(SP), AX		// save return address
+	ADDQ	$8, SP			// remove single parameter
+	MOVQ	AX, (SP)		// restore return address
+
+	XORL	AX, AX			// return 0 == success
+
+	RET
+
+TEXT runtime·notok(SB),7,$0
+	MOVQ	$0xf1, BP
+	MOVQ	BP, (BP)
+	RET
+
+// set tls base to DI
+TEXT runtime·settls(SB),7,$0
+	MOVQ	DI, 0x58(GS)
+	RET
+
diff --git a/src/pkg/runtime/windows/mem.c b/src/pkg/runtime/windows/mem.c
index 54d77da..5d2291f 100644
--- a/src/pkg/runtime/windows/mem.c
+++ b/src/pkg/runtime/windows/mem.c
@@ -24,7 +24,7 @@ void*
 runtime·SysAlloc(uintptr n)
 {
 	mstats.sys += n;
-	return runtime·stdcall(runtime·VirtualAlloc, 4, nil, n, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
+	return runtime·stdcall(runtime·VirtualAlloc, 4, nil, n, (uintptr)(MEM_COMMIT|MEM_RESERVE), (uintptr)PAGE_EXECUTE_READWRITE);
 }
 
 void
@@ -40,7 +40,7 @@ runtime·SysFree(void *v, uintptr n)
 	uintptr r;
 
 	mstats.sys -= n;
-	r = (uintptr)runtime·stdcall(runtime·VirtualFree, 3, v, 0, MEM_RELEASE);
+	r = (uintptr)runtime·stdcall(runtime·VirtualFree, 3, v, (uintptr)0, (uintptr)MEM_RELEASE);
 	if(r == 0)
 		runtime·throw("runtime: failed to release pages");
 }
@@ -50,12 +50,12 @@ runtime·SysReserve(void *v, uintptr n)
 {
 	// v is just a hint.
 	// First try at v.
-	v = runtime·stdcall(runtime·VirtualAlloc, 4, v, n, MEM_RESERVE, PAGE_EXECUTE_READWRITE);
+	v = runtime·stdcall(runtime·VirtualAlloc, 4, v, n, (uintptr)MEM_RESERVE, (uintptr)PAGE_EXECUTE_READWRITE);
 	if(v != nil)
 		return v;
 	
 	// Next let the kernel choose the address.
-	return runtime·stdcall(runtime·VirtualAlloc, 4, nil, n, MEM_RESERVE, PAGE_EXECUTE_READWRITE);
+	return runtime·stdcall(runtime·VirtualAlloc, 4, nil, n, (uintptr)MEM_RESERVE, (uintptr)PAGE_EXECUTE_READWRITE);
 }
 
 void
@@ -64,7 +64,7 @@ runtime·SysMap(void *v, uintptr n)
 	void *p;
 	
 	mstats.sys += n;
-	p = runtime·stdcall(runtime·VirtualAlloc, 4, v, n, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
+	p = runtime·stdcall(runtime·VirtualAlloc, 4, v, n, (uintptr)MEM_COMMIT, (uintptr)PAGE_EXECUTE_READWRITE);
 	if(p != v)
 		runtime·throw("runtime: cannot map pages in arena address space");
 }
diff --git a/src/pkg/runtime/windows/os.h b/src/pkg/runtime/windows/os.h
index 77881e8..bc96787 100644
--- a/src/pkg/runtime/windows/os.h
+++ b/src/pkg/runtime/windows/os.h
@@ -7,6 +7,9 @@ extern void *runtime·GetProcAddress;
 
 // Call a Windows function with stdcall conventions,
 // and switch to os stack during the call.
+#pragma	varargck	countpos	runtime·stdcall	2
+#pragma	varargck	type		runtime·stdcall	void*
+#pragma	varargck	type		runtime·stdcall	uintptr
 void *runtime·stdcall_raw(void *fn, uintptr nargs, void *args);
 void *runtime·stdcall(void *fn, int32 count, ...);
 uintptr runtime·syscall(void *fn, uintptr nargs, void *args, uintptr *err);
diff --git a/src/pkg/runtime/windows/thread.c b/src/pkg/runtime/windows/thread.c
index 81ad680..5644fd5 100644
--- a/src/pkg/runtime/windows/thread.c
+++ b/src/pkg/runtime/windows/thread.c
@@ -45,7 +45,7 @@ void
 runtime·osinit(void)
 {
 	runtime·stdcall(runtime·QueryPerformanceFrequency, 1, &timerfreq);
-	runtime·stdcall(runtime·SetConsoleCtrlHandler, 2, runtime·ctrlhandler, 1);
+	runtime·stdcall(runtime·SetConsoleCtrlHandler, 2, runtime·ctrlhandler, (uintptr)1);
 }
 
 void
@@ -81,7 +81,7 @@ runtime·goenvs(void)
 void
 runtime·exit(int32 code)
 {
-	runtime·stdcall(runtime·ExitProcess, 1, code);
+	runtime·stdcall(runtime·ExitProcess, 1, (uintptr)code);
 }
 
 int32
@@ -93,15 +93,15 @@ runtime·write(int32 fd, void *buf, int32 n)
 	written = 0;
 	switch(fd) {
 	case 1:
-		handle = runtime·stdcall(runtime·GetStdHandle, 1, -11);
+		handle = runtime·stdcall(runtime·GetStdHandle, 1, (uintptr)-11);
 		break;
 	case 2:
-		handle = runtime·stdcall(runtime·GetStdHandle, 1, -12);
+		handle = runtime·stdcall(runtime·GetStdHandle, 1, (uintptr)-12);
 		break;
 	default:
 		return -1;
 	}
-	runtime·stdcall(runtime·WriteFile, 5, handle, buf, n, &written, 0);
+	runtime·stdcall(runtime·WriteFile, 5, handle, buf, (uintptr)n, &written, (uintptr)0);
 	return written;
 }
 
@@ -111,7 +111,7 @@ initevent(void **pevent)
 {
 	void *event;
 
-	event = runtime·stdcall(runtime·CreateEvent, 4, 0, 0, 0, 0);
+	event = runtime·stdcall(runtime·CreateEvent, 4, (uintptr)0, (uintptr)0, (uintptr)0, (uintptr)0);
 	if(!runtime·casp(pevent, 0, event)) {
 		// Someone else filled it in.  Use theirs.
 		runtime·stdcall(runtime·CloseHandle, 1, event);
@@ -126,7 +126,7 @@ eventlock(Lock *l)
 		initevent(&l->event);
 
 	if(runtime·xadd(&l->key, 1) > 1)	// someone else has it; wait
-		runtime·stdcall(runtime·WaitForSingleObject, 2, l->event, -1);
+		runtime·stdcall(runtime·WaitForSingleObject, 2, l->event, (uintptr)-1);
 }
 
 static void
@@ -190,7 +190,7 @@ runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void))
 	USED(g);	// assuming g = m->g0
 	USED(fn);	// assuming fn = mstart
 
-	thandle = runtime·stdcall(runtime·CreateThread, 6, 0, 0, runtime·tstart_stdcall, m, 0, 0);
+	thandle = runtime·stdcall(runtime·CreateThread, 6, (uintptr)0, (uintptr)0, runtime·tstart_stdcall, m, (uintptr)0, (uintptr)0);
 	if(thandle == 0) {
 		runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount(), runtime·getlasterror());
 		runtime·throw("runtime.newosproc");
@@ -219,7 +219,7 @@ runtime·gettime(int64 *sec, int32 *usec)
 void *
 runtime·stdcall(void *fn, int32 count, ...)
 {
-	return runtime·stdcall_raw(fn, count, (uintptr*)(&count + 1));
+	return runtime·stdcall_raw(fn, count, (uintptr*)&count + 1);
 }
 
 uintptr
diff --git a/src/pkg/smtp/smtp.go b/src/pkg/smtp/smtp.go
index d716df5..2d5e862 100644
--- a/src/pkg/smtp/smtp.go
+++ b/src/pkg/smtp/smtp.go
@@ -93,11 +93,11 @@ func (c *Client) ehlo() os.Error {
 		return err
 	}
 	ext := make(map[string]string)
-	extList := strings.Split(msg, "\n", -1)
+	extList := strings.Split(msg, "\n")
 	if len(extList) > 1 {
 		extList = extList[1:]
 		for _, line := range extList {
-			args := strings.Split(line, " ", 2)
+			args := strings.SplitN(line, " ", 2)
 			if len(args) > 1 {
 				ext[args[0]] = args[1]
 			} else {
@@ -106,7 +106,7 @@ func (c *Client) ehlo() os.Error {
 		}
 	}
 	if mechs, ok := ext["AUTH"]; ok {
-		c.auth = strings.Split(mechs, " ", -1)
+		c.auth = strings.Split(mechs, " ")
 	}
 	c.ext = ext
 	return err
diff --git a/src/pkg/smtp/smtp_test.go b/src/pkg/smtp/smtp_test.go
index 49363ad..c053557 100644
--- a/src/pkg/smtp/smtp_test.go
+++ b/src/pkg/smtp/smtp_test.go
@@ -64,8 +64,8 @@ func (f faker) Close() os.Error {
 }
 
 func TestBasic(t *testing.T) {
-	basicServer = strings.Join(strings.Split(basicServer, "\n", -1), "\r\n")
-	basicClient = strings.Join(strings.Split(basicClient, "\n", -1), "\r\n")
+	basicServer = strings.Join(strings.Split(basicServer, "\n"), "\r\n")
+	basicClient = strings.Join(strings.Split(basicClient, "\n"), "\r\n")
 
 	var cmdbuf bytes.Buffer
 	bcmdbuf := bufio.NewWriter(&cmdbuf)
diff --git a/src/pkg/sort/sort.go b/src/pkg/sort/sort.go
index b707579..daed61e 100644
--- a/src/pkg/sort/sort.go
+++ b/src/pkg/sort/sort.go
@@ -190,12 +190,12 @@ func (p StringSlice) Sort() { Sort(p) }
 
 // Convenience wrappers for common cases
 
-// SortInts sorts a slice of ints in increasing order.
-func SortInts(a []int) { Sort(IntSlice(a)) }
-// SortFloat64s sorts a slice of float64s in increasing order.
-func SortFloat64s(a []float64) { Sort(Float64Slice(a)) }
-// SortStrings sorts a slice of strings in increasing order.
-func SortStrings(a []string) { Sort(StringSlice(a)) }
+// Ints sorts a slice of ints in increasing order.
+func Ints(a []int) { Sort(IntSlice(a)) }
+// Float64s sorts a slice of float64s in increasing order.
+func Float64s(a []float64) { Sort(Float64Slice(a)) }
+// Strings sorts a slice of strings in increasing order.
+func Strings(a []string) { Sort(StringSlice(a)) }
 
 
 // IntsAreSorted tests whether a slice of ints is sorted in increasing order.
diff --git a/src/pkg/sort/sort_test.go b/src/pkg/sort/sort_test.go
index 29359c8..4da2626 100644
--- a/src/pkg/sort/sort_test.go
+++ b/src/pkg/sort/sort_test.go
@@ -46,27 +46,27 @@ func TestSortStringSlice(t *testing.T) {
 	}
 }
 
-func TestSortInts(t *testing.T) {
+func TestInts(t *testing.T) {
 	data := ints
-	SortInts(data[0:])
+	Ints(data[0:])
 	if !IntsAreSorted(data[0:]) {
 		t.Errorf("sorted %v", ints)
 		t.Errorf("   got %v", data)
 	}
 }
 
-func TestSortFloat64s(t *testing.T) {
+func TestFloat64s(t *testing.T) {
 	data := float64s
-	SortFloat64s(data[0:])
+	Float64s(data[0:])
 	if !Float64sAreSorted(data[0:]) {
 		t.Errorf("sorted %v", float64s)
 		t.Errorf("   got %v", data)
 	}
 }
 
-func TestSortStrings(t *testing.T) {
+func TestStrings(t *testing.T) {
 	data := strings
-	SortStrings(data[0:])
+	Strings(data[0:])
 	if !StringsAreSorted(data[0:]) {
 		t.Errorf("sorted %v", strings)
 		t.Errorf("   got %v", data)
@@ -85,7 +85,7 @@ func TestSortLarge_Random(t *testing.T) {
 	if IntsAreSorted(data) {
 		t.Fatalf("terrible rand.rand")
 	}
-	SortInts(data)
+	Ints(data)
 	if !IntsAreSorted(data) {
 		t.Errorf("sort didn't sort - 1M ints")
 	}
@@ -99,7 +99,7 @@ func BenchmarkSortString1K(b *testing.B) {
 			data[i] = strconv.Itoa(i ^ 0x2cc)
 		}
 		b.StartTimer()
-		SortStrings(data)
+		Strings(data)
 		b.StopTimer()
 	}
 }
@@ -112,7 +112,7 @@ func BenchmarkSortInt1K(b *testing.B) {
 			data[i] = i ^ 0x2cc
 		}
 		b.StartTimer()
-		SortInts(data)
+		Ints(data)
 		b.StopTimer()
 	}
 }
@@ -125,7 +125,7 @@ func BenchmarkSortInt64K(b *testing.B) {
 			data[i] = i ^ 0xcccc
 		}
 		b.StartTimer()
-		SortInts(data)
+		Ints(data)
 		b.StopTimer()
 	}
 }
@@ -241,9 +241,9 @@ func TestBentleyMcIlroy(t *testing.T) {
 						for i := 0; i < n; i++ {
 							mdata[i] = data[i]
 						}
-						// SortInts is known to be correct
+						// Ints is known to be correct
 						// because mode Sort runs after mode _Copy.
-						SortInts(mdata)
+						Ints(mdata)
 					case _Dither:
 						for i := 0; i < n; i++ {
 							mdata[i] = data[i] + i%5
diff --git a/src/pkg/strconv/fp_test.go b/src/pkg/strconv/fp_test.go
index 34baeee..3096957 100644
--- a/src/pkg/strconv/fp_test.go
+++ b/src/pkg/strconv/fp_test.go
@@ -28,7 +28,7 @@ func pow2(i int) float64 {
 // Wrapper around strconv.Atof64.  Handles dddddp+ddd (binary exponent)
 // itself, passes the rest on to strconv.Atof64.
 func myatof64(s string) (f float64, ok bool) {
-	a := strings.Split(s, "p", 2)
+	a := strings.SplitN(s, "p", 2)
 	if len(a) == 2 {
 		n, err := strconv.Atoi64(a[0])
 		if err != nil {
@@ -72,7 +72,7 @@ func myatof64(s string) (f float64, ok bool) {
 // Wrapper around strconv.Atof32.  Handles dddddp+ddd (binary exponent)
 // itself, passes the rest on to strconv.Atof32.
 func myatof32(s string) (f float32, ok bool) {
-	a := strings.Split(s, "p", 2)
+	a := strings.SplitN(s, "p", 2)
 	if len(a) == 2 {
 		n, err := strconv.Atoi(a[0])
 		if err != nil {
@@ -116,7 +116,7 @@ func TestFp(t *testing.T) {
 		if len(line) == 0 || line[0] == '#' {
 			continue
 		}
-		a := strings.Split(line, " ", -1)
+		a := strings.Split(line, " ")
 		if len(a) != 4 {
 			t.Error("testfp.txt:", lineno, ": wrong field count")
 			continue
diff --git a/src/pkg/strings/strings.go b/src/pkg/strings/strings.go
index bfd0571..6afbc7d 100644
--- a/src/pkg/strings/strings.go
+++ b/src/pkg/strings/strings.go
@@ -198,26 +198,40 @@ func genSplit(s, sep string, sepSave, n int) []string {
 	return a[0 : na+1]
 }
 
-// Split slices s into substrings separated by sep and returns a slice of
+// SplitN slices s into substrings separated by sep and returns a slice of
 // the substrings between those separators.
-// If sep is empty, Split splits after each UTF-8 sequence.
+// If sep is empty, SplitN splits after each UTF-8 sequence.
 // The count determines the number of substrings to return:
 //   n > 0: at most n substrings; the last substring will be the unsplit remainder.
 //   n == 0: the result is nil (zero substrings)
 //   n < 0: all substrings
-func Split(s, sep string, n int) []string { return genSplit(s, sep, 0, n) }
+func SplitN(s, sep string, n int) []string { return genSplit(s, sep, 0, n) }
 
-// SplitAfter slices s into substrings after each instance of sep and
+// SplitAfterN slices s into substrings after each instance of sep and
 // returns a slice of those substrings.
-// If sep is empty, Split splits after each UTF-8 sequence.
+// If sep is empty, SplitAfterN splits after each UTF-8 sequence.
 // The count determines the number of substrings to return:
 //   n > 0: at most n substrings; the last substring will be the unsplit remainder.
 //   n == 0: the result is nil (zero substrings)
 //   n < 0: all substrings
-func SplitAfter(s, sep string, n int) []string {
+func SplitAfterN(s, sep string, n int) []string {
 	return genSplit(s, sep, len(sep), n)
 }
 
+// Split slices s into all substrings separated by sep and returns a slice of
+// the substrings between those separators.
+// If sep is empty, Split splits after each UTF-8 sequence.
+// It is equivalent to SplitN with a count of -1.
+func Split(s, sep string) []string { return genSplit(s, sep, 0, -1) }
+
+// SplitAfter slices s into all substrings after each instance of sep and
+// returns a slice of those substrings.
+// If sep is empty, SplitAfter splits after each UTF-8 sequence.
+// It is equivalent to SplitAfterN with a count of -1.
+func SplitAfter(s, sep string) []string {
+	return genSplit(s, sep, len(sep), -1)
+}
+
 // Fields splits the string s around each instance of one or more consecutive white space
 // characters, returning an array of substrings of s or an empty list if s contains only white space.
 func Fields(s string) []string {
diff --git a/src/pkg/strings/strings_test.go b/src/pkg/strings/strings_test.go
index a1a635d..c546173 100644
--- a/src/pkg/strings/strings_test.go
+++ b/src/pkg/strings/strings_test.go
@@ -186,7 +186,7 @@ var explodetests = []ExplodeTest{
 
 func TestExplode(t *testing.T) {
 	for _, tt := range explodetests {
-		a := Split(tt.s, "", tt.n)
+		a := SplitN(tt.s, "", tt.n)
 		if !eq(a, tt.a) {
 			t.Errorf("explode(%q, %d) = %v; want %v", tt.s, tt.n, a, tt.a)
 			continue
@@ -223,7 +223,7 @@ var splittests = []SplitTest{
 
 func TestSplit(t *testing.T) {
 	for _, tt := range splittests {
-		a := Split(tt.s, tt.sep, tt.n)
+		a := SplitN(tt.s, tt.sep, tt.n)
 		if !eq(a, tt.a) {
 			t.Errorf("Split(%q, %q, %d) = %v; want %v", tt.s, tt.sep, tt.n, a, tt.a)
 			continue
@@ -235,6 +235,12 @@ func TestSplit(t *testing.T) {
 		if s != tt.s {
 			t.Errorf("Join(Split(%q, %q, %d), %q) = %q", tt.s, tt.sep, tt.n, tt.sep, s)
 		}
+		if tt.n < 0 {
+			b := Split(tt.s, tt.sep)
+			if !reflect.DeepEqual(a, b) {
+				t.Errorf("Split disagrees with SplitN(%q, %q, %d) = %v; want %v", tt.s, tt.sep, tt.n, b, a)
+			}
+		}
 	}
 }
 
@@ -256,7 +262,7 @@ var splitaftertests = []SplitTest{
 
 func TestSplitAfter(t *testing.T) {
 	for _, tt := range splitaftertests {
-		a := SplitAfter(tt.s, tt.sep, tt.n)
+		a := SplitAfterN(tt.s, tt.sep, tt.n)
 		if !eq(a, tt.a) {
 			t.Errorf(`Split(%q, %q, %d) = %v; want %v`, tt.s, tt.sep, tt.n, a, tt.a)
 			continue
@@ -265,6 +271,12 @@ func TestSplitAfter(t *testing.T) {
 		if s != tt.s {
 			t.Errorf(`Join(Split(%q, %q, %d), %q) = %q`, tt.s, tt.sep, tt.n, tt.sep, s)
 		}
+		if tt.n < 0 {
+			b := SplitAfter(tt.s, tt.sep)
+			if !reflect.DeepEqual(a, b) {
+				t.Errorf("SplitAfter disagrees with SplitAfterN(%q, %q, %d) = %v; want %v", tt.s, tt.sep, tt.n, b, a)
+			}
+		}
 	}
 }
 
@@ -623,8 +635,8 @@ func equal(m string, s1, s2 string, t *testing.T) bool {
 	if s1 == s2 {
 		return true
 	}
-	e1 := Split(s1, "", -1)
-	e2 := Split(s2, "", -1)
+	e1 := Split(s1, "")
+	e2 := Split(s2, "")
 	for i, c1 := range e1 {
 		if i > len(e2) {
 			break
diff --git a/src/pkg/sync/mutex.go b/src/pkg/sync/mutex.go
index 13f03ca..2d46c89 100644
--- a/src/pkg/sync/mutex.go
+++ b/src/pkg/sync/mutex.go
@@ -17,8 +17,8 @@ import (
 // Mutexes can be created as part of other structures;
 // the zero value for a Mutex is an unlocked mutex.
 type Mutex struct {
-	key  int32
-	sema uint32
+	state int32
+	sema  uint32
 }
 
 // A Locker represents an object that can be locked and unlocked.
@@ -27,15 +27,41 @@ type Locker interface {
 	Unlock()
 }
 
+const (
+	mutexLocked = 1 << iota // mutex is locked
+	mutexWoken
+	mutexWaiterShift = iota
+)
+
 // Lock locks m.
 // If the lock is already in use, the calling goroutine
 // blocks until the mutex is available.
 func (m *Mutex) Lock() {
-	if atomic.AddInt32(&m.key, 1) == 1 {
-		// changed from 0 to 1; we hold lock
+	// Fast path: grab unlocked mutex.
+	if atomic.CompareAndSwapInt32(&m.state, 0, mutexLocked) {
 		return
 	}
-	runtime.Semacquire(&m.sema)
+
+	awoke := false
+	for {
+		old := m.state
+		new := old | mutexLocked
+		if old&mutexLocked != 0 {
+			new = old + 1<<mutexWaiterShift
+		}
+		if awoke {
+			// The goroutine has been woken from sleep,
+			// so we need to reset the flag in either case.
+			new &^= mutexWoken
+		}
+		if atomic.CompareAndSwapInt32(&m.state, old, new) {
+			if old&mutexLocked == 0 {
+				break
+			}
+			runtime.Semacquire(&m.sema)
+			awoke = true
+		}
+	}
 }
 
 // Unlock unlocks m.
@@ -45,14 +71,25 @@ func (m *Mutex) Lock() {
 // It is allowed for one goroutine to lock a Mutex and then
 // arrange for another goroutine to unlock it.
 func (m *Mutex) Unlock() {
-	switch v := atomic.AddInt32(&m.key, -1); {
-	case v == 0:
-		// changed from 1 to 0; no contention
-		return
-	case v == -1:
-		// changed from 0 to -1: wasn't locked
-		// (or there are 4 billion goroutines waiting)
+	// Fast path: drop lock bit.
+	new := atomic.AddInt32(&m.state, -mutexLocked)
+	if (new+mutexLocked)&mutexLocked == 0 {
 		panic("sync: unlock of unlocked mutex")
 	}
-	runtime.Semrelease(&m.sema)
+
+	old := new
+	for {
+		// If there are no waiters or a goroutine has already
+		// been woken or grabbed the lock, no need to wake anyone.
+		if old>>mutexWaiterShift == 0 || old&(mutexLocked|mutexWoken) != 0 {
+			return
+		}
+		// Grab the right to wake someone.
+		new = (old - 1<<mutexWaiterShift) | mutexWoken
+		if atomic.CompareAndSwapInt32(&m.state, old, new) {
+			runtime.Semrelease(&m.sema)
+			return
+		}
+		old = m.state
+	}
 }
diff --git a/src/pkg/sync/mutex_test.go b/src/pkg/sync/mutex_test.go
index 9bfdec3..d5ada85 100644
--- a/src/pkg/sync/mutex_test.go
+++ b/src/pkg/sync/mutex_test.go
@@ -9,6 +9,7 @@ package sync_test
 import (
 	"runtime"
 	. "sync"
+	"sync/atomic"
 	"testing"
 )
 
@@ -72,24 +73,6 @@ func TestMutex(t *testing.T) {
 	}
 }
 
-func BenchmarkUncontendedMutex(b *testing.B) {
-	m := new(Mutex)
-	HammerMutex(m, b.N, make(chan bool, 2))
-}
-
-func BenchmarkContendedMutex(b *testing.B) {
-	b.StopTimer()
-	m := new(Mutex)
-	c := make(chan bool)
-	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(2))
-	b.StartTimer()
-
-	go HammerMutex(m, b.N/2, c)
-	go HammerMutex(m, b.N/2, c)
-	<-c
-	<-c
-}
-
 func TestMutexPanic(t *testing.T) {
 	defer func() {
 		if recover() == nil {
@@ -102,3 +85,83 @@ func TestMutexPanic(t *testing.T) {
 	mu.Unlock()
 	mu.Unlock()
 }
+
+func BenchmarkMutexUncontended(b *testing.B) {
+	type PaddedMutex struct {
+		Mutex
+		pad [128]uint8
+	}
+	const CallsPerSched = 1000
+	procs := runtime.GOMAXPROCS(-1)
+	N := int32(b.N / CallsPerSched)
+	c := make(chan bool, procs)
+	for p := 0; p < procs; p++ {
+		go func() {
+			var mu PaddedMutex
+			for atomic.AddInt32(&N, -1) >= 0 {
+				runtime.Gosched()
+				for g := 0; g < CallsPerSched; g++ {
+					mu.Lock()
+					mu.Unlock()
+				}
+			}
+			c <- true
+		}()
+	}
+	for p := 0; p < procs; p++ {
+		<-c
+	}
+}
+
+func benchmarkMutex(b *testing.B, slack, work bool) {
+	const (
+		CallsPerSched  = 1000
+		LocalWork      = 100
+		GoroutineSlack = 10
+	)
+	procs := runtime.GOMAXPROCS(-1)
+	if slack {
+		procs *= GoroutineSlack
+	}
+	N := int32(b.N / CallsPerSched)
+	c := make(chan bool, procs)
+	var mu Mutex
+	for p := 0; p < procs; p++ {
+		go func() {
+			foo := 0
+			for atomic.AddInt32(&N, -1) >= 0 {
+				runtime.Gosched()
+				for g := 0; g < CallsPerSched; g++ {
+					mu.Lock()
+					mu.Unlock()
+					if work {
+						for i := 0; i < LocalWork; i++ {
+							foo *= 2
+							foo /= 2
+						}
+					}
+				}
+			}
+			c <- foo == 42
+		}()
+	}
+	for p := 0; p < procs; p++ {
+		<-c
+	}
+}
+
+func BenchmarkMutex(b *testing.B) {
+	benchmarkMutex(b, false, false)
+}
+
+func BenchmarkMutexSlack(b *testing.B) {
+	benchmarkMutex(b, true, false)
+}
+
+func BenchmarkMutexWork(b *testing.B) {
+	benchmarkMutex(b, false, true)
+}
+
+func BenchmarkMutexWorkSlack(b *testing.B) {
+	benchmarkMutex(b, true, true)
+}
diff --git a/src/pkg/sync/once.go b/src/pkg/sync/once.go
index b6f5f5a..447b71d 100644
--- a/src/pkg/sync/once.go
+++ b/src/pkg/sync/once.go
@@ -4,10 +4,14 @@
 
 package sync
 
+import (
+	"sync/atomic"
+)
+
 // Once is an object that will perform exactly one action.
 type Once struct {
 	m    Mutex
-	done bool
+	done int32
 }
 
 // Do calls the function f if and only if the method is being called for the
@@ -26,10 +30,14 @@ type Once struct {
 // Do to be called, it will deadlock.
 //
 func (o *Once) Do(f func()) {
+	if atomic.AddInt32(&o.done, 0) == 1 {
+		return
+	}
+	// Slow-path.
 	o.m.Lock()
 	defer o.m.Unlock()
-	if !o.done {
-		o.done = true
+	if o.done == 0 {
 		f()
+		atomic.CompareAndSwapInt32(&o.done, 0, 1)
 	}
 }
diff --git a/src/pkg/sync/once_test.go b/src/pkg/sync/once_test.go
index 155954a..157a366 100644
--- a/src/pkg/sync/once_test.go
+++ b/src/pkg/sync/once_test.go
@@ -6,6 +6,8 @@ package sync_test
 
 import (
 	. "sync"
+	"sync/atomic"
+	"runtime"
 	"testing"
 )
 
@@ -35,3 +37,26 @@ func TestOnce(t *testing.T) {
 		t.Errorf("once failed: %d is not 1", *o)
 	}
 }
+
+func BenchmarkOnce(b *testing.B) {
+	const CallsPerSched = 1000
+	procs := runtime.GOMAXPROCS(-1)
+	N := int32(b.N / CallsPerSched)
+	var once Once
+	f := func() {}
+	c := make(chan bool, procs)
+	for p := 0; p < procs; p++ {
+		go func() {
+			for atomic.AddInt32(&N, -1) >= 0 {
+				runtime.Gosched()
+				for g := 0; g < CallsPerSched; g++ {
+					once.Do(f)
+				}
+			}
+			c <- true
+		}()
+	}
+	for p := 0; p < procs; p++ {
+		<-c
+	}
+}
diff --git a/src/pkg/syscall/Makefile b/src/pkg/syscall/Makefile
index d7bd583..212b6f8 100644
--- a/src/pkg/syscall/Makefile
+++ b/src/pkg/syscall/Makefile
@@ -41,6 +41,8 @@ GOFILES_linux=\
 
 GOFILES_windows=\
 	exec_windows.go\
+	zerrors_windows.go\
+	ztypes_windows.go\
 
 GOFILES_plan9=\
 	exec_plan9.go\
diff --git a/src/pkg/syscall/asm_windows_386.s b/src/pkg/syscall/asm_windows_386.s
index 3d9f6fc..a7b9564 100644
--- a/src/pkg/syscall/asm_windows_386.s
+++ b/src/pkg/syscall/asm_windows_386.s
@@ -3,5 +3,5 @@
 // license that can be found in the LICENSE file.
 
 //
-// System calls for 386, Windows are implemented in ../runtime/windows/syscall.cgo
+// System calls for 386, Windows are implemented in ../runtime/windows/syscall.goc
 //
diff --git a/src/pkg/syscall/asm_windows_amd64.s b/src/pkg/syscall/asm_windows_amd64.s
new file mode 100644
index 0000000..8b38710
--- /dev/null
+++ b/src/pkg/syscall/asm_windows_amd64.s
@@ -0,0 +1,7 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//
+// System calls for amd64, Windows are implemented in ../runtime/windows/syscall.goc
+//
diff --git a/src/pkg/syscall/exec_unix.go b/src/pkg/syscall/exec_unix.go
index 4b3cfe4..46f05ef 100644
--- a/src/pkg/syscall/exec_unix.go
+++ b/src/pkg/syscall/exec_unix.go
@@ -146,6 +146,14 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
 		}
 	}
 
+	// Set process group
+	if sys.Setpgid {
+		_, _, err1 = RawSyscall(SYS_SETPGID, 0, 0, 0)
+		if err1 != 0 {
+			goto childerror
+		}
+	}
+
 	// Chroot
 	if chroot != nil {
 		_, _, err1 = RawSyscall(SYS_CHROOT, uintptr(unsafe.Pointer(chroot)), 0, 0)
@@ -241,6 +249,22 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
 		RawSyscall(SYS_CLOSE, uintptr(i), 0, 0)
 	}
 
+	// Detach fd 0 from tty
+	if sys.Noctty {
+		_, _, err1 = RawSyscall(SYS_IOCTL, 0, uintptr(TIOCNOTTY), 0)
+		if err1 != 0 {
+			goto childerror
+		}
+	}
+
+	// Make fd 0 the tty
+	if sys.Setctty {
+		_, _, err1 = RawSyscall(SYS_IOCTL, 0, uintptr(TIOCSCTTY), 0)
+		if err1 != 0 {
+			goto childerror
+		}
+	}
+
 	// Time to exec.
 	_, _, err1 = RawSyscall(SYS_EXECVE,
 		uintptr(unsafe.Pointer(argv0)),
@@ -260,12 +284,16 @@ childerror:
 	panic("unreached")
 }
 
+// Credential holds user and group identities to be assumed
+// by a child process started by StartProcess.
 type Credential struct {
 	Uid    uint32   // User ID.
 	Gid    uint32   // Group ID.
 	Groups []uint32 // Supplementary group IDs.
 }
 
+// ProcAttr holds attributes that will be applied to a new process started
+// by StartProcess.
 type ProcAttr struct {
 	Dir   string   // Current working directory.
 	Env   []string // Environment.
@@ -278,6 +306,9 @@ type SysProcAttr struct {
 	Credential *Credential // Credential.
 	Ptrace     bool        // Enable tracing.
 	Setsid     bool        // Create session.
+	Setpgid    bool        // Set process group ID to new pid (SYSV setpgrp)
+	Setctty    bool        // Set controlling terminal to fd 0
+	Noctty     bool        // Detach fd 0 from controlling terminal
 }
 
 var zeroProcAttr ProcAttr
diff --git a/src/pkg/syscall/exec_windows.go b/src/pkg/syscall/exec_windows.go
index 96a01e7..e8b540a 100644
--- a/src/pkg/syscall/exec_windows.go
+++ b/src/pkg/syscall/exec_windows.go
@@ -121,11 +121,11 @@ func createEnvBlock(envv []string) *uint16 {
 	return &utf16.Encode([]int(string(b)))[0]
 }
 
-func CloseOnExec(fd int) {
-	SetHandleInformation(int32(fd), HANDLE_FLAG_INHERIT, 0)
+func CloseOnExec(fd Handle) {
+	SetHandleInformation(Handle(fd), HANDLE_FLAG_INHERIT, 0)
 }
 
-func SetNonblock(fd int, nonblocking bool) (errno int) {
+func SetNonblock(fd Handle, nonblocking bool) (errno int) {
 	return 0
 }
 
@@ -220,7 +220,7 @@ func joinExeDirAndFName(dir, p string) (name string, err int) {
 type ProcAttr struct {
 	Dir   string
 	Env   []string
-	Files []int
+	Files []Handle
 	Sys   *SysProcAttr
 }
 
@@ -290,14 +290,14 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid, handle int,
 	defer ForkLock.Unlock()
 
 	p, _ := GetCurrentProcess()
-	fd := make([]int32, len(attr.Files))
+	fd := make([]Handle, len(attr.Files))
 	for i := range attr.Files {
 		if attr.Files[i] > 0 {
-			err := DuplicateHandle(p, int32(attr.Files[i]), p, &fd[i], 0, true, DUPLICATE_SAME_ACCESS)
+			err := DuplicateHandle(p, Handle(attr.Files[i]), p, &fd[i], 0, true, DUPLICATE_SAME_ACCESS)
 			if err != 0 {
 				return 0, 0, err
 			}
-			defer CloseHandle(int32(fd[i]))
+			defer CloseHandle(Handle(fd[i]))
 		}
 	}
 	si := new(StartupInfo)
@@ -317,7 +317,7 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid, handle int,
 	if err != 0 {
 		return 0, 0, err
 	}
-	defer CloseHandle(pi.Thread)
+	defer CloseHandle(Handle(pi.Thread))
 
 	return int(pi.ProcessId), int(pi.Process), 0
 }
diff --git a/src/pkg/syscall/mkall.sh b/src/pkg/syscall/mkall.sh
index f031a38..7d0c1ac 100755
--- a/src/pkg/syscall/mkall.sh
+++ b/src/pkg/syscall/mkall.sh
@@ -78,6 +78,7 @@ GOOSARCH="${GOOS}_${GOARCH}"
 # defaults
 mksyscall="./mksyscall.pl"
 mkerrors="./mkerrors.sh"
+zerrors="zerrors_$GOOSARCH.go"
 run="sh"
 
 case "$1" in
@@ -150,6 +151,14 @@ windows_386)
 	mksysnum=
 	mktypes=
 	mkerrors="./mkerrors_windows.sh -f -m32"
+	zerrors="zerrors_windows.go"
+	;;
+windows_amd64)
+	mksyscall="./mksyscall_windows.pl"
+	mksysnum=
+	mktypes=
+	mkerrors="./mkerrors_windows.sh -f -m32"
+	zerrors="zerrors_windows.go"
 	;;
 plan9_386)
 	mkerrors=
@@ -164,7 +173,7 @@ plan9_386)
 esac
 
 (
-	if [ -n "$mkerrors" ]; then echo "$mkerrors |gofmt >zerrors_$GOOSARCH.go"; fi
+	if [ -n "$mkerrors" ]; then echo "$mkerrors |gofmt >$zerrors"; fi
 	syscall_goos="syscall_$GOOS.go"
 	case "$GOOS" in
 	darwin | freebsd)
diff --git a/src/pkg/syscall/mkerrors.sh b/src/pkg/syscall/mkerrors.sh
index 2158360..c90cd1c 100755
--- a/src/pkg/syscall/mkerrors.sh
+++ b/src/pkg/syscall/mkerrors.sh
@@ -78,6 +78,7 @@ includes_FreeBSD='
 #include <net/if_types.h>
 #include <net/route.h>
 #include <netinet/in.h>
+#include <termios.h>
 #include <netinet/ip.h>
 #include <netinet/ip_mroute.h>
 '
diff --git a/src/pkg/syscall/syscall_windows.go b/src/pkg/syscall/syscall_windows.go
index 0e979ff..5b8143a 100644
--- a/src/pkg/syscall/syscall_windows.go
+++ b/src/pkg/syscall/syscall_windows.go
@@ -13,6 +13,10 @@ import (
 
 const OS = "windows"
 
+type Handle uintptr
+
+const InvalidHandle = ^Handle(0)
+
 /*
 
 small demo to detect version of windows you are running:
@@ -77,10 +81,10 @@ func Syscall(trap, nargs, a1, a2, a3 uintptr) (r1, r2, err uintptr)
 func Syscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
 func Syscall9(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, err uintptr)
 func Syscall12(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 uintptr) (r1, r2, err uintptr)
-func loadlibraryex(filename uintptr) (handle uint32)
-func getprocaddress(handle uint32, procname uintptr) (proc uintptr)
+func loadlibraryex(filename uintptr) (handle uintptr)
+func getprocaddress(handle uintptr, procname uintptr) (proc uintptr)
 
-func loadDll(fname string) uint32 {
+func loadDll(fname string) uintptr {
 	m := loadlibraryex(uintptr(unsafe.Pointer(StringBytePtr(fname))))
 	if m == 0 {
 		panic("syscall: could not LoadLibraryEx " + fname)
@@ -88,7 +92,7 @@ func loadDll(fname string) uint32 {
 	return m
 }
 
-func getSysProcAddr(m uint32, pname string) uintptr {
+func getSysProcAddr(m uintptr, pname string) uintptr {
 	p := getprocaddress(m, uintptr(unsafe.Pointer(StringBytePtr(pname))))
 	if p == 0 {
 		panic("syscall: could not GetProcAddress for " + pname)
@@ -96,6 +100,8 @@ func getSysProcAddr(m uint32, pname string) uintptr {
 	return p
 }
 
+func Getpagesize() int { return 4096 }
+
 // Converts a Go function to a function pointer conforming
 // to the stdcall calling convention.  This is useful when
 // interoperating with Windows code requiring callbacks.
@@ -110,22 +116,22 @@ func Sendfile(outfd int, infd int, offset *int64, count int) (written int, errno
 // windows api calls
 
 //sys	GetLastError() (lasterrno int)
-//sys	LoadLibrary(libname string) (handle uint32, errno int) = LoadLibraryW
-//sys	FreeLibrary(handle uint32) (errno int)
-//sys	GetProcAddress(module uint32, procname string) (proc uint32, errno int)
+//sys	LoadLibrary(libname string) (handle Handle, errno int) = LoadLibraryW
+//sys	FreeLibrary(handle Handle) (errno int)
+//sys	GetProcAddress(module Handle, procname string) (proc Handle, errno int)
 //sys	GetVersion() (ver uint32, errno int)
 //sys	FormatMessage(flags uint32, msgsrc uint32, msgid uint32, langid uint32, buf []uint16, args *byte) (n uint32, errno int) = FormatMessageW
 //sys	ExitProcess(exitcode uint32)
-//sys	CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile int32) (handle int32, errno int) [failretval==-1] = CreateFileW
-//sys	ReadFile(handle int32, buf []byte, done *uint32, overlapped *Overlapped) (errno int)
-//sys	WriteFile(handle int32, buf []byte, done *uint32, overlapped *Overlapped) (errno int)
-//sys	SetFilePointer(handle int32, lowoffset int32, highoffsetptr *int32, whence uint32) (newlowoffset uint32, errno int) [failretval==0xffffffff]
-//sys	CloseHandle(handle int32) (errno int)
-//sys	GetStdHandle(stdhandle int32) (handle int32, errno int) [failretval==-1]
-//sys	FindFirstFile(name *uint16, data *Win32finddata) (handle int32, errno int) [failretval==-1] = FindFirstFileW
-//sys	FindNextFile(handle int32, data *Win32finddata) (errno int) = FindNextFileW
-//sys	FindClose(handle int32) (errno int)
-//sys	GetFileInformationByHandle(handle int32, data *ByHandleFileInformation) (errno int)
+//sys	CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile int32) (handle Handle, errno int) [failretval==InvalidHandle] = CreateFileW
+//sys	ReadFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (errno int)
+//sys	WriteFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (errno int)
+//sys	SetFilePointer(handle Handle, lowoffset int32, highoffsetptr *int32, whence uint32) (newlowoffset uint32, errno int) [failretval==0xffffffff]
+//sys	CloseHandle(handle Handle) (errno int)
+//sys	GetStdHandle(stdhandle int) (handle Handle, errno int) [failretval==InvalidHandle]
+//sys	FindFirstFile(name *uint16, data *Win32finddata) (handle Handle, errno int) [failretval==InvalidHandle] = FindFirstFileW
+//sys	FindNextFile(handle Handle, data *Win32finddata) (errno int) = FindNextFileW
+//sys	FindClose(handle Handle) (errno int)
+//sys	GetFileInformationByHandle(handle Handle, data *ByHandleFileInformation) (errno int)
 //sys	GetCurrentDirectory(buflen uint32, buf *uint16) (n uint32, errno int) = GetCurrentDirectoryW
 //sys	SetCurrentDirectory(path *uint16) (errno int) = SetCurrentDirectoryW
 //sys	CreateDirectory(path *uint16, sa *SecurityAttributes) (errno int) = CreateDirectoryW
@@ -133,47 +139,47 @@ func Sendfile(outfd int, infd int, offset *int64, count int) (written int, errno
 //sys	DeleteFile(path *uint16) (errno int) = DeleteFileW
 //sys	MoveFile(from *uint16, to *uint16) (errno int) = MoveFileW
 //sys	GetComputerName(buf *uint16, n *uint32) (errno int) = GetComputerNameW
-//sys	SetEndOfFile(handle int32) (errno int)
+//sys	SetEndOfFile(handle Handle) (errno int)
 //sys	GetSystemTimeAsFileTime(time *Filetime)
 //sys	sleep(msec uint32) = Sleep
 //sys	GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, errno int) [failretval==0xffffffff]
-//sys	CreateIoCompletionPort(filehandle int32, cphandle int32, key uint32, threadcnt uint32) (handle int32, errno int)
-//sys	GetQueuedCompletionStatus(cphandle int32, qty *uint32, key *uint32, overlapped **Overlapped, timeout uint32) (errno int)
-//sys	CancelIo(s uint32) (errno int)
+//sys	CreateIoCompletionPort(filehandle Handle, cphandle Handle, key uint32, threadcnt uint32) (handle Handle, errno int)
+//sys	GetQueuedCompletionStatus(cphandle Handle, qty *uint32, key *uint32, overlapped **Overlapped, timeout uint32) (errno int)
+//sys	CancelIo(s Handle) (errno int)
 //sys	CreateProcess(appName *uint16, commandLine *uint16, procSecurity *SecurityAttributes, threadSecurity *SecurityAttributes, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation) (errno int) = CreateProcessW
-//sys	OpenProcess(da uint32, inheritHandle bool, pid uint32) (handle int32, errno int)
-//sys	TerminateProcess(handle int32, exitcode uint32) (errno int)
-//sys	GetExitCodeProcess(handle int32, exitcode *uint32) (errno int)
+//sys	OpenProcess(da uint32, inheritHandle bool, pid uint32) (handle Handle, errno int)
+//sys	TerminateProcess(handle Handle, exitcode uint32) (errno int)
+//sys	GetExitCodeProcess(handle Handle, exitcode *uint32) (errno int)
 //sys	GetStartupInfo(startupInfo *StartupInfo) (errno int) = GetStartupInfoW
-//sys	GetCurrentProcess() (pseudoHandle int32, errno int)
-//sys	DuplicateHandle(hSourceProcessHandle int32, hSourceHandle int32, hTargetProcessHandle int32, lpTargetHandle *int32, dwDesiredAccess uint32, bInheritHandle bool, dwOptions uint32) (errno int)
-//sys	WaitForSingleObject(handle int32, waitMilliseconds uint32) (event uint32, errno int) [failretval==0xffffffff]
+//sys	GetCurrentProcess() (pseudoHandle Handle, errno int)
+//sys	DuplicateHandle(hSourceProcessHandle Handle, hSourceHandle Handle, hTargetProcessHandle Handle, lpTargetHandle *Handle, dwDesiredAccess uint32, bInheritHandle bool, dwOptions uint32) (errno int)
+//sys	WaitForSingleObject(handle Handle, waitMilliseconds uint32) (event uint32, errno int) [failretval==0xffffffff]
 //sys	GetTempPath(buflen uint32, buf *uint16) (n uint32, errno int) = GetTempPathW
-//sys	CreatePipe(readhandle *uint32, writehandle *uint32, sa *SecurityAttributes, size uint32) (errno int)
-//sys	GetFileType(filehandle uint32) (n uint32, errno int)
-//sys	CryptAcquireContext(provhandle *uint32, container *uint16, provider *uint16, provtype uint32, flags uint32) (errno int) = advapi32.CryptAcquireContextW
-//sys	CryptReleaseContext(provhandle uint32, flags uint32) (errno int) = advapi32.CryptReleaseContext
-//sys	CryptGenRandom(provhandle uint32, buflen uint32, buf *byte) (errno int) = advapi32.CryptGenRandom
+//sys	CreatePipe(readhandle *Handle, writehandle *Handle, sa *SecurityAttributes, size uint32) (errno int)
+//sys	GetFileType(filehandle Handle) (n uint32, errno int)
+//sys	CryptAcquireContext(provhandle *Handle, container *uint16, provider *uint16, provtype uint32, flags uint32) (errno int) = advapi32.CryptAcquireContextW
+//sys	CryptReleaseContext(provhandle Handle, flags uint32) (errno int) = advapi32.CryptReleaseContext
+//sys	CryptGenRandom(provhandle Handle, buflen uint32, buf *byte) (errno int) = advapi32.CryptGenRandom
 //sys	GetEnvironmentStrings() (envs *uint16, errno int) [failretval==nil] = kernel32.GetEnvironmentStringsW
 //sys	FreeEnvironmentStrings(envs *uint16) (errno int) = kernel32.FreeEnvironmentStringsW
 //sys	GetEnvironmentVariable(name *uint16, buffer *uint16, size uint32) (n uint32, errno int) = kernel32.GetEnvironmentVariableW
 //sys	SetEnvironmentVariable(name *uint16, value *uint16) (errno int) = kernel32.SetEnvironmentVariableW
-//sys	SetFileTime(handle int32, ctime *Filetime, atime *Filetime, wtime *Filetime) (errno int)
+//sys	SetFileTime(handle Handle, ctime *Filetime, atime *Filetime, wtime *Filetime) (errno int)
 //sys	GetFileAttributes(name *uint16) (attrs uint32, errno int) [failretval==INVALID_FILE_ATTRIBUTES] = kernel32.GetFileAttributesW
 //sys	SetFileAttributes(name *uint16, attrs uint32) (errno int) = kernel32.SetFileAttributesW
 //sys	GetCommandLine() (cmd *uint16) = kernel32.GetCommandLineW
 //sys	CommandLineToArgv(cmd *uint16, argc *int32) (argv *[8192]*[8192]uint16, errno int) [failretval==nil] = shell32.CommandLineToArgvW
-//sys	LocalFree(hmem uint32) (handle uint32, errno int) [failretval!=0]
-//sys	SetHandleInformation(handle int32, mask uint32, flags uint32) (errno int)
-//sys	FlushFileBuffers(handle int32) (errno int)
+//sys	LocalFree(hmem Handle) (handle Handle, errno int) [failretval!=0]
+//sys	SetHandleInformation(handle Handle, mask uint32, flags uint32) (errno int)
+//sys	FlushFileBuffers(handle Handle) (errno int)
 //sys	GetFullPathName(path *uint16, buflen uint32, buf *uint16, fname **uint16) (n uint32, errno int) = kernel32.GetFullPathNameW
-//sys	CreateFileMapping(fhandle int32, sa *SecurityAttributes, prot uint32, maxSizeHigh uint32, maxSizeLow uint32, name *uint16) (handle int32, errno int) = kernel32.CreateFileMappingW
-//sys	MapViewOfFile(handle int32, access uint32, offsetHigh uint32, offsetLow uint32, length uintptr) (addr uintptr, errno int)
+//sys	CreateFileMapping(fhandle Handle, sa *SecurityAttributes, prot uint32, maxSizeHigh uint32, maxSizeLow uint32, name *uint16) (handle Handle, errno int) = kernel32.CreateFileMappingW
+//sys	MapViewOfFile(handle Handle, access uint32, offsetHigh uint32, offsetLow uint32, length uintptr) (addr uintptr, errno int)
 //sys	UnmapViewOfFile(addr uintptr) (errno int)
 //sys	FlushViewOfFile(addr uintptr, length uintptr) (errno int)
 //sys	VirtualLock(addr uintptr, length uintptr) (errno int)
 //sys	VirtualUnlock(addr uintptr, length uintptr) (errno int)
-//sys	TransmitFile(s int32, handle int32, bytesToWrite uint32, bytsPerSend uint32, overlapped *Overlapped, transmitFileBuf *TransmitFileBuffers, flags uint32) (errno int) = wsock32.TransmitFile
+//sys	TransmitFile(s Handle, handle Handle, bytesToWrite uint32, bytsPerSend uint32, overlapped *Overlapped, transmitFileBuf *TransmitFileBuffers, flags uint32) (errno int) = wsock32.TransmitFile
 
 // syscall interface implementation for other packages
 
@@ -205,9 +211,9 @@ func makeInheritSa() *SecurityAttributes {
 	return &sa
 }
 
-func Open(path string, mode int, perm uint32) (fd int, errno int) {
+func Open(path string, mode int, perm uint32) (fd Handle, errno int) {
 	if len(path) == 0 {
-		return -1, ERROR_FILE_NOT_FOUND
+		return InvalidHandle, ERROR_FILE_NOT_FOUND
 	}
 	var access uint32
 	switch mode & (O_RDONLY | O_WRONLY | O_RDWR) {
@@ -244,12 +250,12 @@ func Open(path string, mode int, perm uint32) (fd int, errno int) {
 		createmode = OPEN_EXISTING
 	}
 	h, e := CreateFile(StringToUTF16Ptr(path), access, sharemode, sa, createmode, FILE_ATTRIBUTE_NORMAL, 0)
-	return int(h), int(e)
+	return h, int(e)
 }
 
-func Read(fd int, p []byte) (n int, errno int) {
+func Read(fd Handle, p []byte) (n int, errno int) {
 	var done uint32
-	e := ReadFile(int32(fd), p, &done, nil)
+	e := ReadFile(fd, p, &done, nil)
 	if e != 0 {
 		if e == ERROR_BROKEN_PIPE {
 			// NOTE(brainman): work around ERROR_BROKEN_PIPE is returned on reading EOF from stdin
@@ -260,16 +266,16 @@ func Read(fd int, p []byte) (n int, errno int) {
 	return int(done), 0
 }
 
-func Write(fd int, p []byte) (n int, errno int) {
+func Write(fd Handle, p []byte) (n int, errno int) {
 	var done uint32
-	e := WriteFile(int32(fd), p, &done, nil)
+	e := WriteFile(fd, p, &done, nil)
 	if e != 0 {
 		return 0, e
 	}
 	return int(done), 0
 }
 
-func Seek(fd int, offset int64, whence int) (newoffset int64, errno int) {
+func Seek(fd Handle, offset int64, whence int) (newoffset int64, errno int) {
 	var w uint32
 	switch whence {
 	case 0:
@@ -282,19 +288,19 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, errno int) {
 	hi := int32(offset >> 32)
 	lo := int32(offset)
 	// use GetFileType to check pipe, pipe can't do seek
-	ft, _ := GetFileType(uint32(fd))
+	ft, _ := GetFileType(fd)
 	if ft == FILE_TYPE_PIPE {
 		return 0, EPIPE
 	}
-	rlo, e := SetFilePointer(int32(fd), lo, &hi, w)
+	rlo, e := SetFilePointer(fd, lo, &hi, w)
 	if e != 0 {
 		return 0, e
 	}
 	return int64(hi)<<32 + int64(rlo), 0
 }
 
-func Close(fd int) (errno int) {
-	return CloseHandle(int32(fd))
+func Close(fd Handle) (errno int) {
+	return CloseHandle(fd)
 }
 
 var (
@@ -303,9 +309,9 @@ var (
 	Stderr = getStdHandle(STD_ERROR_HANDLE)
 )
 
-func getStdHandle(h int32) (fd int) {
+func getStdHandle(h int) (fd Handle) {
 	r, _ := GetStdHandle(h)
-	return int(r)
+	return r
 }
 
 func Stat(path string, stat *Stat_t) (errno int) {
@@ -384,7 +390,7 @@ func ComputerName() (name string, errno int) {
 	return string(utf16.Decode(b[0:n])), 0
 }
 
-func Ftruncate(fd int, length int64) (errno int) {
+func Ftruncate(fd Handle, length int64) (errno int) {
 	curoffset, e := Seek(fd, 0, 1)
 	if e != 0 {
 		return e
@@ -394,7 +400,7 @@ func Ftruncate(fd int, length int64) (errno int) {
 	if e != 0 {
 		return e
 	}
-	e = SetEndOfFile(int32(fd))
+	e = SetEndOfFile(fd)
 	if e != 0 {
 		return e
 	}
@@ -413,17 +419,17 @@ func Sleep(nsec int64) (errno int) {
 	return 0
 }
 
-func Pipe(p []int) (errno int) {
+func Pipe(p []Handle) (errno int) {
 	if len(p) != 2 {
 		return EINVAL
 	}
-	var r, w uint32
+	var r, w Handle
 	e := CreatePipe(&r, &w, makeInheritSa(), 0)
 	if e != 0 {
 		return e
 	}
-	p[0] = int(r)
-	p[1] = int(w)
+	p[0] = r
+	p[1] = w
 	return 0
 }
 
@@ -437,14 +443,14 @@ func Utimes(path string, tv []Timeval) (errno int) {
 	if e != 0 {
 		return e
 	}
-	defer Close(int(h))
+	defer Close(h)
 	a := NsecToFiletime(tv[0].Nanoseconds())
 	w := NsecToFiletime(tv[1].Nanoseconds())
 	return SetFileTime(h, nil, &a, &w)
 }
 
-func Fsync(fd int) (errno int) {
-	return FlushFileBuffers(int32(fd))
+func Fsync(fd Handle) (errno int) {
+	return FlushFileBuffers(fd)
 }
 
 func Chmod(path string, mode uint32) (errno int) {
@@ -468,22 +474,22 @@ func Chmod(path string, mode uint32) (errno int) {
 
 //sys	WSAStartup(verreq uint32, data *WSAData) (sockerrno int) = wsock32.WSAStartup
 //sys	WSACleanup() (errno int) [failretval==-1] = wsock32.WSACleanup
-//sys	WSAIoctl(s int32, iocc uint32, inbuf *byte, cbif uint32, outbuf *byte, cbob uint32, cbbr *uint32, overlapped *Overlapped, completionRoutine uintptr) (errno int) [failretval==-1] = ws2_32.WSAIoctl
-//sys	socket(af int32, typ int32, protocol int32) (handle int32, errno int) [failretval==-1] = wsock32.socket
-//sys	setsockopt(s int32, level int32, optname int32, optval *byte, optlen int32) (errno int) [failretval==-1] = wsock32.setsockopt
-//sys	bind(s int32, name uintptr, namelen int32) (errno int) [failretval==-1] = wsock32.bind
-//sys	connect(s int32, name uintptr, namelen int32) (errno int) [failretval==-1] = wsock32.connect
-//sys	getsockname(s int32, rsa *RawSockaddrAny, addrlen *int32) (errno int) [failretval==-1] = wsock32.getsockname
-//sys	getpeername(s int32, rsa *RawSockaddrAny, addrlen *int32) (errno int) [failretval==-1] = wsock32.getpeername
-//sys	listen(s int32, backlog int32) (errno int) [failretval==-1] = wsock32.listen
-//sys	shutdown(s int32, how int32) (errno int) [failretval==-1] = wsock32.shutdown
-//sys	Closesocket(s int32) (errno int) [failretval==-1] = wsock32.closesocket
-//sys	AcceptEx(ls uint32, as uint32, buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, recvd *uint32, overlapped *Overlapped) (errno int) = wsock32.AcceptEx
+//sys	WSAIoctl(s Handle, iocc uint32, inbuf *byte, cbif uint32, outbuf *byte, cbob uint32, cbbr *uint32, overlapped *Overlapped, completionRoutine uintptr) (errno int) [failretval==-1] = ws2_32.WSAIoctl
+//sys	socket(af int32, typ int32, protocol int32) (handle Handle, errno int) [failretval==InvalidHandle] = wsock32.socket
+//sys	setsockopt(s Handle, level int32, optname int32, optval *byte, optlen int32) (errno int) [failretval==-1] = wsock32.setsockopt
+//sys	bind(s Handle, name uintptr, namelen int32) (errno int) [failretval==-1] = wsock32.bind
+//sys	connect(s Handle, name uintptr, namelen int32) (errno int) [failretval==-1] = wsock32.connect
+//sys	getsockname(s Handle, rsa *RawSockaddrAny, addrlen *int32) (errno int) [failretval==-1] = wsock32.getsockname
+//sys	getpeername(s Handle, rsa *RawSockaddrAny, addrlen *int32) (errno int) [failretval==-1] = wsock32.getpeername
+//sys	listen(s Handle, backlog int32) (errno int) [failretval==-1] = wsock32.listen
+//sys	shutdown(s Handle, how int32) (errno int) [failretval==-1] = wsock32.shutdown
+//sys	Closesocket(s Handle) (errno int) [failretval==-1] = wsock32.closesocket
+//sys	AcceptEx(ls Handle, as Handle, buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, recvd *uint32, overlapped *Overlapped) (errno int) = wsock32.AcceptEx
 //sys	GetAcceptExSockaddrs(buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, lrsa **RawSockaddrAny, lrsalen *int32, rrsa **RawSockaddrAny, rrsalen *int32) = wsock32.GetAcceptExSockaddrs
-//sys	WSARecv(s uint32, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, overlapped *Overlapped, croutine *byte) (errno int) [failretval==-1] = ws2_32.WSARecv
-//sys	WSASend(s uint32, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, overlapped *Overlapped, croutine *byte) (errno int) [failretval==-1] = ws2_32.WSASend
-//sys	WSARecvFrom(s uint32, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32,  from *RawSockaddrAny, fromlen *int32, overlapped *Overlapped, croutine *byte) (errno int) [failretval==-1] = ws2_32.WSARecvFrom
-//sys	WSASendTo(s uint32, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to *RawSockaddrAny, tolen int32,  overlapped *Overlapped, croutine *byte) (errno int) [failretval==-1] = ws2_32.WSASendTo
+//sys	WSARecv(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, overlapped *Overlapped, croutine *byte) (errno int) [failretval==-1] = ws2_32.WSARecv
+//sys	WSASend(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, overlapped *Overlapped, croutine *byte) (errno int) [failretval==-1] = ws2_32.WSASend
+//sys	WSARecvFrom(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32,  from *RawSockaddrAny, fromlen *int32, overlapped *Overlapped, croutine *byte) (errno int) [failretval==-1] = ws2_32.WSARecvFrom
+//sys	WSASendTo(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to *RawSockaddrAny, tolen int32,  overlapped *Overlapped, croutine *byte) (errno int) [failretval==-1] = ws2_32.WSASendTo
 //sys	GetHostByName(name string) (h *Hostent, errno int) [failretval==nil] = ws2_32.gethostbyname
 //sys	GetServByName(name string, proto string) (s *Servent, errno int) [failretval==nil] = ws2_32.getservbyname
 //sys	Ntohs(netshort uint16) (u uint16) = ws2_32.ntohs
@@ -578,62 +584,62 @@ func (rsa *RawSockaddrAny) Sockaddr() (Sockaddr, int) {
 	return nil, EAFNOSUPPORT
 }
 
-func Socket(domain, typ, proto int) (fd, errno int) {
+func Socket(domain, typ, proto int) (fd Handle, errno int) {
 	if domain == AF_INET6 && SocketDisableIPv6 {
-		return -1, EAFNOSUPPORT
+		return InvalidHandle, EAFNOSUPPORT
 	}
 	h, e := socket(int32(domain), int32(typ), int32(proto))
-	return int(h), int(e)
+	return h, int(e)
 }
 
-func SetsockoptInt(fd, level, opt int, value int) (errno int) {
+func SetsockoptInt(fd Handle, level, opt int, value int) (errno int) {
 	v := int32(value)
-	return int(setsockopt(int32(fd), int32(level), int32(opt), (*byte)(unsafe.Pointer(&v)), int32(unsafe.Sizeof(v))))
+	return int(setsockopt(fd, int32(level), int32(opt), (*byte)(unsafe.Pointer(&v)), int32(unsafe.Sizeof(v))))
 }
 
-func Bind(fd int, sa Sockaddr) (errno int) {
+func Bind(fd Handle, sa Sockaddr) (errno int) {
 	ptr, n, err := sa.sockaddr()
 	if err != 0 {
 		return err
 	}
-	return bind(int32(fd), ptr, n)
+	return bind(fd, ptr, n)
 }
 
-func Connect(fd int, sa Sockaddr) (errno int) {
+func Connect(fd Handle, sa Sockaddr) (errno int) {
 	ptr, n, err := sa.sockaddr()
 	if err != 0 {
 		return err
 	}
-	return connect(int32(fd), ptr, n)
+	return connect(fd, ptr, n)
 }
 
-func Getsockname(fd int) (sa Sockaddr, errno int) {
+func Getsockname(fd Handle) (sa Sockaddr, errno int) {
 	var rsa RawSockaddrAny
 	l := int32(unsafe.Sizeof(rsa))
-	if errno = getsockname(int32(fd), &rsa, &l); errno != 0 {
+	if errno = getsockname(fd, &rsa, &l); errno != 0 {
 		return
 	}
 	return rsa.Sockaddr()
 }
 
-func Getpeername(fd int) (sa Sockaddr, errno int) {
+func Getpeername(fd Handle) (sa Sockaddr, errno int) {
 	var rsa RawSockaddrAny
 	l := int32(unsafe.Sizeof(rsa))
-	if errno = getpeername(int32(fd), &rsa, &l); errno != 0 {
+	if errno = getpeername(fd, &rsa, &l); errno != 0 {
 		return
 	}
 	return rsa.Sockaddr()
 }
 
-func Listen(s int, n int) (errno int) {
-	return int(listen(int32(s), int32(n)))
+func Listen(s Handle, n int) (errno int) {
+	return int(listen(s, int32(n)))
 }
 
-func Shutdown(fd, how int) (errno int) {
-	return int(shutdown(int32(fd), int32(how)))
+func Shutdown(fd Handle, how int) (errno int) {
+	return int(shutdown(fd, int32(how)))
 }
 
-func WSASendto(s uint32, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to Sockaddr, overlapped *Overlapped, croutine *byte) (errno int) {
+func WSASendto(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to Sockaddr, overlapped *Overlapped, croutine *byte) (errno int) {
 	rsa, l, err := to.sockaddr()
 	if err != 0 {
 		return err
@@ -670,10 +676,12 @@ func (w WaitStatus) TrapCause() int { return -1 }
 
 // TODO(brainman): fix all needed for net
 
-func Accept(fd int) (nfd int, sa Sockaddr, errno int)                        { return 0, nil, EWINDOWS }
-func Recvfrom(fd int, p []byte, flags int) (n int, from Sockaddr, errno int) { return 0, nil, EWINDOWS }
-func Sendto(fd int, p []byte, flags int, to Sockaddr) (errno int)            { return EWINDOWS }
-func SetsockoptTimeval(fd, level, opt int, tv *Timeval) (errno int)          { return EWINDOWS }
+func Accept(fd Handle) (nfd Handle, sa Sockaddr, errno int) { return 0, nil, EWINDOWS }
+func Recvfrom(fd Handle, p []byte, flags int) (n int, from Sockaddr, errno int) {
+	return 0, nil, EWINDOWS
+}
+func Sendto(fd Handle, p []byte, flags int, to Sockaddr) (errno int)       { return EWINDOWS }
+func SetsockoptTimeval(fd Handle, level, opt int, tv *Timeval) (errno int) { return EWINDOWS }
 
 type Linger struct {
 	Onoff  int32
@@ -695,25 +703,25 @@ type IPv6Mreq struct {
 	Interface uint32
 }
 
-func SetsockoptLinger(fd, level, opt int, l *Linger) (errno int)        { return EWINDOWS }
-func SetsockoptIPMreq(fd, level, opt int, mreq *IPMreq) (errno int)     { return EWINDOWS }
-func SetsockoptIPv6Mreq(fd, level, opt int, mreq *IPv6Mreq) (errno int) { return EWINDOWS }
-func BindToDevice(fd int, device string) (errno int)                    { return EWINDOWS }
+func SetsockoptLinger(fd Handle, level, opt int, l *Linger) (errno int)        { return EWINDOWS }
+func SetsockoptIPMreq(fd Handle, level, opt int, mreq *IPMreq) (errno int)     { return EWINDOWS }
+func SetsockoptIPv6Mreq(fd Handle, level, opt int, mreq *IPv6Mreq) (errno int) { return EWINDOWS }
+func BindToDevice(fd Handle, device string) (errno int)                        { return EWINDOWS }
 
 // TODO(brainman): fix all needed for os
 
 func Getpid() (pid int)   { return -1 }
 func Getppid() (ppid int) { return -1 }
 
-func Fchdir(fd int) (errno int)                           { return EWINDOWS }
+func Fchdir(fd Handle) (errno int)                        { return EWINDOWS }
 func Link(oldpath, newpath string) (errno int)            { return EWINDOWS }
 func Symlink(path, link string) (errno int)               { return EWINDOWS }
 func Readlink(path string, buf []byte) (n int, errno int) { return 0, EWINDOWS }
 
-func Fchmod(fd int, mode uint32) (errno int)           { return EWINDOWS }
+func Fchmod(fd Handle, mode uint32) (errno int)        { return EWINDOWS }
 func Chown(path string, uid int, gid int) (errno int)  { return EWINDOWS }
 func Lchown(path string, uid int, gid int) (errno int) { return EWINDOWS }
-func Fchown(fd int, uid int, gid int) (errno int)      { return EWINDOWS }
+func Fchown(fd Handle, uid int, gid int) (errno int)   { return EWINDOWS }
 
 func Getuid() (uid int)                  { return -1 }
 func Geteuid() (euid int)                { return -1 }
@@ -723,11 +731,11 @@ func Getgroups() (gids []int, errno int) { return nil, EWINDOWS }
 
 // TODO(brainman): fix all this meaningless code, it is here to compile exec.go
 
-func read(fd int, buf *byte, nbuf int) (n int, errno int) {
+func read(fd Handle, buf *byte, nbuf int) (n int, errno int) {
 	return 0, EWINDOWS
 }
 
-func fcntl(fd, cmd, arg int) (val int, errno int) {
+func fcntl(fd Handle, cmd, arg int) (val int, errno int) {
 	return 0, EWINDOWS
 }
 
diff --git a/src/pkg/syscall/syscall_windows_386.go b/src/pkg/syscall/syscall_windows_386.go
index 1ce025b..61d2d8c 100644
--- a/src/pkg/syscall/syscall_windows_386.go
+++ b/src/pkg/syscall/syscall_windows_386.go
@@ -3,5 +3,3 @@
 // license that can be found in the LICENSE file.
 
 package syscall
-
-func Getpagesize() int { return 4096 }
diff --git a/src/pkg/syscall/syscall_windows_amd64.go b/src/pkg/syscall/syscall_windows_amd64.go
new file mode 100644
index 0000000..61d2d8c
--- /dev/null
+++ b/src/pkg/syscall/syscall_windows_amd64.go
@@ -0,0 +1,5 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
diff --git a/src/pkg/syscall/zerrors_darwin_386.go b/src/pkg/syscall/zerrors_darwin_386.go
index 964e588..33cc7fd 100644
--- a/src/pkg/syscall/zerrors_darwin_386.go
+++ b/src/pkg/syscall/zerrors_darwin_386.go
@@ -165,6 +165,13 @@ const (
 	EBUSY                       = 0x10
 	ECANCELED                   = 0x59
 	ECHILD                      = 0xa
+	ECHO                        = 0x8
+	ECHOCTL                     = 0x40
+	ECHOE                       = 0x2
+	ECHOK                       = 0x4
+	ECHOKE                      = 0x1
+	ECHONL                      = 0x10
+	ECHOPRT                     = 0x20
 	ECONNABORTED                = 0x35
 	ECONNREFUSED                = 0x3d
 	ECONNRESET                  = 0x36
@@ -282,6 +289,9 @@ const (
 	EV_TRIGGER                  = 0x100
 	EWOULDBLOCK                 = 0x23
 	EXDEV                       = 0x12
+	EXTA                        = 0x4b00
+	EXTB                        = 0x9600
+	EXTPROC                     = 0x800
 	FD_CLOEXEC                  = 0x1
 	FD_SETSIZE                  = 0x400
 	F_ADDFILESIGS               = 0x3d
@@ -996,6 +1006,75 @@ const (
 	TCP_NODELAY                 = 0x1
 	TCP_NOOPT                   = 0x8
 	TCP_NOPUSH                  = 0x4
+	TIOCCBRK                    = 0x2000747a
+	TIOCCDTR                    = 0x20007478
+	TIOCCONS                    = 0x80047462
+	TIOCDCDTIMESTAMP            = 0x40087458
+	TIOCDRAIN                   = 0x2000745e
+	TIOCDSIMICROCODE            = 0x20007455
+	TIOCEXCL                    = 0x2000740d
+	TIOCEXT                     = 0x80047460
+	TIOCFLUSH                   = 0x80047410
+	TIOCGDRAINWAIT              = 0x40047456
+	TIOCGETA                    = 0x402c7413
+	TIOCGETD                    = 0x4004741a
+	TIOCGPGRP                   = 0x40047477
+	TIOCGWINSZ                  = 0x40087468
+	TIOCIXOFF                   = 0x20007480
+	TIOCIXON                    = 0x20007481
+	TIOCMBIC                    = 0x8004746b
+	TIOCMBIS                    = 0x8004746c
+	TIOCMGDTRWAIT               = 0x4004745a
+	TIOCMGET                    = 0x4004746a
+	TIOCMODG                    = 0x40047403
+	TIOCMODS                    = 0x80047404
+	TIOCMSDTRWAIT               = 0x8004745b
+	TIOCMSET                    = 0x8004746d
+	TIOCM_CAR                   = 0x40
+	TIOCM_CD                    = 0x40
+	TIOCM_CTS                   = 0x20
+	TIOCM_DSR                   = 0x100
+	TIOCM_DTR                   = 0x2
+	TIOCM_LE                    = 0x1
+	TIOCM_RI                    = 0x80
+	TIOCM_RNG                   = 0x80
+	TIOCM_RTS                   = 0x4
+	TIOCM_SR                    = 0x10
+	TIOCM_ST                    = 0x8
+	TIOCNOTTY                   = 0x20007471
+	TIOCNXCL                    = 0x2000740e
+	TIOCOUTQ                    = 0x40047473
+	TIOCPKT                     = 0x80047470
+	TIOCPKT_DATA                = 0
+	TIOCPKT_DOSTOP              = 0x20
+	TIOCPKT_FLUSHREAD           = 0x1
+	TIOCPKT_FLUSHWRITE          = 0x2
+	TIOCPKT_IOCTL               = 0x40
+	TIOCPKT_NOSTOP              = 0x10
+	TIOCPKT_START               = 0x8
+	TIOCPKT_STOP                = 0x4
+	TIOCPTYGNAME                = 0x40807453
+	TIOCPTYGRANT                = 0x20007454
+	TIOCPTYUNLK                 = 0x20007452
+	TIOCREMOTE                  = 0x80047469
+	TIOCSBRK                    = 0x2000747b
+	TIOCSCONS                   = 0x20007463
+	TIOCSCTTY                   = 0x20007461
+	TIOCSDRAINWAIT              = 0x80047457
+	TIOCSDTR                    = 0x20007479
+	TIOCSETA                    = 0x802c7414
+	TIOCSETAF                   = 0x802c7416
+	TIOCSETAW                   = 0x802c7415
+	TIOCSETD                    = 0x8004741b
+	TIOCSIG                     = 0x2000745f
+	TIOCSPGRP                   = 0x80047476
+	TIOCSTART                   = 0x2000746e
+	TIOCSTAT                    = 0x20007465
+	TIOCSTI                     = 0x80017472
+	TIOCSTOP                    = 0x2000746f
+	TIOCSWINSZ                  = 0x80087467
+	TIOCTIMESTAMP               = 0x40087459
+	TIOCUCNTL                   = 0x80047466
 	WCONTINUED                  = 0x10
 	WCOREFLAG                   = 0x80
 	WEXITED                     = 0x4
diff --git a/src/pkg/syscall/zerrors_darwin_amd64.go b/src/pkg/syscall/zerrors_darwin_amd64.go
index adf0399..571ce90 100644
--- a/src/pkg/syscall/zerrors_darwin_amd64.go
+++ b/src/pkg/syscall/zerrors_darwin_amd64.go
@@ -165,6 +165,13 @@ const (
 	EBUSY                       = 0x10
 	ECANCELED                   = 0x59
 	ECHILD                      = 0xa
+	ECHO                        = 0x8
+	ECHOCTL                     = 0x40
+	ECHOE                       = 0x2
+	ECHOK                       = 0x4
+	ECHOKE                      = 0x1
+	ECHONL                      = 0x10
+	ECHOPRT                     = 0x20
 	ECONNABORTED                = 0x35
 	ECONNREFUSED                = 0x3d
 	ECONNRESET                  = 0x36
@@ -282,6 +289,9 @@ const (
 	EV_TRIGGER                  = 0x100
 	EWOULDBLOCK                 = 0x23
 	EXDEV                       = 0x12
+	EXTA                        = 0x4b00
+	EXTB                        = 0x9600
+	EXTPROC                     = 0x800
 	FD_CLOEXEC                  = 0x1
 	FD_SETSIZE                  = 0x400
 	F_ADDFILESIGS               = 0x3d
@@ -996,6 +1006,75 @@ const (
 	TCP_NODELAY                 = 0x1
 	TCP_NOOPT                   = 0x8
 	TCP_NOPUSH                  = 0x4
+	TIOCCBRK                    = 0x2000747a
+	TIOCCDTR                    = 0x20007478
+	TIOCCONS                    = 0x80047462
+	TIOCDCDTIMESTAMP            = 0x40107458
+	TIOCDRAIN                   = 0x2000745e
+	TIOCDSIMICROCODE            = 0x20007455
+	TIOCEXCL                    = 0x2000740d
+	TIOCEXT                     = 0x80047460
+	TIOCFLUSH                   = 0x80047410
+	TIOCGDRAINWAIT              = 0x40047456
+	TIOCGETA                    = 0x40487413
+	TIOCGETD                    = 0x4004741a
+	TIOCGPGRP                   = 0x40047477
+	TIOCGWINSZ                  = 0x40087468
+	TIOCIXOFF                   = 0x20007480
+	TIOCIXON                    = 0x20007481
+	TIOCMBIC                    = 0x8004746b
+	TIOCMBIS                    = 0x8004746c
+	TIOCMGDTRWAIT               = 0x4004745a
+	TIOCMGET                    = 0x4004746a
+	TIOCMODG                    = 0x40047403
+	TIOCMODS                    = 0x80047404
+	TIOCMSDTRWAIT               = 0x8004745b
+	TIOCMSET                    = 0x8004746d
+	TIOCM_CAR                   = 0x40
+	TIOCM_CD                    = 0x40
+	TIOCM_CTS                   = 0x20
+	TIOCM_DSR                   = 0x100
+	TIOCM_DTR                   = 0x2
+	TIOCM_LE                    = 0x1
+	TIOCM_RI                    = 0x80
+	TIOCM_RNG                   = 0x80
+	TIOCM_RTS                   = 0x4
+	TIOCM_SR                    = 0x10
+	TIOCM_ST                    = 0x8
+	TIOCNOTTY                   = 0x20007471
+	TIOCNXCL                    = 0x2000740e
+	TIOCOUTQ                    = 0x40047473
+	TIOCPKT                     = 0x80047470
+	TIOCPKT_DATA                = 0
+	TIOCPKT_DOSTOP              = 0x20
+	TIOCPKT_FLUSHREAD           = 0x1
+	TIOCPKT_FLUSHWRITE          = 0x2
+	TIOCPKT_IOCTL               = 0x40
+	TIOCPKT_NOSTOP              = 0x10
+	TIOCPKT_START               = 0x8
+	TIOCPKT_STOP                = 0x4
+	TIOCPTYGNAME                = 0x40807453
+	TIOCPTYGRANT                = 0x20007454
+	TIOCPTYUNLK                 = 0x20007452
+	TIOCREMOTE                  = 0x80047469
+	TIOCSBRK                    = 0x2000747b
+	TIOCSCONS                   = 0x20007463
+	TIOCSCTTY                   = 0x20007461
+	TIOCSDRAINWAIT              = 0x80047457
+	TIOCSDTR                    = 0x20007479
+	TIOCSETA                    = 0x80487414
+	TIOCSETAF                   = 0x80487416
+	TIOCSETAW                   = 0x80487415
+	TIOCSETD                    = 0x8004741b
+	TIOCSIG                     = 0x2000745f
+	TIOCSPGRP                   = 0x80047476
+	TIOCSTART                   = 0x2000746e
+	TIOCSTAT                    = 0x20007465
+	TIOCSTI                     = 0x80017472
+	TIOCSTOP                    = 0x2000746f
+	TIOCSWINSZ                  = 0x80087467
+	TIOCTIMESTAMP               = 0x40107459
+	TIOCUCNTL                   = 0x80047466
 	WCONTINUED                  = 0x10
 	WCOREFLAG                   = 0x80
 	WEXITED                     = 0x4
diff --git a/src/pkg/syscall/zerrors_freebsd_386.go b/src/pkg/syscall/zerrors_freebsd_386.go
index 52e4248..d045cab 100644
--- a/src/pkg/syscall/zerrors_freebsd_386.go
+++ b/src/pkg/syscall/zerrors_freebsd_386.go
@@ -327,6 +327,13 @@ const (
 	EBUSY                             = 0x10
 	ECANCELED                         = 0x55
 	ECHILD                            = 0xa
+	ECHO                              = 0x8
+	ECHOCTL                           = 0x40
+	ECHOE                             = 0x2
+	ECHOK                             = 0x4
+	ECHOKE                            = 0x1
+	ECHONL                            = 0x10
+	ECHOPRT                           = 0x20
 	ECONNABORTED                      = 0x35
 	ECONNREFUSED                      = 0x3d
 	ECONNRESET                        = 0x36
@@ -432,6 +439,9 @@ const (
 	EV_SYSFLAGS                       = 0xf000
 	EWOULDBLOCK                       = 0x23
 	EXDEV                             = 0x12
+	EXTA                              = 0x4b00
+	EXTB                              = 0x9600
+	EXTPROC                           = 0x800
 	FD_CLOEXEC                        = 0x1
 	FD_SETSIZE                        = 0x400
 	F_CANCEL                          = 0x5
@@ -1224,6 +1234,68 @@ const (
 	TCP_NODELAY                       = 0x1
 	TCP_NOOPT                         = 0x8
 	TCP_NOPUSH                        = 0x4
+	TIOCCBRK                          = 0x2000747a
+	TIOCCDTR                          = 0x20007478
+	TIOCCONS                          = 0x80047462
+	TIOCDRAIN                         = 0x2000745e
+	TIOCEXCL                          = 0x2000740d
+	TIOCEXT                           = 0x80047460
+	TIOCFLUSH                         = 0x80047410
+	TIOCGDRAINWAIT                    = 0x40047456
+	TIOCGETA                          = 0x402c7413
+	TIOCGETD                          = 0x4004741a
+	TIOCGPGRP                         = 0x40047477
+	TIOCGPTN                          = 0x4004740f
+	TIOCGSID                          = 0x40047463
+	TIOCGWINSZ                        = 0x40087468
+	TIOCMBIC                          = 0x8004746b
+	TIOCMBIS                          = 0x8004746c
+	TIOCMGDTRWAIT                     = 0x4004745a
+	TIOCMGET                          = 0x4004746a
+	TIOCMSDTRWAIT                     = 0x8004745b
+	TIOCMSET                          = 0x8004746d
+	TIOCM_CAR                         = 0x40
+	TIOCM_CD                          = 0x40
+	TIOCM_CTS                         = 0x20
+	TIOCM_DCD                         = 0x40
+	TIOCM_DSR                         = 0x100
+	TIOCM_DTR                         = 0x2
+	TIOCM_LE                          = 0x1
+	TIOCM_RI                          = 0x80
+	TIOCM_RNG                         = 0x80
+	TIOCM_RTS                         = 0x4
+	TIOCM_SR                          = 0x10
+	TIOCM_ST                          = 0x8
+	TIOCNOTTY                         = 0x20007471
+	TIOCNXCL                          = 0x2000740e
+	TIOCOUTQ                          = 0x40047473
+	TIOCPKT                           = 0x80047470
+	TIOCPKT_DATA                      = 0
+	TIOCPKT_DOSTOP                    = 0x20
+	TIOCPKT_FLUSHREAD                 = 0x1
+	TIOCPKT_FLUSHWRITE                = 0x2
+	TIOCPKT_IOCTL                     = 0x40
+	TIOCPKT_NOSTOP                    = 0x10
+	TIOCPKT_START                     = 0x8
+	TIOCPKT_STOP                      = 0x4
+	TIOCPTMASTER                      = 0x2000741c
+	TIOCSBRK                          = 0x2000747b
+	TIOCSCTTY                         = 0x20007461
+	TIOCSDRAINWAIT                    = 0x80047457
+	TIOCSDTR                          = 0x20007479
+	TIOCSETA                          = 0x802c7414
+	TIOCSETAF                         = 0x802c7416
+	TIOCSETAW                         = 0x802c7415
+	TIOCSETD                          = 0x8004741b
+	TIOCSIG                           = 0x2004745f
+	TIOCSPGRP                         = 0x80047476
+	TIOCSTART                         = 0x2000746e
+	TIOCSTAT                          = 0x20007465
+	TIOCSTI                           = 0x80017472
+	TIOCSTOP                          = 0x2000746f
+	TIOCSWINSZ                        = 0x80087467
+	TIOCTIMESTAMP                     = 0x40087459
+	TIOCUCNTL                         = 0x80047466
 	WCONTINUED                        = 0x4
 	WCOREFLAG                         = 0x80
 	WLINUXCLONE                       = 0x80000000
diff --git a/src/pkg/syscall/zerrors_freebsd_amd64.go b/src/pkg/syscall/zerrors_freebsd_amd64.go
index 9b632ba..871b381 100644
--- a/src/pkg/syscall/zerrors_freebsd_amd64.go
+++ b/src/pkg/syscall/zerrors_freebsd_amd64.go
@@ -327,6 +327,13 @@ const (
 	EBUSY                             = 0x10
 	ECANCELED                         = 0x55
 	ECHILD                            = 0xa
+	ECHO                              = 0x8
+	ECHOCTL                           = 0x40
+	ECHOE                             = 0x2
+	ECHOK                             = 0x4
+	ECHOKE                            = 0x1
+	ECHONL                            = 0x10
+	ECHOPRT                           = 0x20
 	ECONNABORTED                      = 0x35
 	ECONNREFUSED                      = 0x3d
 	ECONNRESET                        = 0x36
@@ -432,6 +439,9 @@ const (
 	EV_SYSFLAGS                       = 0xf000
 	EWOULDBLOCK                       = 0x23
 	EXDEV                             = 0x12
+	EXTA                              = 0x4b00
+	EXTB                              = 0x9600
+	EXTPROC                           = 0x800
 	FD_CLOEXEC                        = 0x1
 	FD_SETSIZE                        = 0x400
 	F_CANCEL                          = 0x5
@@ -1224,6 +1234,68 @@ const (
 	TCP_NODELAY                       = 0x1
 	TCP_NOOPT                         = 0x8
 	TCP_NOPUSH                        = 0x4
+	TIOCCBRK                          = 0x2000747a
+	TIOCCDTR                          = 0x20007478
+	TIOCCONS                          = 0x80047462
+	TIOCDRAIN                         = 0x2000745e
+	TIOCEXCL                          = 0x2000740d
+	TIOCEXT                           = 0x80047460
+	TIOCFLUSH                         = 0x80047410
+	TIOCGDRAINWAIT                    = 0x40047456
+	TIOCGETA                          = 0x402c7413
+	TIOCGETD                          = 0x4004741a
+	TIOCGPGRP                         = 0x40047477
+	TIOCGPTN                          = 0x4004740f
+	TIOCGSID                          = 0x40047463
+	TIOCGWINSZ                        = 0x40087468
+	TIOCMBIC                          = 0x8004746b
+	TIOCMBIS                          = 0x8004746c
+	TIOCMGDTRWAIT                     = 0x4004745a
+	TIOCMGET                          = 0x4004746a
+	TIOCMSDTRWAIT                     = 0x8004745b
+	TIOCMSET                          = 0x8004746d
+	TIOCM_CAR                         = 0x40
+	TIOCM_CD                          = 0x40
+	TIOCM_CTS                         = 0x20
+	TIOCM_DCD                         = 0x40
+	TIOCM_DSR                         = 0x100
+	TIOCM_DTR                         = 0x2
+	TIOCM_LE                          = 0x1
+	TIOCM_RI                          = 0x80
+	TIOCM_RNG                         = 0x80
+	TIOCM_RTS                         = 0x4
+	TIOCM_SR                          = 0x10
+	TIOCM_ST                          = 0x8
+	TIOCNOTTY                         = 0x20007471
+	TIOCNXCL                          = 0x2000740e
+	TIOCOUTQ                          = 0x40047473
+	TIOCPKT                           = 0x80047470
+	TIOCPKT_DATA                      = 0
+	TIOCPKT_DOSTOP                    = 0x20
+	TIOCPKT_FLUSHREAD                 = 0x1
+	TIOCPKT_FLUSHWRITE                = 0x2
+	TIOCPKT_IOCTL                     = 0x40
+	TIOCPKT_NOSTOP                    = 0x10
+	TIOCPKT_START                     = 0x8
+	TIOCPKT_STOP                      = 0x4
+	TIOCPTMASTER                      = 0x2000741c
+	TIOCSBRK                          = 0x2000747b
+	TIOCSCTTY                         = 0x20007461
+	TIOCSDRAINWAIT                    = 0x80047457
+	TIOCSDTR                          = 0x20007479
+	TIOCSETA                          = 0x802c7414
+	TIOCSETAF                         = 0x802c7416
+	TIOCSETAW                         = 0x802c7415
+	TIOCSETD                          = 0x8004741b
+	TIOCSIG                           = 0x2004745f
+	TIOCSPGRP                         = 0x80047476
+	TIOCSTART                         = 0x2000746e
+	TIOCSTAT                          = 0x20007465
+	TIOCSTI                           = 0x80017472
+	TIOCSTOP                          = 0x2000746f
+	TIOCSWINSZ                        = 0x80087467
+	TIOCTIMESTAMP                     = 0x40107459
+	TIOCUCNTL                         = 0x80047466
 	WCONTINUED                        = 0x4
 	WCOREFLAG                         = 0x80
 	WLINUXCLONE                       = 0x80000000
diff --git a/src/pkg/syscall/zerrors_linux_386.go b/src/pkg/syscall/zerrors_linux_386.go
index 8d31581..2987540 100644
--- a/src/pkg/syscall/zerrors_linux_386.go
+++ b/src/pkg/syscall/zerrors_linux_386.go
@@ -1104,6 +1104,69 @@ const (
 	TCP_QUICKACK                     = 0xc
 	TCP_SYNCNT                       = 0x7
 	TCP_WINDOW_CLAMP                 = 0xa
+	TIOCCBRK                         = 0x5428
+	TIOCCONS                         = 0x541d
+	TIOCEXCL                         = 0x540c
+	TIOCGETD                         = 0x5424
+	TIOCGHAYESESP                    = 0x545e
+	TIOCGICOUNT                      = 0x545d
+	TIOCGLCKTRMIOS                   = 0x5456
+	TIOCGPGRP                        = 0x540f
+	TIOCGPTN                         = 0x80045430
+	TIOCGRS485                       = 0x542e
+	TIOCGSERIAL                      = 0x541e
+	TIOCGSID                         = 0x5429
+	TIOCGSOFTCAR                     = 0x5419
+	TIOCGWINSZ                       = 0x5413
+	TIOCINQ                          = 0x541b
+	TIOCLINUX                        = 0x541c
+	TIOCMBIC                         = 0x5417
+	TIOCMBIS                         = 0x5416
+	TIOCMGET                         = 0x5415
+	TIOCMIWAIT                       = 0x545c
+	TIOCMSET                         = 0x5418
+	TIOCM_CAR                        = 0x40
+	TIOCM_CD                         = 0x40
+	TIOCM_CTS                        = 0x20
+	TIOCM_DSR                        = 0x100
+	TIOCM_DTR                        = 0x2
+	TIOCM_LE                         = 0x1
+	TIOCM_RI                         = 0x80
+	TIOCM_RNG                        = 0x80
+	TIOCM_RTS                        = 0x4
+	TIOCM_SR                         = 0x10
+	TIOCM_ST                         = 0x8
+	TIOCNOTTY                        = 0x5422
+	TIOCNXCL                         = 0x540d
+	TIOCOUTQ                         = 0x5411
+	TIOCPKT                          = 0x5420
+	TIOCPKT_DATA                     = 0
+	TIOCPKT_DOSTOP                   = 0x20
+	TIOCPKT_FLUSHREAD                = 0x1
+	TIOCPKT_FLUSHWRITE               = 0x2
+	TIOCPKT_NOSTOP                   = 0x10
+	TIOCPKT_START                    = 0x8
+	TIOCPKT_STOP                     = 0x4
+	TIOCSBRK                         = 0x5427
+	TIOCSCTTY                        = 0x540e
+	TIOCSERCONFIG                    = 0x5453
+	TIOCSERGETLSR                    = 0x5459
+	TIOCSERGETMULTI                  = 0x545a
+	TIOCSERGSTRUCT                   = 0x5458
+	TIOCSERGWILD                     = 0x5454
+	TIOCSERSETMULTI                  = 0x545b
+	TIOCSERSWILD                     = 0x5455
+	TIOCSER_TEMT                     = 0x1
+	TIOCSETD                         = 0x5423
+	TIOCSHAYESESP                    = 0x545f
+	TIOCSLCKTRMIOS                   = 0x5457
+	TIOCSPGRP                        = 0x5410
+	TIOCSPTLCK                       = 0x40045431
+	TIOCSRS485                       = 0x542f
+	TIOCSSERIAL                      = 0x541f
+	TIOCSSOFTCAR                     = 0x541a
+	TIOCSTI                          = 0x5412
+	TIOCSWINSZ                       = 0x5414
 	TUNGETFEATURES                   = 0x800454cf
 	TUNGETIFF                        = 0x800454d2
 	TUNGETSNDBUF                     = 0x800454d3
diff --git a/src/pkg/syscall/zerrors_linux_amd64.go b/src/pkg/syscall/zerrors_linux_amd64.go
index 8f91478..728eefd 100644
--- a/src/pkg/syscall/zerrors_linux_amd64.go
+++ b/src/pkg/syscall/zerrors_linux_amd64.go
@@ -1105,6 +1105,69 @@ const (
 	TCP_QUICKACK                     = 0xc
 	TCP_SYNCNT                       = 0x7
 	TCP_WINDOW_CLAMP                 = 0xa
+	TIOCCBRK                         = 0x5428
+	TIOCCONS                         = 0x541d
+	TIOCEXCL                         = 0x540c
+	TIOCGETD                         = 0x5424
+	TIOCGHAYESESP                    = 0x545e
+	TIOCGICOUNT                      = 0x545d
+	TIOCGLCKTRMIOS                   = 0x5456
+	TIOCGPGRP                        = 0x540f
+	TIOCGPTN                         = 0x80045430
+	TIOCGRS485                       = 0x542e
+	TIOCGSERIAL                      = 0x541e
+	TIOCGSID                         = 0x5429
+	TIOCGSOFTCAR                     = 0x5419
+	TIOCGWINSZ                       = 0x5413
+	TIOCINQ                          = 0x541b
+	TIOCLINUX                        = 0x541c
+	TIOCMBIC                         = 0x5417
+	TIOCMBIS                         = 0x5416
+	TIOCMGET                         = 0x5415
+	TIOCMIWAIT                       = 0x545c
+	TIOCMSET                         = 0x5418
+	TIOCM_CAR                        = 0x40
+	TIOCM_CD                         = 0x40
+	TIOCM_CTS                        = 0x20
+	TIOCM_DSR                        = 0x100
+	TIOCM_DTR                        = 0x2
+	TIOCM_LE                         = 0x1
+	TIOCM_RI                         = 0x80
+	TIOCM_RNG                        = 0x80
+	TIOCM_RTS                        = 0x4
+	TIOCM_SR                         = 0x10
+	TIOCM_ST                         = 0x8
+	TIOCNOTTY                        = 0x5422
+	TIOCNXCL                         = 0x540d
+	TIOCOUTQ                         = 0x5411
+	TIOCPKT                          = 0x5420
+	TIOCPKT_DATA                     = 0
+	TIOCPKT_DOSTOP                   = 0x20
+	TIOCPKT_FLUSHREAD                = 0x1
+	TIOCPKT_FLUSHWRITE               = 0x2
+	TIOCPKT_NOSTOP                   = 0x10
+	TIOCPKT_START                    = 0x8
+	TIOCPKT_STOP                     = 0x4
+	TIOCSBRK                         = 0x5427
+	TIOCSCTTY                        = 0x540e
+	TIOCSERCONFIG                    = 0x5453
+	TIOCSERGETLSR                    = 0x5459
+	TIOCSERGETMULTI                  = 0x545a
+	TIOCSERGSTRUCT                   = 0x5458
+	TIOCSERGWILD                     = 0x5454
+	TIOCSERSETMULTI                  = 0x545b
+	TIOCSERSWILD                     = 0x5455
+	TIOCSER_TEMT                     = 0x1
+	TIOCSETD                         = 0x5423
+	TIOCSHAYESESP                    = 0x545f
+	TIOCSLCKTRMIOS                   = 0x5457
+	TIOCSPGRP                        = 0x5410
+	TIOCSPTLCK                       = 0x40045431
+	TIOCSRS485                       = 0x542f
+	TIOCSSERIAL                      = 0x541f
+	TIOCSSOFTCAR                     = 0x541a
+	TIOCSTI                          = 0x5412
+	TIOCSWINSZ                       = 0x5414
 	TUNGETFEATURES                   = 0x800454cf
 	TUNGETIFF                        = 0x800454d2
 	TUNGETSNDBUF                     = 0x800454d3
diff --git a/src/pkg/syscall/zerrors_linux_arm.go b/src/pkg/syscall/zerrors_linux_arm.go
index 64a74c0..7d57271 100644
--- a/src/pkg/syscall/zerrors_linux_arm.go
+++ b/src/pkg/syscall/zerrors_linux_arm.go
@@ -1098,6 +1098,65 @@ const (
 	TCP_QUICKACK                     = 0xc
 	TCP_SYNCNT                       = 0x7
 	TCP_WINDOW_CLAMP                 = 0xa
+	TIOCCBRK                         = 0x5428
+	TIOCCONS                         = 0x541d
+	TIOCEXCL                         = 0x540c
+	TIOCGETD                         = 0x5424
+	TIOCGICOUNT                      = 0x545d
+	TIOCGLCKTRMIOS                   = 0x5456
+	TIOCGPGRP                        = 0x540f
+	TIOCGPTN                         = 0x80045430
+	TIOCGSERIAL                      = 0x541e
+	TIOCGSID                         = 0x5429
+	TIOCGSOFTCAR                     = 0x5419
+	TIOCGWINSZ                       = 0x5413
+	TIOCINQ                          = 0x541b
+	TIOCLINUX                        = 0x541c
+	TIOCMBIC                         = 0x5417
+	TIOCMBIS                         = 0x5416
+	TIOCMGET                         = 0x5415
+	TIOCMIWAIT                       = 0x545c
+	TIOCMSET                         = 0x5418
+	TIOCM_CAR                        = 0x40
+	TIOCM_CD                         = 0x40
+	TIOCM_CTS                        = 0x20
+	TIOCM_DSR                        = 0x100
+	TIOCM_DTR                        = 0x2
+	TIOCM_LE                         = 0x1
+	TIOCM_RI                         = 0x80
+	TIOCM_RNG                        = 0x80
+	TIOCM_RTS                        = 0x4
+	TIOCM_SR                         = 0x10
+	TIOCM_ST                         = 0x8
+	TIOCNOTTY                        = 0x5422
+	TIOCNXCL                         = 0x540d
+	TIOCOUTQ                         = 0x5411
+	TIOCPKT                          = 0x5420
+	TIOCPKT_DATA                     = 0
+	TIOCPKT_DOSTOP                   = 0x20
+	TIOCPKT_FLUSHREAD                = 0x1
+	TIOCPKT_FLUSHWRITE               = 0x2
+	TIOCPKT_NOSTOP                   = 0x10
+	TIOCPKT_START                    = 0x8
+	TIOCPKT_STOP                     = 0x4
+	TIOCSBRK                         = 0x5427
+	TIOCSCTTY                        = 0x540e
+	TIOCSERCONFIG                    = 0x5453
+	TIOCSERGETLSR                    = 0x5459
+	TIOCSERGETMULTI                  = 0x545a
+	TIOCSERGSTRUCT                   = 0x5458
+	TIOCSERGWILD                     = 0x5454
+	TIOCSERSETMULTI                  = 0x545b
+	TIOCSERSWILD                     = 0x5455
+	TIOCSER_TEMT                     = 0x1
+	TIOCSETD                         = 0x5423
+	TIOCSLCKTRMIOS                   = 0x5457
+	TIOCSPGRP                        = 0x5410
+	TIOCSPTLCK                       = 0x40045431
+	TIOCSSERIAL                      = 0x541f
+	TIOCSSOFTCAR                     = 0x541a
+	TIOCSTI                          = 0x5412
+	TIOCSWINSZ                       = 0x5414
 	TUNGETFEATURES                   = 0x800454cf
 	TUNGETIFF                        = 0x800454d2
 	TUNGETSNDBUF                     = 0x800454d3
diff --git a/src/pkg/syscall/zerrors_windows_386.go b/src/pkg/syscall/zerrors_windows.go
similarity index 100%
copy from src/pkg/syscall/zerrors_windows_386.go
copy to src/pkg/syscall/zerrors_windows.go
diff --git a/src/pkg/syscall/zerrors_windows_386.go b/src/pkg/syscall/zerrors_windows_386.go
index ae4506f..d1008bd 100644
--- a/src/pkg/syscall/zerrors_windows_386.go
+++ b/src/pkg/syscall/zerrors_windows_386.go
@@ -1,283 +1,5 @@
-// mkerrors_windows.sh -f -m32
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// 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 syscall
-
-// Go names for Windows errors.
-const (
-	ENOENT  = ERROR_FILE_NOT_FOUND
-	ENOTDIR = ERROR_DIRECTORY
-)
-
-// Windows reserves errors >= 1<<29 for application use.
-const APPLICATION_ERROR = 1 << 29
-
-// Invented values to support what package os and others expects.
-const (
-	E2BIG = APPLICATION_ERROR + iota
-	EACCES
-	EADDRINUSE
-	EADDRNOTAVAIL
-	EADV
-	EAFNOSUPPORT
-	EAGAIN
-	EALREADY
-	EBADE
-	EBADF
-	EBADFD
-	EBADMSG
-	EBADR
-	EBADRQC
-	EBADSLT
-	EBFONT
-	EBUSY
-	ECANCELED
-	ECHILD
-	ECHRNG
-	ECOMM
-	ECONNABORTED
-	ECONNREFUSED
-	ECONNRESET
-	EDEADLK
-	EDEADLOCK
-	EDESTADDRREQ
-	EDOM
-	EDOTDOT
-	EDQUOT
-	EEXIST
-	EFAULT
-	EFBIG
-	EHOSTDOWN
-	EHOSTUNREACH
-	EIDRM
-	EILSEQ
-	EINPROGRESS
-	EINTR
-	EINVAL
-	EIO
-	EISCONN
-	EISDIR
-	EISNAM
-	EKEYEXPIRED
-	EKEYREJECTED
-	EKEYREVOKED
-	EL2HLT
-	EL2NSYNC
-	EL3HLT
-	EL3RST
-	ELIBACC
-	ELIBBAD
-	ELIBEXEC
-	ELIBMAX
-	ELIBSCN
-	ELNRNG
-	ELOOP
-	EMEDIUMTYPE
-	EMFILE
-	EMLINK
-	EMSGSIZE
-	EMULTIHOP
-	ENAMETOOLONG
-	ENAVAIL
-	ENETDOWN
-	ENETRESET
-	ENETUNREACH
-	ENFILE
-	ENOANO
-	ENOBUFS
-	ENOCSI
-	ENODATA
-	ENODEV
-	ENOEXEC
-	ENOKEY
-	ENOLCK
-	ENOLINK
-	ENOMEDIUM
-	ENOMEM
-	ENOMSG
-	ENONET
-	ENOPKG
-	ENOPROTOOPT
-	ENOSPC
-	ENOSR
-	ENOSTR
-	ENOSYS
-	ENOTBLK
-	ENOTCONN
-	ENOTEMPTY
-	ENOTNAM
-	ENOTRECOVERABLE
-	ENOTSOCK
-	ENOTSUP
-	ENOTTY
-	ENOTUNIQ
-	ENXIO
-	EOPNOTSUPP
-	EOVERFLOW
-	EOWNERDEAD
-	EPERM
-	EPFNOSUPPORT
-	EPIPE
-	EPROTO
-	EPROTONOSUPPORT
-	EPROTOTYPE
-	ERANGE
-	EREMCHG
-	EREMOTE
-	EREMOTEIO
-	ERESTART
-	EROFS
-	ESHUTDOWN
-	ESOCKTNOSUPPORT
-	ESPIPE
-	ESRCH
-	ESRMNT
-	ESTALE
-	ESTRPIPE
-	ETIME
-	ETIMEDOUT
-	ETOOMANYREFS
-	ETXTBSY
-	EUCLEAN
-	EUNATCH
-	EUSERS
-	EWOULDBLOCK
-	EXDEV
-	EXFULL
-	EWINDOWS
-)
-
-// Error strings for invented errors
-var errors = [...]string{
-	E2BIG - APPLICATION_ERROR:           "argument list too long",
-	EACCES - APPLICATION_ERROR:          "permission denied",
-	EADDRINUSE - APPLICATION_ERROR:      "address already in use",
-	EADDRNOTAVAIL - APPLICATION_ERROR:   "cannot assign requested address",
-	EADV - APPLICATION_ERROR:            "advertise error",
-	EAFNOSUPPORT - APPLICATION_ERROR:    "address family not supported by protocol",
-	EAGAIN - APPLICATION_ERROR:          "resource temporarily unavailable",
-	EALREADY - APPLICATION_ERROR:        "operation already in progress",
-	EBADE - APPLICATION_ERROR:           "invalid exchange",
-	EBADF - APPLICATION_ERROR:           "bad file descriptor",
-	EBADFD - APPLICATION_ERROR:          "file descriptor in bad state",
-	EBADMSG - APPLICATION_ERROR:         "bad message",
-	EBADR - APPLICATION_ERROR:           "invalid request descriptor",
-	EBADRQC - APPLICATION_ERROR:         "invalid request code",
-	EBADSLT - APPLICATION_ERROR:         "invalid slot",
-	EBFONT - APPLICATION_ERROR:          "bad font file format",
-	EBUSY - APPLICATION_ERROR:           "device or resource busy",
-	ECANCELED - APPLICATION_ERROR:       "operation canceled",
-	ECHILD - APPLICATION_ERROR:          "no child processes",
-	ECHRNG - APPLICATION_ERROR:          "channel number out of range",
-	ECOMM - APPLICATION_ERROR:           "communication error on send",
-	ECONNABORTED - APPLICATION_ERROR:    "software caused connection abort",
-	ECONNREFUSED - APPLICATION_ERROR:    "connection refused",
-	ECONNRESET - APPLICATION_ERROR:      "connection reset by peer",
-	EDEADLK - APPLICATION_ERROR:         "resource deadlock avoided",
-	EDEADLOCK - APPLICATION_ERROR:       "resource deadlock avoided",
-	EDESTADDRREQ - APPLICATION_ERROR:    "destination address required",
-	EDOM - APPLICATION_ERROR:            "numerical argument out of domain",
-	EDOTDOT - APPLICATION_ERROR:         "RFS specific error",
-	EDQUOT - APPLICATION_ERROR:          "disk quota exceeded",
-	EEXIST - APPLICATION_ERROR:          "file exists",
-	EFAULT - APPLICATION_ERROR:          "bad address",
-	EFBIG - APPLICATION_ERROR:           "file too large",
-	EHOSTDOWN - APPLICATION_ERROR:       "host is down",
-	EHOSTUNREACH - APPLICATION_ERROR:    "no route to host",
-	EIDRM - APPLICATION_ERROR:           "identifier removed",
-	EILSEQ - APPLICATION_ERROR:          "invalid or incomplete multibyte or wide character",
-	EINPROGRESS - APPLICATION_ERROR:     "operation now in progress",
-	EINTR - APPLICATION_ERROR:           "interrupted system call",
-	EINVAL - APPLICATION_ERROR:          "invalid argument",
-	EIO - APPLICATION_ERROR:             "input/output error",
-	EISCONN - APPLICATION_ERROR:         "transport endpoint is already connected",
-	EISDIR - APPLICATION_ERROR:          "is a directory",
-	EISNAM - APPLICATION_ERROR:          "is a named type file",
-	EKEYEXPIRED - APPLICATION_ERROR:     "key has expired",
-	EKEYREJECTED - APPLICATION_ERROR:    "key was rejected by service",
-	EKEYREVOKED - APPLICATION_ERROR:     "key has been revoked",
-	EL2HLT - APPLICATION_ERROR:          "level 2 halted",
-	EL2NSYNC - APPLICATION_ERROR:        "level 2 not synchronized",
-	EL3HLT - APPLICATION_ERROR:          "level 3 halted",
-	EL3RST - APPLICATION_ERROR:          "level 3 reset",
-	ELIBACC - APPLICATION_ERROR:         "can not access a needed shared library",
-	ELIBBAD - APPLICATION_ERROR:         "accessing a corrupted shared library",
-	ELIBEXEC - APPLICATION_ERROR:        "cannot exec a shared library directly",
-	ELIBMAX - APPLICATION_ERROR:         "attempting to link in too many shared libraries",
-	ELIBSCN - APPLICATION_ERROR:         ".lib section in a.out corrupted",
-	ELNRNG - APPLICATION_ERROR:          "link number out of range",
-	ELOOP - APPLICATION_ERROR:           "too many levels of symbolic links",
-	EMEDIUMTYPE - APPLICATION_ERROR:     "wrong medium type",
-	EMFILE - APPLICATION_ERROR:          "too many open files",
-	EMLINK - APPLICATION_ERROR:          "too many links",
-	EMSGSIZE - APPLICATION_ERROR:        "message too long",
-	EMULTIHOP - APPLICATION_ERROR:       "multihop attempted",
-	ENAMETOOLONG - APPLICATION_ERROR:    "file name too long",
-	ENAVAIL - APPLICATION_ERROR:         "no XENIX semaphores available",
-	ENETDOWN - APPLICATION_ERROR:        "network is down",
-	ENETRESET - APPLICATION_ERROR:       "network dropped connection on reset",
-	ENETUNREACH - APPLICATION_ERROR:     "network is unreachable",
-	ENFILE - APPLICATION_ERROR:          "too many open files in system",
-	ENOANO - APPLICATION_ERROR:          "no anode",
-	ENOBUFS - APPLICATION_ERROR:         "no buffer space available",
-	ENOCSI - APPLICATION_ERROR:          "no CSI structure available",
-	ENODATA - APPLICATION_ERROR:         "no data available",
-	ENODEV - APPLICATION_ERROR:          "no such device",
-	ENOEXEC - APPLICATION_ERROR:         "exec format error",
-	ENOKEY - APPLICATION_ERROR:          "required key not available",
-	ENOLCK - APPLICATION_ERROR:          "no locks available",
-	ENOLINK - APPLICATION_ERROR:         "link has been severed",
-	ENOMEDIUM - APPLICATION_ERROR:       "no medium found",
-	ENOMEM - APPLICATION_ERROR:          "cannot allocate memory",
-	ENOMSG - APPLICATION_ERROR:          "no message of desired type",
-	ENONET - APPLICATION_ERROR:          "machine is not on the network",
-	ENOPKG - APPLICATION_ERROR:          "package not installed",
-	ENOPROTOOPT - APPLICATION_ERROR:     "protocol not available",
-	ENOSPC - APPLICATION_ERROR:          "no space left on device",
-	ENOSR - APPLICATION_ERROR:           "out of streams resources",
-	ENOSTR - APPLICATION_ERROR:          "device not a stream",
-	ENOSYS - APPLICATION_ERROR:          "function not implemented",
-	ENOTBLK - APPLICATION_ERROR:         "block device required",
-	ENOTCONN - APPLICATION_ERROR:        "transport endpoint is not connected",
-	ENOTEMPTY - APPLICATION_ERROR:       "directory not empty",
-	ENOTNAM - APPLICATION_ERROR:         "not a XENIX named type file",
-	ENOTRECOVERABLE - APPLICATION_ERROR: "state not recoverable",
-	ENOTSOCK - APPLICATION_ERROR:        "socket operation on non-socket",
-	ENOTSUP - APPLICATION_ERROR:         "operation not supported",
-	ENOTTY - APPLICATION_ERROR:          "inappropriate ioctl for device",
-	ENOTUNIQ - APPLICATION_ERROR:        "name not unique on network",
-	ENXIO - APPLICATION_ERROR:           "no such device or address",
-	EOPNOTSUPP - APPLICATION_ERROR:      "operation not supported",
-	EOVERFLOW - APPLICATION_ERROR:       "value too large for defined data type",
-	EOWNERDEAD - APPLICATION_ERROR:      "owner died",
-	EPERM - APPLICATION_ERROR:           "operation not permitted",
-	EPFNOSUPPORT - APPLICATION_ERROR:    "protocol family not supported",
-	EPIPE - APPLICATION_ERROR:           "broken pipe",
-	EPROTO - APPLICATION_ERROR:          "protocol error",
-	EPROTONOSUPPORT - APPLICATION_ERROR: "protocol not supported",
-	EPROTOTYPE - APPLICATION_ERROR:      "protocol wrong type for socket",
-	ERANGE - APPLICATION_ERROR:          "numerical result out of range",
-	EREMCHG - APPLICATION_ERROR:         "remote address changed",
-	EREMOTE - APPLICATION_ERROR:         "object is remote",
-	EREMOTEIO - APPLICATION_ERROR:       "remote I/O error",
-	ERESTART - APPLICATION_ERROR:        "interrupted system call should be restarted",
-	EROFS - APPLICATION_ERROR:           "read-only file system",
-	ESHUTDOWN - APPLICATION_ERROR:       "cannot send after transport endpoint shutdown",
-	ESOCKTNOSUPPORT - APPLICATION_ERROR: "socket type not supported",
-	ESPIPE - APPLICATION_ERROR:          "illegal seek",
-	ESRCH - APPLICATION_ERROR:           "no such process",
-	ESRMNT - APPLICATION_ERROR:          "srmount error",
-	ESTALE - APPLICATION_ERROR:          "stale NFS file handle",
-	ESTRPIPE - APPLICATION_ERROR:        "streams pipe error",
-	ETIME - APPLICATION_ERROR:           "timer expired",
-	ETIMEDOUT - APPLICATION_ERROR:       "connection timed out",
-	ETOOMANYREFS - APPLICATION_ERROR:    "too many references: cannot splice",
-	ETXTBSY - APPLICATION_ERROR:         "text file busy",
-	EUCLEAN - APPLICATION_ERROR:         "structure needs cleaning",
-	EUNATCH - APPLICATION_ERROR:         "protocol driver not attached",
-	EUSERS - APPLICATION_ERROR:          "too many users",
-	EWOULDBLOCK - APPLICATION_ERROR:     "resource temporarily unavailable",
-	EXDEV - APPLICATION_ERROR:           "invalid cross-device link",
-	EXFULL - APPLICATION_ERROR:          "exchange full",
-	EWINDOWS - APPLICATION_ERROR:        "not supported by windows",
-}
diff --git a/src/pkg/syscall/zerrors_windows_amd64.go b/src/pkg/syscall/zerrors_windows_amd64.go
new file mode 100644
index 0000000..d1008bd
--- /dev/null
+++ b/src/pkg/syscall/zerrors_windows_amd64.go
@@ -0,0 +1,5 @@
+// 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 syscall
diff --git a/src/pkg/syscall/zsyscall_windows_386.go b/src/pkg/syscall/zsyscall_windows_386.go
index fd28d33..350ad23 100644
--- a/src/pkg/syscall/zsyscall_windows_386.go
+++ b/src/pkg/syscall/zsyscall_windows_386.go
@@ -1,4 +1,4 @@
-// mksyscall_windows.pl 
+// mksyscall_windows.pl -l32 syscall_windows.go syscall_windows_386.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
 package syscall
@@ -112,9 +112,9 @@ func GetLastError() (lasterrno int) {
 	return
 }
 
-func LoadLibrary(libname string) (handle uint32, errno int) {
+func LoadLibrary(libname string) (handle Handle, errno int) {
 	r0, _, e1 := Syscall(procLoadLibraryW, 1, uintptr(unsafe.Pointer(StringToUTF16Ptr(libname))), 0, 0)
-	handle = uint32(r0)
+	handle = Handle(r0)
 	if handle == 0 {
 		if e1 != 0 {
 			errno = int(e1)
@@ -127,7 +127,7 @@ func LoadLibrary(libname string) (handle uint32, errno int) {
 	return
 }
 
-func FreeLibrary(handle uint32) (errno int) {
+func FreeLibrary(handle Handle) (errno int) {
 	r1, _, e1 := Syscall(procFreeLibrary, 1, uintptr(handle), 0, 0)
 	if int(r1) == 0 {
 		if e1 != 0 {
@@ -141,9 +141,9 @@ func FreeLibrary(handle uint32) (errno int) {
 	return
 }
 
-func GetProcAddress(module uint32, procname string) (proc uint32, errno int) {
+func GetProcAddress(module Handle, procname string) (proc Handle, errno int) {
 	r0, _, e1 := Syscall(procGetProcAddress, 2, uintptr(module), uintptr(unsafe.Pointer(StringBytePtr(procname))), 0)
-	proc = uint32(r0)
+	proc = Handle(r0)
 	if proc == 0 {
 		if e1 != 0 {
 			errno = int(e1)
@@ -195,10 +195,10 @@ func ExitProcess(exitcode uint32) {
 	return
 }
 
-func CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile int32) (handle int32, errno int) {
+func CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile int32) (handle Handle, errno int) {
 	r0, _, e1 := Syscall9(procCreateFileW, 7, uintptr(unsafe.Pointer(name)), uintptr(access), uintptr(mode), uintptr(unsafe.Pointer(sa)), uintptr(createmode), uintptr(attrs), uintptr(templatefile), 0, 0)
-	handle = int32(r0)
-	if handle == -1 {
+	handle = Handle(r0)
+	if handle == InvalidHandle {
 		if e1 != 0 {
 			errno = int(e1)
 		} else {
@@ -210,7 +210,7 @@ func CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes
 	return
 }
 
-func ReadFile(handle int32, buf []byte, done *uint32, overlapped *Overlapped) (errno int) {
+func ReadFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (errno int) {
 	var _p0 *byte
 	if len(buf) > 0 {
 		_p0 = &buf[0]
@@ -228,7 +228,7 @@ func ReadFile(handle int32, buf []byte, done *uint32, overlapped *Overlapped) (e
 	return
 }
 
-func WriteFile(handle int32, buf []byte, done *uint32, overlapped *Overlapped) (errno int) {
+func WriteFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (errno int) {
 	var _p0 *byte
 	if len(buf) > 0 {
 		_p0 = &buf[0]
@@ -246,7 +246,7 @@ func WriteFile(handle int32, buf []byte, done *uint32, overlapped *Overlapped) (
 	return
 }
 
-func SetFilePointer(handle int32, lowoffset int32, highoffsetptr *int32, whence uint32) (newlowoffset uint32, errno int) {
+func SetFilePointer(handle Handle, lowoffset int32, highoffsetptr *int32, whence uint32) (newlowoffset uint32, errno int) {
 	r0, _, e1 := Syscall6(procSetFilePointer, 4, uintptr(handle), uintptr(lowoffset), uintptr(unsafe.Pointer(highoffsetptr)), uintptr(whence), 0, 0)
 	newlowoffset = uint32(r0)
 	if newlowoffset == 0xffffffff {
@@ -261,7 +261,7 @@ func SetFilePointer(handle int32, lowoffset int32, highoffsetptr *int32, whence
 	return
 }
 
-func CloseHandle(handle int32) (errno int) {
+func CloseHandle(handle Handle) (errno int) {
 	r1, _, e1 := Syscall(procCloseHandle, 1, uintptr(handle), 0, 0)
 	if int(r1) == 0 {
 		if e1 != 0 {
@@ -275,10 +275,10 @@ func CloseHandle(handle int32) (errno int) {
 	return
 }
 
-func GetStdHandle(stdhandle int32) (handle int32, errno int) {
+func GetStdHandle(stdhandle int) (handle Handle, errno int) {
 	r0, _, e1 := Syscall(procGetStdHandle, 1, uintptr(stdhandle), 0, 0)
-	handle = int32(r0)
-	if handle == -1 {
+	handle = Handle(r0)
+	if handle == InvalidHandle {
 		if e1 != 0 {
 			errno = int(e1)
 		} else {
@@ -290,10 +290,10 @@ func GetStdHandle(stdhandle int32) (handle int32, errno int) {
 	return
 }
 
-func FindFirstFile(name *uint16, data *Win32finddata) (handle int32, errno int) {
+func FindFirstFile(name *uint16, data *Win32finddata) (handle Handle, errno int) {
 	r0, _, e1 := Syscall(procFindFirstFileW, 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(data)), 0)
-	handle = int32(r0)
-	if handle == -1 {
+	handle = Handle(r0)
+	if handle == InvalidHandle {
 		if e1 != 0 {
 			errno = int(e1)
 		} else {
@@ -305,7 +305,7 @@ func FindFirstFile(name *uint16, data *Win32finddata) (handle int32, errno int)
 	return
 }
 
-func FindNextFile(handle int32, data *Win32finddata) (errno int) {
+func FindNextFile(handle Handle, data *Win32finddata) (errno int) {
 	r1, _, e1 := Syscall(procFindNextFileW, 2, uintptr(handle), uintptr(unsafe.Pointer(data)), 0)
 	if int(r1) == 0 {
 		if e1 != 0 {
@@ -319,7 +319,7 @@ func FindNextFile(handle int32, data *Win32finddata) (errno int) {
 	return
 }
 
-func FindClose(handle int32) (errno int) {
+func FindClose(handle Handle) (errno int) {
 	r1, _, e1 := Syscall(procFindClose, 1, uintptr(handle), 0, 0)
 	if int(r1) == 0 {
 		if e1 != 0 {
@@ -333,7 +333,7 @@ func FindClose(handle int32) (errno int) {
 	return
 }
 
-func GetFileInformationByHandle(handle int32, data *ByHandleFileInformation) (errno int) {
+func GetFileInformationByHandle(handle Handle, data *ByHandleFileInformation) (errno int) {
 	r1, _, e1 := Syscall(procGetFileInformationByHandle, 2, uintptr(handle), uintptr(unsafe.Pointer(data)), 0)
 	if int(r1) == 0 {
 		if e1 != 0 {
@@ -446,7 +446,7 @@ func GetComputerName(buf *uint16, n *uint32) (errno int) {
 	return
 }
 
-func SetEndOfFile(handle int32) (errno int) {
+func SetEndOfFile(handle Handle) (errno int) {
 	r1, _, e1 := Syscall(procSetEndOfFile, 1, uintptr(handle), 0, 0)
 	if int(r1) == 0 {
 		if e1 != 0 {
@@ -485,9 +485,9 @@ func GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, errno int) {
 	return
 }
 
-func CreateIoCompletionPort(filehandle int32, cphandle int32, key uint32, threadcnt uint32) (handle int32, errno int) {
+func CreateIoCompletionPort(filehandle Handle, cphandle Handle, key uint32, threadcnt uint32) (handle Handle, errno int) {
 	r0, _, e1 := Syscall6(procCreateIoCompletionPort, 4, uintptr(filehandle), uintptr(cphandle), uintptr(key), uintptr(threadcnt), 0, 0)
-	handle = int32(r0)
+	handle = Handle(r0)
 	if handle == 0 {
 		if e1 != 0 {
 			errno = int(e1)
@@ -500,7 +500,7 @@ func CreateIoCompletionPort(filehandle int32, cphandle int32, key uint32, thread
 	return
 }
 
-func GetQueuedCompletionStatus(cphandle int32, qty *uint32, key *uint32, overlapped **Overlapped, timeout uint32) (errno int) {
+func GetQueuedCompletionStatus(cphandle Handle, qty *uint32, key *uint32, overlapped **Overlapped, timeout uint32) (errno int) {
 	r1, _, e1 := Syscall6(procGetQueuedCompletionStatus, 5, uintptr(cphandle), uintptr(unsafe.Pointer(qty)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(overlapped)), uintptr(timeout), 0)
 	if int(r1) == 0 {
 		if e1 != 0 {
@@ -514,7 +514,7 @@ func GetQueuedCompletionStatus(cphandle int32, qty *uint32, key *uint32, overlap
 	return
 }
 
-func CancelIo(s uint32) (errno int) {
+func CancelIo(s Handle) (errno int) {
 	r1, _, e1 := Syscall(procCancelIo, 1, uintptr(s), 0, 0)
 	if int(r1) == 0 {
 		if e1 != 0 {
@@ -548,7 +548,7 @@ func CreateProcess(appName *uint16, commandLine *uint16, procSecurity *SecurityA
 	return
 }
 
-func OpenProcess(da uint32, inheritHandle bool, pid uint32) (handle int32, errno int) {
+func OpenProcess(da uint32, inheritHandle bool, pid uint32) (handle Handle, errno int) {
 	var _p0 uint32
 	if inheritHandle {
 		_p0 = 1
@@ -556,7 +556,7 @@ func OpenProcess(da uint32, inheritHandle bool, pid uint32) (handle int32, errno
 		_p0 = 0
 	}
 	r0, _, e1 := Syscall(procOpenProcess, 3, uintptr(da), uintptr(_p0), uintptr(pid))
-	handle = int32(r0)
+	handle = Handle(r0)
 	if handle == 0 {
 		if e1 != 0 {
 			errno = int(e1)
@@ -569,7 +569,7 @@ func OpenProcess(da uint32, inheritHandle bool, pid uint32) (handle int32, errno
 	return
 }
 
-func TerminateProcess(handle int32, exitcode uint32) (errno int) {
+func TerminateProcess(handle Handle, exitcode uint32) (errno int) {
 	r1, _, e1 := Syscall(procTerminateProcess, 2, uintptr(handle), uintptr(exitcode), 0)
 	if int(r1) == 0 {
 		if e1 != 0 {
@@ -583,7 +583,7 @@ func TerminateProcess(handle int32, exitcode uint32) (errno int) {
 	return
 }
 
-func GetExitCodeProcess(handle int32, exitcode *uint32) (errno int) {
+func GetExitCodeProcess(handle Handle, exitcode *uint32) (errno int) {
 	r1, _, e1 := Syscall(procGetExitCodeProcess, 2, uintptr(handle), uintptr(unsafe.Pointer(exitcode)), 0)
 	if int(r1) == 0 {
 		if e1 != 0 {
@@ -611,9 +611,9 @@ func GetStartupInfo(startupInfo *StartupInfo) (errno int) {
 	return
 }
 
-func GetCurrentProcess() (pseudoHandle int32, errno int) {
+func GetCurrentProcess() (pseudoHandle Handle, errno int) {
 	r0, _, e1 := Syscall(procGetCurrentProcess, 0, 0, 0, 0)
-	pseudoHandle = int32(r0)
+	pseudoHandle = Handle(r0)
 	if pseudoHandle == 0 {
 		if e1 != 0 {
 			errno = int(e1)
@@ -626,7 +626,7 @@ func GetCurrentProcess() (pseudoHandle int32, errno int) {
 	return
 }
 
-func DuplicateHandle(hSourceProcessHandle int32, hSourceHandle int32, hTargetProcessHandle int32, lpTargetHandle *int32, dwDesiredAccess uint32, bInheritHandle bool, dwOptions uint32) (errno int) {
+func DuplicateHandle(hSourceProcessHandle Handle, hSourceHandle Handle, hTargetProcessHandle Handle, lpTargetHandle *Handle, dwDesiredAccess uint32, bInheritHandle bool, dwOptions uint32) (errno int) {
 	var _p0 uint32
 	if bInheritHandle {
 		_p0 = 1
@@ -646,7 +646,7 @@ func DuplicateHandle(hSourceProcessHandle int32, hSourceHandle int32, hTargetPro
 	return
 }
 
-func WaitForSingleObject(handle int32, waitMilliseconds uint32) (event uint32, errno int) {
+func WaitForSingleObject(handle Handle, waitMilliseconds uint32) (event uint32, errno int) {
 	r0, _, e1 := Syscall(procWaitForSingleObject, 2, uintptr(handle), uintptr(waitMilliseconds), 0)
 	event = uint32(r0)
 	if event == 0xffffffff {
@@ -676,7 +676,7 @@ func GetTempPath(buflen uint32, buf *uint16) (n uint32, errno int) {
 	return
 }
 
-func CreatePipe(readhandle *uint32, writehandle *uint32, sa *SecurityAttributes, size uint32) (errno int) {
+func CreatePipe(readhandle *Handle, writehandle *Handle, sa *SecurityAttributes, size uint32) (errno int) {
 	r1, _, e1 := Syscall6(procCreatePipe, 4, uintptr(unsafe.Pointer(readhandle)), uintptr(unsafe.Pointer(writehandle)), uintptr(unsafe.Pointer(sa)), uintptr(size), 0, 0)
 	if int(r1) == 0 {
 		if e1 != 0 {
@@ -690,7 +690,7 @@ func CreatePipe(readhandle *uint32, writehandle *uint32, sa *SecurityAttributes,
 	return
 }
 
-func GetFileType(filehandle uint32) (n uint32, errno int) {
+func GetFileType(filehandle Handle) (n uint32, errno int) {
 	r0, _, e1 := Syscall(procGetFileType, 1, uintptr(filehandle), 0, 0)
 	n = uint32(r0)
 	if n == 0 {
@@ -705,7 +705,7 @@ func GetFileType(filehandle uint32) (n uint32, errno int) {
 	return
 }
 
-func CryptAcquireContext(provhandle *uint32, container *uint16, provider *uint16, provtype uint32, flags uint32) (errno int) {
+func CryptAcquireContext(provhandle *Handle, container *uint16, provider *uint16, provtype uint32, flags uint32) (errno int) {
 	r1, _, e1 := Syscall6(procCryptAcquireContextW, 5, uintptr(unsafe.Pointer(provhandle)), uintptr(unsafe.Pointer(container)), uintptr(unsafe.Pointer(provider)), uintptr(provtype), uintptr(flags), 0)
 	if int(r1) == 0 {
 		if e1 != 0 {
@@ -719,7 +719,7 @@ func CryptAcquireContext(provhandle *uint32, container *uint16, provider *uint16
 	return
 }
 
-func CryptReleaseContext(provhandle uint32, flags uint32) (errno int) {
+func CryptReleaseContext(provhandle Handle, flags uint32) (errno int) {
 	r1, _, e1 := Syscall(procCryptReleaseContext, 2, uintptr(provhandle), uintptr(flags), 0)
 	if int(r1) == 0 {
 		if e1 != 0 {
@@ -733,7 +733,7 @@ func CryptReleaseContext(provhandle uint32, flags uint32) (errno int) {
 	return
 }
 
-func CryptGenRandom(provhandle uint32, buflen uint32, buf *byte) (errno int) {
+func CryptGenRandom(provhandle Handle, buflen uint32, buf *byte) (errno int) {
 	r1, _, e1 := Syscall(procCryptGenRandom, 3, uintptr(provhandle), uintptr(buflen), uintptr(unsafe.Pointer(buf)))
 	if int(r1) == 0 {
 		if e1 != 0 {
@@ -805,7 +805,7 @@ func SetEnvironmentVariable(name *uint16, value *uint16) (errno int) {
 	return
 }
 
-func SetFileTime(handle int32, ctime *Filetime, atime *Filetime, wtime *Filetime) (errno int) {
+func SetFileTime(handle Handle, ctime *Filetime, atime *Filetime, wtime *Filetime) (errno int) {
 	r1, _, e1 := Syscall6(procSetFileTime, 4, uintptr(handle), uintptr(unsafe.Pointer(ctime)), uintptr(unsafe.Pointer(atime)), uintptr(unsafe.Pointer(wtime)), 0, 0)
 	if int(r1) == 0 {
 		if e1 != 0 {
@@ -869,9 +869,9 @@ func CommandLineToArgv(cmd *uint16, argc *int32) (argv *[8192]*[8192]uint16, err
 	return
 }
 
-func LocalFree(hmem uint32) (handle uint32, errno int) {
+func LocalFree(hmem Handle) (handle Handle, errno int) {
 	r0, _, e1 := Syscall(procLocalFree, 1, uintptr(hmem), 0, 0)
-	handle = uint32(r0)
+	handle = Handle(r0)
 	if handle != 0 {
 		if e1 != 0 {
 			errno = int(e1)
@@ -884,7 +884,7 @@ func LocalFree(hmem uint32) (handle uint32, errno int) {
 	return
 }
 
-func SetHandleInformation(handle int32, mask uint32, flags uint32) (errno int) {
+func SetHandleInformation(handle Handle, mask uint32, flags uint32) (errno int) {
 	r1, _, e1 := Syscall(procSetHandleInformation, 3, uintptr(handle), uintptr(mask), uintptr(flags))
 	if int(r1) == 0 {
 		if e1 != 0 {
@@ -898,7 +898,7 @@ func SetHandleInformation(handle int32, mask uint32, flags uint32) (errno int) {
 	return
 }
 
-func FlushFileBuffers(handle int32) (errno int) {
+func FlushFileBuffers(handle Handle) (errno int) {
 	r1, _, e1 := Syscall(procFlushFileBuffers, 1, uintptr(handle), 0, 0)
 	if int(r1) == 0 {
 		if e1 != 0 {
@@ -927,9 +927,9 @@ func GetFullPathName(path *uint16, buflen uint32, buf *uint16, fname **uint16) (
 	return
 }
 
-func CreateFileMapping(fhandle int32, sa *SecurityAttributes, prot uint32, maxSizeHigh uint32, maxSizeLow uint32, name *uint16) (handle int32, errno int) {
+func CreateFileMapping(fhandle Handle, sa *SecurityAttributes, prot uint32, maxSizeHigh uint32, maxSizeLow uint32, name *uint16) (handle Handle, errno int) {
 	r0, _, e1 := Syscall6(procCreateFileMappingW, 6, uintptr(fhandle), uintptr(unsafe.Pointer(sa)), uintptr(prot), uintptr(maxSizeHigh), uintptr(maxSizeLow), uintptr(unsafe.Pointer(name)))
-	handle = int32(r0)
+	handle = Handle(r0)
 	if handle == 0 {
 		if e1 != 0 {
 			errno = int(e1)
@@ -942,7 +942,7 @@ func CreateFileMapping(fhandle int32, sa *SecurityAttributes, prot uint32, maxSi
 	return
 }
 
-func MapViewOfFile(handle int32, access uint32, offsetHigh uint32, offsetLow uint32, length uintptr) (addr uintptr, errno int) {
+func MapViewOfFile(handle Handle, access uint32, offsetHigh uint32, offsetLow uint32, length uintptr) (addr uintptr, errno int) {
 	r0, _, e1 := Syscall6(procMapViewOfFile, 5, uintptr(handle), uintptr(access), uintptr(offsetHigh), uintptr(offsetLow), uintptr(length), 0)
 	addr = uintptr(r0)
 	if addr == 0 {
@@ -1013,7 +1013,7 @@ func VirtualUnlock(addr uintptr, length uintptr) (errno int) {
 	return
 }
 
-func TransmitFile(s int32, handle int32, bytesToWrite uint32, bytsPerSend uint32, overlapped *Overlapped, transmitFileBuf *TransmitFileBuffers, flags uint32) (errno int) {
+func TransmitFile(s Handle, handle Handle, bytesToWrite uint32, bytsPerSend uint32, overlapped *Overlapped, transmitFileBuf *TransmitFileBuffers, flags uint32) (errno int) {
 	r1, _, e1 := Syscall9(procTransmitFile, 7, uintptr(s), uintptr(handle), uintptr(bytesToWrite), uintptr(bytsPerSend), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(transmitFileBuf)), uintptr(flags), 0, 0)
 	if int(r1) == 0 {
 		if e1 != 0 {
@@ -1047,7 +1047,7 @@ func WSACleanup() (errno int) {
 	return
 }
 
-func WSAIoctl(s int32, iocc uint32, inbuf *byte, cbif uint32, outbuf *byte, cbob uint32, cbbr *uint32, overlapped *Overlapped, completionRoutine uintptr) (errno int) {
+func WSAIoctl(s Handle, iocc uint32, inbuf *byte, cbif uint32, outbuf *byte, cbob uint32, cbbr *uint32, overlapped *Overlapped, completionRoutine uintptr) (errno int) {
 	r1, _, e1 := Syscall9(procWSAIoctl, 9, uintptr(s), uintptr(iocc), uintptr(unsafe.Pointer(inbuf)), uintptr(cbif), uintptr(unsafe.Pointer(outbuf)), uintptr(cbob), uintptr(unsafe.Pointer(cbbr)), uintptr(unsafe.Pointer(overlapped)), uintptr(completionRoutine))
 	if int(r1) == -1 {
 		if e1 != 0 {
@@ -1061,10 +1061,10 @@ func WSAIoctl(s int32, iocc uint32, inbuf *byte, cbif uint32, outbuf *byte, cbob
 	return
 }
 
-func socket(af int32, typ int32, protocol int32) (handle int32, errno int) {
+func socket(af int32, typ int32, protocol int32) (handle Handle, errno int) {
 	r0, _, e1 := Syscall(procsocket, 3, uintptr(af), uintptr(typ), uintptr(protocol))
-	handle = int32(r0)
-	if handle == -1 {
+	handle = Handle(r0)
+	if handle == InvalidHandle {
 		if e1 != 0 {
 			errno = int(e1)
 		} else {
@@ -1076,7 +1076,7 @@ func socket(af int32, typ int32, protocol int32) (handle int32, errno int) {
 	return
 }
 
-func setsockopt(s int32, level int32, optname int32, optval *byte, optlen int32) (errno int) {
+func setsockopt(s Handle, level int32, optname int32, optval *byte, optlen int32) (errno int) {
 	r1, _, e1 := Syscall6(procsetsockopt, 5, uintptr(s), uintptr(level), uintptr(optname), uintptr(unsafe.Pointer(optval)), uintptr(optlen), 0)
 	if int(r1) == -1 {
 		if e1 != 0 {
@@ -1090,7 +1090,7 @@ func setsockopt(s int32, level int32, optname int32, optval *byte, optlen int32)
 	return
 }
 
-func bind(s int32, name uintptr, namelen int32) (errno int) {
+func bind(s Handle, name uintptr, namelen int32) (errno int) {
 	r1, _, e1 := Syscall(procbind, 3, uintptr(s), uintptr(name), uintptr(namelen))
 	if int(r1) == -1 {
 		if e1 != 0 {
@@ -1104,7 +1104,7 @@ func bind(s int32, name uintptr, namelen int32) (errno int) {
 	return
 }
 
-func connect(s int32, name uintptr, namelen int32) (errno int) {
+func connect(s Handle, name uintptr, namelen int32) (errno int) {
 	r1, _, e1 := Syscall(procconnect, 3, uintptr(s), uintptr(name), uintptr(namelen))
 	if int(r1) == -1 {
 		if e1 != 0 {
@@ -1118,7 +1118,7 @@ func connect(s int32, name uintptr, namelen int32) (errno int) {
 	return
 }
 
-func getsockname(s int32, rsa *RawSockaddrAny, addrlen *int32) (errno int) {
+func getsockname(s Handle, rsa *RawSockaddrAny, addrlen *int32) (errno int) {
 	r1, _, e1 := Syscall(procgetsockname, 3, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if int(r1) == -1 {
 		if e1 != 0 {
@@ -1132,7 +1132,7 @@ func getsockname(s int32, rsa *RawSockaddrAny, addrlen *int32) (errno int) {
 	return
 }
 
-func getpeername(s int32, rsa *RawSockaddrAny, addrlen *int32) (errno int) {
+func getpeername(s Handle, rsa *RawSockaddrAny, addrlen *int32) (errno int) {
 	r1, _, e1 := Syscall(procgetpeername, 3, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if int(r1) == -1 {
 		if e1 != 0 {
@@ -1146,7 +1146,7 @@ func getpeername(s int32, rsa *RawSockaddrAny, addrlen *int32) (errno int) {
 	return
 }
 
-func listen(s int32, backlog int32) (errno int) {
+func listen(s Handle, backlog int32) (errno int) {
 	r1, _, e1 := Syscall(proclisten, 2, uintptr(s), uintptr(backlog), 0)
 	if int(r1) == -1 {
 		if e1 != 0 {
@@ -1160,7 +1160,7 @@ func listen(s int32, backlog int32) (errno int) {
 	return
 }
 
-func shutdown(s int32, how int32) (errno int) {
+func shutdown(s Handle, how int32) (errno int) {
 	r1, _, e1 := Syscall(procshutdown, 2, uintptr(s), uintptr(how), 0)
 	if int(r1) == -1 {
 		if e1 != 0 {
@@ -1174,7 +1174,7 @@ func shutdown(s int32, how int32) (errno int) {
 	return
 }
 
-func Closesocket(s int32) (errno int) {
+func Closesocket(s Handle) (errno int) {
 	r1, _, e1 := Syscall(procclosesocket, 1, uintptr(s), 0, 0)
 	if int(r1) == -1 {
 		if e1 != 0 {
@@ -1188,7 +1188,7 @@ func Closesocket(s int32) (errno int) {
 	return
 }
 
-func AcceptEx(ls uint32, as uint32, buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, recvd *uint32, overlapped *Overlapped) (errno int) {
+func AcceptEx(ls Handle, as Handle, buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, recvd *uint32, overlapped *Overlapped) (errno int) {
 	r1, _, e1 := Syscall9(procAcceptEx, 8, uintptr(ls), uintptr(as), uintptr(unsafe.Pointer(buf)), uintptr(rxdatalen), uintptr(laddrlen), uintptr(raddrlen), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(overlapped)), 0)
 	if int(r1) == 0 {
 		if e1 != 0 {
@@ -1207,7 +1207,7 @@ func GetAcceptExSockaddrs(buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen
 	return
 }
 
-func WSARecv(s uint32, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, overlapped *Overlapped, croutine *byte) (errno int) {
+func WSARecv(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, overlapped *Overlapped, croutine *byte) (errno int) {
 	r1, _, e1 := Syscall9(procWSARecv, 7, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)), 0, 0)
 	if int(r1) == -1 {
 		if e1 != 0 {
@@ -1221,7 +1221,7 @@ func WSARecv(s uint32, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32
 	return
 }
 
-func WSASend(s uint32, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, overlapped *Overlapped, croutine *byte) (errno int) {
+func WSASend(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, overlapped *Overlapped, croutine *byte) (errno int) {
 	r1, _, e1 := Syscall9(procWSASend, 7, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(sent)), uintptr(flags), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)), 0, 0)
 	if int(r1) == -1 {
 		if e1 != 0 {
@@ -1235,7 +1235,7 @@ func WSASend(s uint32, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32,
 	return
 }
 
-func WSARecvFrom(s uint32, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, from *RawSockaddrAny, fromlen *int32, overlapped *Overlapped, croutine *byte) (errno int) {
+func WSARecvFrom(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, from *RawSockaddrAny, fromlen *int32, overlapped *Overlapped, croutine *byte) (errno int) {
 	r1, _, e1 := Syscall9(procWSARecvFrom, 9, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)))
 	if int(r1) == -1 {
 		if e1 != 0 {
@@ -1249,7 +1249,7 @@ func WSARecvFrom(s uint32, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *ui
 	return
 }
 
-func WSASendTo(s uint32, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to *RawSockaddrAny, tolen int32, overlapped *Overlapped, croutine *byte) (errno int) {
+func WSASendTo(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to *RawSockaddrAny, tolen int32, overlapped *Overlapped, croutine *byte) (errno int) {
 	r1, _, e1 := Syscall9(procWSASendTo, 9, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(sent)), uintptr(flags), uintptr(unsafe.Pointer(to)), uintptr(tolen), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)))
 	if int(r1) == -1 {
 		if e1 != 0 {
diff --git a/src/pkg/syscall/zsyscall_windows_amd64.go b/src/pkg/syscall/zsyscall_windows_amd64.go
new file mode 100644
index 0000000..e7d09fb
--- /dev/null
+++ b/src/pkg/syscall/zsyscall_windows_amd64.go
@@ -0,0 +1,1323 @@
+// mksyscall_windows.pl syscall_windows.go syscall_windows_amd64.go
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+package syscall
+
+import "unsafe"
+
+var (
+	modkernel32 = loadDll("kernel32.dll")
+	modadvapi32 = loadDll("advapi32.dll")
+	modshell32  = loadDll("shell32.dll")
+	modwsock32  = loadDll("wsock32.dll")
+	modws2_32   = loadDll("ws2_32.dll")
+	moddnsapi   = loadDll("dnsapi.dll")
+	modiphlpapi = loadDll("iphlpapi.dll")
+
+	procGetLastError               = getSysProcAddr(modkernel32, "GetLastError")
+	procLoadLibraryW               = getSysProcAddr(modkernel32, "LoadLibraryW")
+	procFreeLibrary                = getSysProcAddr(modkernel32, "FreeLibrary")
+	procGetProcAddress             = getSysProcAddr(modkernel32, "GetProcAddress")
+	procGetVersion                 = getSysProcAddr(modkernel32, "GetVersion")
+	procFormatMessageW             = getSysProcAddr(modkernel32, "FormatMessageW")
+	procExitProcess                = getSysProcAddr(modkernel32, "ExitProcess")
+	procCreateFileW                = getSysProcAddr(modkernel32, "CreateFileW")
+	procReadFile                   = getSysProcAddr(modkernel32, "ReadFile")
+	procWriteFile                  = getSysProcAddr(modkernel32, "WriteFile")
+	procSetFilePointer             = getSysProcAddr(modkernel32, "SetFilePointer")
+	procCloseHandle                = getSysProcAddr(modkernel32, "CloseHandle")
+	procGetStdHandle               = getSysProcAddr(modkernel32, "GetStdHandle")
+	procFindFirstFileW             = getSysProcAddr(modkernel32, "FindFirstFileW")
+	procFindNextFileW              = getSysProcAddr(modkernel32, "FindNextFileW")
+	procFindClose                  = getSysProcAddr(modkernel32, "FindClose")
+	procGetFileInformationByHandle = getSysProcAddr(modkernel32, "GetFileInformationByHandle")
+	procGetCurrentDirectoryW       = getSysProcAddr(modkernel32, "GetCurrentDirectoryW")
+	procSetCurrentDirectoryW       = getSysProcAddr(modkernel32, "SetCurrentDirectoryW")
+	procCreateDirectoryW           = getSysProcAddr(modkernel32, "CreateDirectoryW")
+	procRemoveDirectoryW           = getSysProcAddr(modkernel32, "RemoveDirectoryW")
+	procDeleteFileW                = getSysProcAddr(modkernel32, "DeleteFileW")
+	procMoveFileW                  = getSysProcAddr(modkernel32, "MoveFileW")
+	procGetComputerNameW           = getSysProcAddr(modkernel32, "GetComputerNameW")
+	procSetEndOfFile               = getSysProcAddr(modkernel32, "SetEndOfFile")
+	procGetSystemTimeAsFileTime    = getSysProcAddr(modkernel32, "GetSystemTimeAsFileTime")
+	procSleep                      = getSysProcAddr(modkernel32, "Sleep")
+	procGetTimeZoneInformation     = getSysProcAddr(modkernel32, "GetTimeZoneInformation")
+	procCreateIoCompletionPort     = getSysProcAddr(modkernel32, "CreateIoCompletionPort")
+	procGetQueuedCompletionStatus  = getSysProcAddr(modkernel32, "GetQueuedCompletionStatus")
+	procCancelIo                   = getSysProcAddr(modkernel32, "CancelIo")
+	procCreateProcessW             = getSysProcAddr(modkernel32, "CreateProcessW")
+	procOpenProcess                = getSysProcAddr(modkernel32, "OpenProcess")
+	procTerminateProcess           = getSysProcAddr(modkernel32, "TerminateProcess")
+	procGetExitCodeProcess         = getSysProcAddr(modkernel32, "GetExitCodeProcess")
+	procGetStartupInfoW            = getSysProcAddr(modkernel32, "GetStartupInfoW")
+	procGetCurrentProcess          = getSysProcAddr(modkernel32, "GetCurrentProcess")
+	procDuplicateHandle            = getSysProcAddr(modkernel32, "DuplicateHandle")
+	procWaitForSingleObject        = getSysProcAddr(modkernel32, "WaitForSingleObject")
+	procGetTempPathW               = getSysProcAddr(modkernel32, "GetTempPathW")
+	procCreatePipe                 = getSysProcAddr(modkernel32, "CreatePipe")
+	procGetFileType                = getSysProcAddr(modkernel32, "GetFileType")
+	procCryptAcquireContextW       = getSysProcAddr(modadvapi32, "CryptAcquireContextW")
+	procCryptReleaseContext        = getSysProcAddr(modadvapi32, "CryptReleaseContext")
+	procCryptGenRandom             = getSysProcAddr(modadvapi32, "CryptGenRandom")
+	procGetEnvironmentStringsW     = getSysProcAddr(modkernel32, "GetEnvironmentStringsW")
+	procFreeEnvironmentStringsW    = getSysProcAddr(modkernel32, "FreeEnvironmentStringsW")
+	procGetEnvironmentVariableW    = getSysProcAddr(modkernel32, "GetEnvironmentVariableW")
+	procSetEnvironmentVariableW    = getSysProcAddr(modkernel32, "SetEnvironmentVariableW")
+	procSetFileTime                = getSysProcAddr(modkernel32, "SetFileTime")
+	procGetFileAttributesW         = getSysProcAddr(modkernel32, "GetFileAttributesW")
+	procSetFileAttributesW         = getSysProcAddr(modkernel32, "SetFileAttributesW")
+	procGetCommandLineW            = getSysProcAddr(modkernel32, "GetCommandLineW")
+	procCommandLineToArgvW         = getSysProcAddr(modshell32, "CommandLineToArgvW")
+	procLocalFree                  = getSysProcAddr(modkernel32, "LocalFree")
+	procSetHandleInformation       = getSysProcAddr(modkernel32, "SetHandleInformation")
+	procFlushFileBuffers           = getSysProcAddr(modkernel32, "FlushFileBuffers")
+	procGetFullPathNameW           = getSysProcAddr(modkernel32, "GetFullPathNameW")
+	procCreateFileMappingW         = getSysProcAddr(modkernel32, "CreateFileMappingW")
+	procMapViewOfFile              = getSysProcAddr(modkernel32, "MapViewOfFile")
+	procUnmapViewOfFile            = getSysProcAddr(modkernel32, "UnmapViewOfFile")
+	procFlushViewOfFile            = getSysProcAddr(modkernel32, "FlushViewOfFile")
+	procVirtualLock                = getSysProcAddr(modkernel32, "VirtualLock")
+	procVirtualUnlock              = getSysProcAddr(modkernel32, "VirtualUnlock")
+	procTransmitFile               = getSysProcAddr(modwsock32, "TransmitFile")
+	procWSAStartup                 = getSysProcAddr(modwsock32, "WSAStartup")
+	procWSACleanup                 = getSysProcAddr(modwsock32, "WSACleanup")
+	procWSAIoctl                   = getSysProcAddr(modws2_32, "WSAIoctl")
+	procsocket                     = getSysProcAddr(modwsock32, "socket")
+	procsetsockopt                 = getSysProcAddr(modwsock32, "setsockopt")
+	procbind                       = getSysProcAddr(modwsock32, "bind")
+	procconnect                    = getSysProcAddr(modwsock32, "connect")
+	procgetsockname                = getSysProcAddr(modwsock32, "getsockname")
+	procgetpeername                = getSysProcAddr(modwsock32, "getpeername")
+	proclisten                     = getSysProcAddr(modwsock32, "listen")
+	procshutdown                   = getSysProcAddr(modwsock32, "shutdown")
+	procclosesocket                = getSysProcAddr(modwsock32, "closesocket")
+	procAcceptEx                   = getSysProcAddr(modwsock32, "AcceptEx")
+	procGetAcceptExSockaddrs       = getSysProcAddr(modwsock32, "GetAcceptExSockaddrs")
+	procWSARecv                    = getSysProcAddr(modws2_32, "WSARecv")
+	procWSASend                    = getSysProcAddr(modws2_32, "WSASend")
+	procWSARecvFrom                = getSysProcAddr(modws2_32, "WSARecvFrom")
+	procWSASendTo                  = getSysProcAddr(modws2_32, "WSASendTo")
+	procgethostbyname              = getSysProcAddr(modws2_32, "gethostbyname")
+	procgetservbyname              = getSysProcAddr(modws2_32, "getservbyname")
+	procntohs                      = getSysProcAddr(modws2_32, "ntohs")
+	procDnsQuery_W                 = getSysProcAddr(moddnsapi, "DnsQuery_W")
+	procDnsRecordListFree          = getSysProcAddr(moddnsapi, "DnsRecordListFree")
+	procGetIfEntry                 = getSysProcAddr(modiphlpapi, "GetIfEntry")
+	procGetAdaptersInfo            = getSysProcAddr(modiphlpapi, "GetAdaptersInfo")
+)
+
+func GetLastError() (lasterrno int) {
+	r0, _, _ := Syscall(procGetLastError, 0, 0, 0, 0)
+	lasterrno = int(r0)
+	return
+}
+
+func LoadLibrary(libname string) (handle Handle, errno int) {
+	r0, _, e1 := Syscall(procLoadLibraryW, 1, uintptr(unsafe.Pointer(StringToUTF16Ptr(libname))), 0, 0)
+	handle = Handle(r0)
+	if handle == 0 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func FreeLibrary(handle Handle) (errno int) {
+	r1, _, e1 := Syscall(procFreeLibrary, 1, uintptr(handle), 0, 0)
+	if int(r1) == 0 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func GetProcAddress(module Handle, procname string) (proc Handle, errno int) {
+	r0, _, e1 := Syscall(procGetProcAddress, 2, uintptr(module), uintptr(unsafe.Pointer(StringBytePtr(procname))), 0)
+	proc = Handle(r0)
+	if proc == 0 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func GetVersion() (ver uint32, errno int) {
+	r0, _, e1 := Syscall(procGetVersion, 0, 0, 0, 0)
+	ver = uint32(r0)
+	if ver == 0 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func FormatMessage(flags uint32, msgsrc uint32, msgid uint32, langid uint32, buf []uint16, args *byte) (n uint32, errno int) {
+	var _p0 *uint16
+	if len(buf) > 0 {
+		_p0 = &buf[0]
+	}
+	r0, _, e1 := Syscall9(procFormatMessageW, 7, uintptr(flags), uintptr(msgsrc), uintptr(msgid), uintptr(langid), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(args)), 0, 0)
+	n = uint32(r0)
+	if n == 0 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func ExitProcess(exitcode uint32) {
+	Syscall(procExitProcess, 1, uintptr(exitcode), 0, 0)
+	return
+}
+
+func CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile int32) (handle Handle, errno int) {
+	r0, _, e1 := Syscall9(procCreateFileW, 7, uintptr(unsafe.Pointer(name)), uintptr(access), uintptr(mode), uintptr(unsafe.Pointer(sa)), uintptr(createmode), uintptr(attrs), uintptr(templatefile), 0, 0)
+	handle = Handle(r0)
+	if handle == InvalidHandle {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func ReadFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (errno int) {
+	var _p0 *byte
+	if len(buf) > 0 {
+		_p0 = &buf[0]
+	}
+	r1, _, e1 := Syscall6(procReadFile, 5, uintptr(handle), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(done)), uintptr(unsafe.Pointer(overlapped)), 0)
+	if int(r1) == 0 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func WriteFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (errno int) {
+	var _p0 *byte
+	if len(buf) > 0 {
+		_p0 = &buf[0]
+	}
+	r1, _, e1 := Syscall6(procWriteFile, 5, uintptr(handle), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(done)), uintptr(unsafe.Pointer(overlapped)), 0)
+	if int(r1) == 0 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func SetFilePointer(handle Handle, lowoffset int32, highoffsetptr *int32, whence uint32) (newlowoffset uint32, errno int) {
+	r0, _, e1 := Syscall6(procSetFilePointer, 4, uintptr(handle), uintptr(lowoffset), uintptr(unsafe.Pointer(highoffsetptr)), uintptr(whence), 0, 0)
+	newlowoffset = uint32(r0)
+	if newlowoffset == 0xffffffff {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func CloseHandle(handle Handle) (errno int) {
+	r1, _, e1 := Syscall(procCloseHandle, 1, uintptr(handle), 0, 0)
+	if int(r1) == 0 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func GetStdHandle(stdhandle int) (handle Handle, errno int) {
+	r0, _, e1 := Syscall(procGetStdHandle, 1, uintptr(stdhandle), 0, 0)
+	handle = Handle(r0)
+	if handle == InvalidHandle {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func FindFirstFile(name *uint16, data *Win32finddata) (handle Handle, errno int) {
+	r0, _, e1 := Syscall(procFindFirstFileW, 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(data)), 0)
+	handle = Handle(r0)
+	if handle == InvalidHandle {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func FindNextFile(handle Handle, data *Win32finddata) (errno int) {
+	r1, _, e1 := Syscall(procFindNextFileW, 2, uintptr(handle), uintptr(unsafe.Pointer(data)), 0)
+	if int(r1) == 0 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func FindClose(handle Handle) (errno int) {
+	r1, _, e1 := Syscall(procFindClose, 1, uintptr(handle), 0, 0)
+	if int(r1) == 0 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func GetFileInformationByHandle(handle Handle, data *ByHandleFileInformation) (errno int) {
+	r1, _, e1 := Syscall(procGetFileInformationByHandle, 2, uintptr(handle), uintptr(unsafe.Pointer(data)), 0)
+	if int(r1) == 0 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func GetCurrentDirectory(buflen uint32, buf *uint16) (n uint32, errno int) {
+	r0, _, e1 := Syscall(procGetCurrentDirectoryW, 2, uintptr(buflen), uintptr(unsafe.Pointer(buf)), 0)
+	n = uint32(r0)
+	if n == 0 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func SetCurrentDirectory(path *uint16) (errno int) {
+	r1, _, e1 := Syscall(procSetCurrentDirectoryW, 1, uintptr(unsafe.Pointer(path)), 0, 0)
+	if int(r1) == 0 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func CreateDirectory(path *uint16, sa *SecurityAttributes) (errno int) {
+	r1, _, e1 := Syscall(procCreateDirectoryW, 2, uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(sa)), 0)
+	if int(r1) == 0 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func RemoveDirectory(path *uint16) (errno int) {
+	r1, _, e1 := Syscall(procRemoveDirectoryW, 1, uintptr(unsafe.Pointer(path)), 0, 0)
+	if int(r1) == 0 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func DeleteFile(path *uint16) (errno int) {
+	r1, _, e1 := Syscall(procDeleteFileW, 1, uintptr(unsafe.Pointer(path)), 0, 0)
+	if int(r1) == 0 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func MoveFile(from *uint16, to *uint16) (errno int) {
+	r1, _, e1 := Syscall(procMoveFileW, 2, uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(to)), 0)
+	if int(r1) == 0 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func GetComputerName(buf *uint16, n *uint32) (errno int) {
+	r1, _, e1 := Syscall(procGetComputerNameW, 2, uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(n)), 0)
+	if int(r1) == 0 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func SetEndOfFile(handle Handle) (errno int) {
+	r1, _, e1 := Syscall(procSetEndOfFile, 1, uintptr(handle), 0, 0)
+	if int(r1) == 0 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func GetSystemTimeAsFileTime(time *Filetime) {
+	Syscall(procGetSystemTimeAsFileTime, 1, uintptr(unsafe.Pointer(time)), 0, 0)
+	return
+}
+
+func sleep(msec uint32) {
+	Syscall(procSleep, 1, uintptr(msec), 0, 0)
+	return
+}
+
+func GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, errno int) {
+	r0, _, e1 := Syscall(procGetTimeZoneInformation, 1, uintptr(unsafe.Pointer(tzi)), 0, 0)
+	rc = uint32(r0)
+	if rc == 0xffffffff {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func CreateIoCompletionPort(filehandle Handle, cphandle Handle, key uint32, threadcnt uint32) (handle Handle, errno int) {
+	r0, _, e1 := Syscall6(procCreateIoCompletionPort, 4, uintptr(filehandle), uintptr(cphandle), uintptr(key), uintptr(threadcnt), 0, 0)
+	handle = Handle(r0)
+	if handle == 0 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func GetQueuedCompletionStatus(cphandle Handle, qty *uint32, key *uint32, overlapped **Overlapped, timeout uint32) (errno int) {
+	r1, _, e1 := Syscall6(procGetQueuedCompletionStatus, 5, uintptr(cphandle), uintptr(unsafe.Pointer(qty)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(overlapped)), uintptr(timeout), 0)
+	if int(r1) == 0 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func CancelIo(s Handle) (errno int) {
+	r1, _, e1 := Syscall(procCancelIo, 1, uintptr(s), 0, 0)
+	if int(r1) == 0 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func CreateProcess(appName *uint16, commandLine *uint16, procSecurity *SecurityAttributes, threadSecurity *SecurityAttributes, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation) (errno int) {
+	var _p0 uint32
+	if inheritHandles {
+		_p0 = 1
+	} else {
+		_p0 = 0
+	}
+	r1, _, e1 := Syscall12(procCreateProcessW, 10, uintptr(unsafe.Pointer(appName)), uintptr(unsafe.Pointer(commandLine)), uintptr(unsafe.Pointer(procSecurity)), uintptr(unsafe.Pointer(threadSecurity)), uintptr(_p0), uintptr(creationFlags), uintptr(unsafe.Pointer(env)), uintptr(unsafe.Pointer(currentDir)), uintptr(unsafe.Pointer(startupInfo)), uintptr(unsafe.Pointer(outProcInfo)), 0, 0)
+	if int(r1) == 0 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func OpenProcess(da uint32, inheritHandle bool, pid uint32) (handle Handle, errno int) {
+	var _p0 uint32
+	if inheritHandle {
+		_p0 = 1
+	} else {
+		_p0 = 0
+	}
+	r0, _, e1 := Syscall(procOpenProcess, 3, uintptr(da), uintptr(_p0), uintptr(pid))
+	handle = Handle(r0)
+	if handle == 0 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func TerminateProcess(handle Handle, exitcode uint32) (errno int) {
+	r1, _, e1 := Syscall(procTerminateProcess, 2, uintptr(handle), uintptr(exitcode), 0)
+	if int(r1) == 0 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func GetExitCodeProcess(handle Handle, exitcode *uint32) (errno int) {
+	r1, _, e1 := Syscall(procGetExitCodeProcess, 2, uintptr(handle), uintptr(unsafe.Pointer(exitcode)), 0)
+	if int(r1) == 0 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func GetStartupInfo(startupInfo *StartupInfo) (errno int) {
+	r1, _, e1 := Syscall(procGetStartupInfoW, 1, uintptr(unsafe.Pointer(startupInfo)), 0, 0)
+	if int(r1) == 0 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func GetCurrentProcess() (pseudoHandle Handle, errno int) {
+	r0, _, e1 := Syscall(procGetCurrentProcess, 0, 0, 0, 0)
+	pseudoHandle = Handle(r0)
+	if pseudoHandle == 0 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func DuplicateHandle(hSourceProcessHandle Handle, hSourceHandle Handle, hTargetProcessHandle Handle, lpTargetHandle *Handle, dwDesiredAccess uint32, bInheritHandle bool, dwOptions uint32) (errno int) {
+	var _p0 uint32
+	if bInheritHandle {
+		_p0 = 1
+	} else {
+		_p0 = 0
+	}
+	r1, _, e1 := Syscall9(procDuplicateHandle, 7, uintptr(hSourceProcessHandle), uintptr(hSourceHandle), uintptr(hTargetProcessHandle), uintptr(unsafe.Pointer(lpTargetHandle)), uintptr(dwDesiredAccess), uintptr(_p0), uintptr(dwOptions), 0, 0)
+	if int(r1) == 0 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func WaitForSingleObject(handle Handle, waitMilliseconds uint32) (event uint32, errno int) {
+	r0, _, e1 := Syscall(procWaitForSingleObject, 2, uintptr(handle), uintptr(waitMilliseconds), 0)
+	event = uint32(r0)
+	if event == 0xffffffff {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func GetTempPath(buflen uint32, buf *uint16) (n uint32, errno int) {
+	r0, _, e1 := Syscall(procGetTempPathW, 2, uintptr(buflen), uintptr(unsafe.Pointer(buf)), 0)
+	n = uint32(r0)
+	if n == 0 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func CreatePipe(readhandle *Handle, writehandle *Handle, sa *SecurityAttributes, size uint32) (errno int) {
+	r1, _, e1 := Syscall6(procCreatePipe, 4, uintptr(unsafe.Pointer(readhandle)), uintptr(unsafe.Pointer(writehandle)), uintptr(unsafe.Pointer(sa)), uintptr(size), 0, 0)
+	if int(r1) == 0 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func GetFileType(filehandle Handle) (n uint32, errno int) {
+	r0, _, e1 := Syscall(procGetFileType, 1, uintptr(filehandle), 0, 0)
+	n = uint32(r0)
+	if n == 0 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func CryptAcquireContext(provhandle *Handle, container *uint16, provider *uint16, provtype uint32, flags uint32) (errno int) {
+	r1, _, e1 := Syscall6(procCryptAcquireContextW, 5, uintptr(unsafe.Pointer(provhandle)), uintptr(unsafe.Pointer(container)), uintptr(unsafe.Pointer(provider)), uintptr(provtype), uintptr(flags), 0)
+	if int(r1) == 0 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func CryptReleaseContext(provhandle Handle, flags uint32) (errno int) {
+	r1, _, e1 := Syscall(procCryptReleaseContext, 2, uintptr(provhandle), uintptr(flags), 0)
+	if int(r1) == 0 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func CryptGenRandom(provhandle Handle, buflen uint32, buf *byte) (errno int) {
+	r1, _, e1 := Syscall(procCryptGenRandom, 3, uintptr(provhandle), uintptr(buflen), uintptr(unsafe.Pointer(buf)))
+	if int(r1) == 0 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func GetEnvironmentStrings() (envs *uint16, errno int) {
+	r0, _, e1 := Syscall(procGetEnvironmentStringsW, 0, 0, 0, 0)
+	envs = (*uint16)(unsafe.Pointer(r0))
+	if envs == nil {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func FreeEnvironmentStrings(envs *uint16) (errno int) {
+	r1, _, e1 := Syscall(procFreeEnvironmentStringsW, 1, uintptr(unsafe.Pointer(envs)), 0, 0)
+	if int(r1) == 0 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func GetEnvironmentVariable(name *uint16, buffer *uint16, size uint32) (n uint32, errno int) {
+	r0, _, e1 := Syscall(procGetEnvironmentVariableW, 3, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(buffer)), uintptr(size))
+	n = uint32(r0)
+	if n == 0 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func SetEnvironmentVariable(name *uint16, value *uint16) (errno int) {
+	r1, _, e1 := Syscall(procSetEnvironmentVariableW, 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(value)), 0)
+	if int(r1) == 0 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func SetFileTime(handle Handle, ctime *Filetime, atime *Filetime, wtime *Filetime) (errno int) {
+	r1, _, e1 := Syscall6(procSetFileTime, 4, uintptr(handle), uintptr(unsafe.Pointer(ctime)), uintptr(unsafe.Pointer(atime)), uintptr(unsafe.Pointer(wtime)), 0, 0)
+	if int(r1) == 0 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func GetFileAttributes(name *uint16) (attrs uint32, errno int) {
+	r0, _, e1 := Syscall(procGetFileAttributesW, 1, uintptr(unsafe.Pointer(name)), 0, 0)
+	attrs = uint32(r0)
+	if attrs == INVALID_FILE_ATTRIBUTES {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func SetFileAttributes(name *uint16, attrs uint32) (errno int) {
+	r1, _, e1 := Syscall(procSetFileAttributesW, 2, uintptr(unsafe.Pointer(name)), uintptr(attrs), 0)
+	if int(r1) == 0 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func GetCommandLine() (cmd *uint16) {
+	r0, _, _ := Syscall(procGetCommandLineW, 0, 0, 0, 0)
+	cmd = (*uint16)(unsafe.Pointer(r0))
+	return
+}
+
+func CommandLineToArgv(cmd *uint16, argc *int32) (argv *[8192]*[8192]uint16, errno int) {
+	r0, _, e1 := Syscall(procCommandLineToArgvW, 2, uintptr(unsafe.Pointer(cmd)), uintptr(unsafe.Pointer(argc)), 0)
+	argv = (*[8192]*[8192]uint16)(unsafe.Pointer(r0))
+	if argv == nil {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func LocalFree(hmem Handle) (handle Handle, errno int) {
+	r0, _, e1 := Syscall(procLocalFree, 1, uintptr(hmem), 0, 0)
+	handle = Handle(r0)
+	if handle != 0 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func SetHandleInformation(handle Handle, mask uint32, flags uint32) (errno int) {
+	r1, _, e1 := Syscall(procSetHandleInformation, 3, uintptr(handle), uintptr(mask), uintptr(flags))
+	if int(r1) == 0 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func FlushFileBuffers(handle Handle) (errno int) {
+	r1, _, e1 := Syscall(procFlushFileBuffers, 1, uintptr(handle), 0, 0)
+	if int(r1) == 0 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func GetFullPathName(path *uint16, buflen uint32, buf *uint16, fname **uint16) (n uint32, errno int) {
+	r0, _, e1 := Syscall6(procGetFullPathNameW, 4, uintptr(unsafe.Pointer(path)), uintptr(buflen), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(fname)), 0, 0)
+	n = uint32(r0)
+	if n == 0 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func CreateFileMapping(fhandle Handle, sa *SecurityAttributes, prot uint32, maxSizeHigh uint32, maxSizeLow uint32, name *uint16) (handle Handle, errno int) {
+	r0, _, e1 := Syscall6(procCreateFileMappingW, 6, uintptr(fhandle), uintptr(unsafe.Pointer(sa)), uintptr(prot), uintptr(maxSizeHigh), uintptr(maxSizeLow), uintptr(unsafe.Pointer(name)))
+	handle = Handle(r0)
+	if handle == 0 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func MapViewOfFile(handle Handle, access uint32, offsetHigh uint32, offsetLow uint32, length uintptr) (addr uintptr, errno int) {
+	r0, _, e1 := Syscall6(procMapViewOfFile, 5, uintptr(handle), uintptr(access), uintptr(offsetHigh), uintptr(offsetLow), uintptr(length), 0)
+	addr = uintptr(r0)
+	if addr == 0 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func UnmapViewOfFile(addr uintptr) (errno int) {
+	r1, _, e1 := Syscall(procUnmapViewOfFile, 1, uintptr(addr), 0, 0)
+	if int(r1) == 0 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func FlushViewOfFile(addr uintptr, length uintptr) (errno int) {
+	r1, _, e1 := Syscall(procFlushViewOfFile, 2, uintptr(addr), uintptr(length), 0)
+	if int(r1) == 0 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func VirtualLock(addr uintptr, length uintptr) (errno int) {
+	r1, _, e1 := Syscall(procVirtualLock, 2, uintptr(addr), uintptr(length), 0)
+	if int(r1) == 0 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func VirtualUnlock(addr uintptr, length uintptr) (errno int) {
+	r1, _, e1 := Syscall(procVirtualUnlock, 2, uintptr(addr), uintptr(length), 0)
+	if int(r1) == 0 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func TransmitFile(s Handle, handle Handle, bytesToWrite uint32, bytsPerSend uint32, overlapped *Overlapped, transmitFileBuf *TransmitFileBuffers, flags uint32) (errno int) {
+	r1, _, e1 := Syscall9(procTransmitFile, 7, uintptr(s), uintptr(handle), uintptr(bytesToWrite), uintptr(bytsPerSend), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(transmitFileBuf)), uintptr(flags), 0, 0)
+	if int(r1) == 0 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func WSAStartup(verreq uint32, data *WSAData) (sockerrno int) {
+	r0, _, _ := Syscall(procWSAStartup, 2, uintptr(verreq), uintptr(unsafe.Pointer(data)), 0)
+	sockerrno = int(r0)
+	return
+}
+
+func WSACleanup() (errno int) {
+	r1, _, e1 := Syscall(procWSACleanup, 0, 0, 0, 0)
+	if int(r1) == -1 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func WSAIoctl(s Handle, iocc uint32, inbuf *byte, cbif uint32, outbuf *byte, cbob uint32, cbbr *uint32, overlapped *Overlapped, completionRoutine uintptr) (errno int) {
+	r1, _, e1 := Syscall9(procWSAIoctl, 9, uintptr(s), uintptr(iocc), uintptr(unsafe.Pointer(inbuf)), uintptr(cbif), uintptr(unsafe.Pointer(outbuf)), uintptr(cbob), uintptr(unsafe.Pointer(cbbr)), uintptr(unsafe.Pointer(overlapped)), uintptr(completionRoutine))
+	if int(r1) == -1 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func socket(af int32, typ int32, protocol int32) (handle Handle, errno int) {
+	r0, _, e1 := Syscall(procsocket, 3, uintptr(af), uintptr(typ), uintptr(protocol))
+	handle = Handle(r0)
+	if handle == InvalidHandle {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func setsockopt(s Handle, level int32, optname int32, optval *byte, optlen int32) (errno int) {
+	r1, _, e1 := Syscall6(procsetsockopt, 5, uintptr(s), uintptr(level), uintptr(optname), uintptr(unsafe.Pointer(optval)), uintptr(optlen), 0)
+	if int(r1) == -1 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func bind(s Handle, name uintptr, namelen int32) (errno int) {
+	r1, _, e1 := Syscall(procbind, 3, uintptr(s), uintptr(name), uintptr(namelen))
+	if int(r1) == -1 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func connect(s Handle, name uintptr, namelen int32) (errno int) {
+	r1, _, e1 := Syscall(procconnect, 3, uintptr(s), uintptr(name), uintptr(namelen))
+	if int(r1) == -1 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func getsockname(s Handle, rsa *RawSockaddrAny, addrlen *int32) (errno int) {
+	r1, _, e1 := Syscall(procgetsockname, 3, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
+	if int(r1) == -1 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func getpeername(s Handle, rsa *RawSockaddrAny, addrlen *int32) (errno int) {
+	r1, _, e1 := Syscall(procgetpeername, 3, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
+	if int(r1) == -1 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func listen(s Handle, backlog int32) (errno int) {
+	r1, _, e1 := Syscall(proclisten, 2, uintptr(s), uintptr(backlog), 0)
+	if int(r1) == -1 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func shutdown(s Handle, how int32) (errno int) {
+	r1, _, e1 := Syscall(procshutdown, 2, uintptr(s), uintptr(how), 0)
+	if int(r1) == -1 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func Closesocket(s Handle) (errno int) {
+	r1, _, e1 := Syscall(procclosesocket, 1, uintptr(s), 0, 0)
+	if int(r1) == -1 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func AcceptEx(ls Handle, as Handle, buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, recvd *uint32, overlapped *Overlapped) (errno int) {
+	r1, _, e1 := Syscall9(procAcceptEx, 8, uintptr(ls), uintptr(as), uintptr(unsafe.Pointer(buf)), uintptr(rxdatalen), uintptr(laddrlen), uintptr(raddrlen), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(overlapped)), 0)
+	if int(r1) == 0 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func GetAcceptExSockaddrs(buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, lrsa **RawSockaddrAny, lrsalen *int32, rrsa **RawSockaddrAny, rrsalen *int32) {
+	Syscall9(procGetAcceptExSockaddrs, 8, uintptr(unsafe.Pointer(buf)), uintptr(rxdatalen), uintptr(laddrlen), uintptr(raddrlen), uintptr(unsafe.Pointer(lrsa)), uintptr(unsafe.Pointer(lrsalen)), uintptr(unsafe.Pointer(rrsa)), uintptr(unsafe.Pointer(rrsalen)), 0)
+	return
+}
+
+func WSARecv(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, overlapped *Overlapped, croutine *byte) (errno int) {
+	r1, _, e1 := Syscall9(procWSARecv, 7, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)), 0, 0)
+	if int(r1) == -1 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func WSASend(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, overlapped *Overlapped, croutine *byte) (errno int) {
+	r1, _, e1 := Syscall9(procWSASend, 7, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(sent)), uintptr(flags), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)), 0, 0)
+	if int(r1) == -1 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func WSARecvFrom(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, from *RawSockaddrAny, fromlen *int32, overlapped *Overlapped, croutine *byte) (errno int) {
+	r1, _, e1 := Syscall9(procWSARecvFrom, 9, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)))
+	if int(r1) == -1 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func WSASendTo(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to *RawSockaddrAny, tolen int32, overlapped *Overlapped, croutine *byte) (errno int) {
+	r1, _, e1 := Syscall9(procWSASendTo, 9, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(sent)), uintptr(flags), uintptr(unsafe.Pointer(to)), uintptr(tolen), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)))
+	if int(r1) == -1 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func GetHostByName(name string) (h *Hostent, errno int) {
+	r0, _, e1 := Syscall(procgethostbyname, 1, uintptr(unsafe.Pointer(StringBytePtr(name))), 0, 0)
+	h = (*Hostent)(unsafe.Pointer(r0))
+	if h == nil {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func GetServByName(name string, proto string) (s *Servent, errno int) {
+	r0, _, e1 := Syscall(procgetservbyname, 2, uintptr(unsafe.Pointer(StringBytePtr(name))), uintptr(unsafe.Pointer(StringBytePtr(proto))), 0)
+	s = (*Servent)(unsafe.Pointer(r0))
+	if s == nil {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func Ntohs(netshort uint16) (u uint16) {
+	r0, _, _ := Syscall(procntohs, 1, uintptr(netshort), 0, 0)
+	u = uint16(r0)
+	return
+}
+
+func DnsQuery(name string, qtype uint16, options uint32, extra *byte, qrs **DNSRecord, pr *byte) (status uint32) {
+	r0, _, _ := Syscall6(procDnsQuery_W, 6, uintptr(unsafe.Pointer(StringToUTF16Ptr(name))), uintptr(qtype), uintptr(options), uintptr(unsafe.Pointer(extra)), uintptr(unsafe.Pointer(qrs)), uintptr(unsafe.Pointer(pr)))
+	status = uint32(r0)
+	return
+}
+
+func DnsRecordListFree(rl *DNSRecord, freetype uint32) {
+	Syscall(procDnsRecordListFree, 2, uintptr(unsafe.Pointer(rl)), uintptr(freetype), 0)
+	return
+}
+
+func GetIfEntry(pIfRow *MibIfRow) (errcode int) {
+	r0, _, _ := Syscall(procGetIfEntry, 1, uintptr(unsafe.Pointer(pIfRow)), 0, 0)
+	errcode = int(r0)
+	return
+}
+
+func GetAdaptersInfo(ai *IpAdapterInfo, ol *uint32) (errcode int) {
+	r0, _, _ := Syscall(procGetAdaptersInfo, 2, uintptr(unsafe.Pointer(ai)), uintptr(unsafe.Pointer(ol)), 0)
+	errcode = int(r0)
+	return
+}
diff --git a/src/pkg/syscall/zsysnum_windows_386.go b/src/pkg/syscall/zsysnum_windows_amd64.go
similarity index 100%
copy from src/pkg/syscall/zsysnum_windows_386.go
copy to src/pkg/syscall/zsysnum_windows_amd64.go
diff --git a/src/pkg/syscall/ztypes_windows.go b/src/pkg/syscall/ztypes_windows.go
new file mode 100644
index 0000000..1a264a4
--- /dev/null
+++ b/src/pkg/syscall/ztypes_windows.go
@@ -0,0 +1,656 @@
+package syscall
+
+// TODO(brainman): autogenerate types in ztypes_windows_386.go
+
+//import "unsafe"
+
+// Constants
+const (
+	sizeofPtr      = 0x4
+	sizeofShort    = 0x2
+	sizeofInt      = 0x4
+	sizeofLong     = 0x4
+	sizeofLongLong = 0x8
+	PathMax        = 0x1000
+	SizeofLinger   = 0x8
+	SizeofMsghdr   = 0x1c
+	SizeofCmsghdr  = 0xc
+)
+
+const (
+	// Windows errors.
+	ERROR_FILE_NOT_FOUND      = 2
+	ERROR_PATH_NOT_FOUND      = 3
+	ERROR_NO_MORE_FILES       = 18
+	ERROR_BROKEN_PIPE         = 109
+	ERROR_BUFFER_OVERFLOW     = 111
+	ERROR_INSUFFICIENT_BUFFER = 122
+	ERROR_MOD_NOT_FOUND       = 126
+	ERROR_PROC_NOT_FOUND      = 127
+	ERROR_ENVVAR_NOT_FOUND    = 203
+	ERROR_DIRECTORY           = 267
+	ERROR_OPERATION_ABORTED   = 995
+	ERROR_IO_PENDING          = 997
+)
+
+const (
+	// Invented values to support what package os expects.
+	O_RDONLY   = 0x00000
+	O_WRONLY   = 0x00001
+	O_RDWR     = 0x00002
+	O_CREAT    = 0x00040
+	O_EXCL     = 0x00080
+	O_NOCTTY   = 0x00100
+	O_TRUNC    = 0x00200
+	O_NONBLOCK = 0x00800
+	O_APPEND   = 0x00400
+	O_SYNC     = 0x01000
+	O_ASYNC    = 0x02000
+	O_CLOEXEC  = 0x80000
+)
+
+const (
+	// More invented values for signals
+	SIGHUP  = 0x1
+	SIGINT  = 0x2
+	SIGQUIT = 0x3
+	SIGILL  = 0x4
+	SIGTRAP = 0x5
+	SIGABRT = 0x6
+	SIGBUS  = 0x7
+	SIGFPE  = 0x8
+	SIGKILL = 0x9
+	SIGSEGV = 0xb
+	SIGPIPE = 0xd
+	SIGALRM = 0xe
+	SIGTERM = 0xf
+)
+
+const (
+	GENERIC_READ    = 0x80000000
+	GENERIC_WRITE   = 0x40000000
+	GENERIC_EXECUTE = 0x20000000
+	GENERIC_ALL     = 0x10000000
+
+	FILE_APPEND_DATA      = 0x00000004
+	FILE_WRITE_ATTRIBUTES = 0x00000100
+
+	FILE_SHARE_READ          = 0x00000001
+	FILE_SHARE_WRITE         = 0x00000002
+	FILE_SHARE_DELETE        = 0x00000004
+	FILE_ATTRIBUTE_READONLY  = 0x00000001
+	FILE_ATTRIBUTE_HIDDEN    = 0x00000002
+	FILE_ATTRIBUTE_SYSTEM    = 0x00000004
+	FILE_ATTRIBUTE_DIRECTORY = 0x00000010
+	FILE_ATTRIBUTE_ARCHIVE   = 0x00000020
+	FILE_ATTRIBUTE_NORMAL    = 0x00000080
+
+	INVALID_FILE_ATTRIBUTES = 0xffffffff
+
+	CREATE_NEW        = 1
+	CREATE_ALWAYS     = 2
+	OPEN_EXISTING     = 3
+	OPEN_ALWAYS       = 4
+	TRUNCATE_EXISTING = 5
+
+	HANDLE_FLAG_INHERIT    = 0x00000001
+	STARTF_USESTDHANDLES   = 0x00000100
+	STARTF_USESHOWWINDOW   = 0x00000001
+	DUPLICATE_CLOSE_SOURCE = 0x00000001
+	DUPLICATE_SAME_ACCESS  = 0x00000002
+
+	STD_INPUT_HANDLE  = -10
+	STD_OUTPUT_HANDLE = -11
+	STD_ERROR_HANDLE  = -12
+
+	FILE_BEGIN   = 0
+	FILE_CURRENT = 1
+	FILE_END     = 2
+
+	FORMAT_MESSAGE_ALLOCATE_BUFFER = 256
+	FORMAT_MESSAGE_IGNORE_INSERTS  = 512
+	FORMAT_MESSAGE_FROM_STRING     = 1024
+	FORMAT_MESSAGE_FROM_HMODULE    = 2048
+	FORMAT_MESSAGE_FROM_SYSTEM     = 4096
+	FORMAT_MESSAGE_ARGUMENT_ARRAY  = 8192
+	FORMAT_MESSAGE_MAX_WIDTH_MASK  = 255
+
+	MAX_PATH      = 260
+	MAX_LONG_PATH = 32768
+
+	MAX_COMPUTERNAME_LENGTH = 15
+
+	TIME_ZONE_ID_UNKNOWN  = 0
+	TIME_ZONE_ID_STANDARD = 1
+
+	TIME_ZONE_ID_DAYLIGHT = 2
+	IGNORE                = 0
+	INFINITE              = 0xffffffff
+
+	WAIT_TIMEOUT   = 258
+	WAIT_ABANDONED = 0x00000080
+	WAIT_OBJECT_0  = 0x00000000
+	WAIT_FAILED    = 0xFFFFFFFF
+
+	CREATE_UNICODE_ENVIRONMENT = 0x00000400
+
+	STANDARD_RIGHTS_READ      = 0x00020000
+	PROCESS_QUERY_INFORMATION = 0x00000400
+	SYNCHRONIZE               = 0x00100000
+
+	PAGE_READONLY          = 0x02
+	PAGE_READWRITE         = 0x04
+	PAGE_WRITECOPY         = 0x08
+	PAGE_EXECUTE_READ      = 0x20
+	PAGE_EXECUTE_READWRITE = 0x40
+	PAGE_EXECUTE_WRITECOPY = 0x80
+
+	FILE_MAP_COPY    = 0x01
+	FILE_MAP_WRITE   = 0x02
+	FILE_MAP_READ    = 0x04
+	FILE_MAP_EXECUTE = 0x20
+)
+
+const (
+	// wincrypt.h
+	PROV_RSA_FULL                    = 1
+	PROV_RSA_SIG                     = 2
+	PROV_DSS                         = 3
+	PROV_FORTEZZA                    = 4
+	PROV_MS_EXCHANGE                 = 5
+	PROV_SSL                         = 6
+	PROV_RSA_SCHANNEL                = 12
+	PROV_DSS_DH                      = 13
+	PROV_EC_ECDSA_SIG                = 14
+	PROV_EC_ECNRA_SIG                = 15
+	PROV_EC_ECDSA_FULL               = 16
+	PROV_EC_ECNRA_FULL               = 17
+	PROV_DH_SCHANNEL                 = 18
+	PROV_SPYRUS_LYNKS                = 20
+	PROV_RNG                         = 21
+	PROV_INTEL_SEC                   = 22
+	PROV_REPLACE_OWF                 = 23
+	PROV_RSA_AES                     = 24
+	CRYPT_VERIFYCONTEXT              = 0xF0000000
+	CRYPT_NEWKEYSET                  = 0x00000008
+	CRYPT_DELETEKEYSET               = 0x00000010
+	CRYPT_MACHINE_KEYSET             = 0x00000020
+	CRYPT_SILENT                     = 0x00000040
+	CRYPT_DEFAULT_CONTAINER_OPTIONAL = 0x00000080
+)
+
+// Types
+
+type _C_short int16
+
+type _C_int int32
+
+type _C_long int32
+
+type _C_long_long int64
+
+// Invented values to support what package os expects.
+type Timeval struct {
+	Sec  int32
+	Usec int32
+}
+
+func (tv *Timeval) Nanoseconds() int64 {
+	return (int64(tv.Sec)*1e6 + int64(tv.Usec)) * 1e3
+}
+
+func NsecToTimeval(nsec int64) (tv Timeval) {
+	tv.Sec = int32(nsec / 1e9)
+	tv.Usec = int32(nsec % 1e9 / 1e3)
+	return
+}
+
+type SecurityAttributes struct {
+	Length             uint32
+	SecurityDescriptor uintptr
+	InheritHandle      uint32
+}
+
+type Overlapped struct {
+	Internal     uint32
+	InternalHigh uint32
+	Offset       uint32
+	OffsetHigh   uint32
+	HEvent       Handle
+}
+
+type Filetime struct {
+	LowDateTime  uint32
+	HighDateTime uint32
+}
+
+func (ft *Filetime) Nanoseconds() int64 {
+	// 100-nanosecond intervals since January 1, 1601
+	nsec := int64(ft.HighDateTime)<<32 + int64(ft.LowDateTime)
+	// change starting time to the Epoch (00:00:00 UTC, January 1, 1970)
+	nsec -= 116444736000000000
+	// convert into nanoseconds
+	nsec *= 100
+	return nsec
+}
+
+func NsecToFiletime(nsec int64) (ft Filetime) {
+	// convert into 100-nanosecond
+	nsec /= 100
+	// change starting time to January 1, 1601
+	nsec += 116444736000000000
+	// split into high / low
+	ft.LowDateTime = uint32(nsec & 0xffffffff)
+	ft.HighDateTime = uint32(nsec >> 32 & 0xffffffff)
+	return ft
+}
+
+type Win32finddata struct {
+	FileAttributes    uint32
+	CreationTime      Filetime
+	LastAccessTime    Filetime
+	LastWriteTime     Filetime
+	FileSizeHigh      uint32
+	FileSizeLow       uint32
+	Reserved0         uint32
+	Reserved1         uint32
+	FileName          [MAX_PATH - 1]uint16
+	AlternateFileName [13]uint16
+}
+
+type ByHandleFileInformation struct {
+	FileAttributes     uint32
+	CreationTime       Filetime
+	LastAccessTime     Filetime
+	LastWriteTime      Filetime
+	VolumeSerialNumber uint32
+	FileSizeHigh       uint32
+	FileSizeLow        uint32
+	NumberOfLinks      uint32
+	FileIndexHigh      uint32
+	FileIndexLow       uint32
+}
+
+// ShowWindow constants
+const (
+	// winuser.h
+	SW_HIDE            = 0
+	SW_NORMAL          = 1
+	SW_SHOWNORMAL      = 1
+	SW_SHOWMINIMIZED   = 2
+	SW_SHOWMAXIMIZED   = 3
+	SW_MAXIMIZE        = 3
+	SW_SHOWNOACTIVATE  = 4
+	SW_SHOW            = 5
+	SW_MINIMIZE        = 6
+	SW_SHOWMINNOACTIVE = 7
+	SW_SHOWNA          = 8
+	SW_RESTORE         = 9
+	SW_SHOWDEFAULT     = 10
+	SW_FORCEMINIMIZE   = 11
+)
+
+type StartupInfo struct {
+	Cb            uint32
+	_             *uint16
+	Desktop       *uint16
+	Title         *uint16
+	X             uint32
+	Y             uint32
+	XSize         uint32
+	YSize         uint32
+	XCountChars   uint32
+	YCountChars   uint32
+	FillAttribute uint32
+	Flags         uint32
+	ShowWindow    uint16
+	_             uint16
+	_             *byte
+	StdInput      Handle
+	StdOutput     Handle
+	StdErr        Handle
+}
+
+type ProcessInformation struct {
+	Process   Handle
+	Thread    Handle
+	ProcessId uint32
+	ThreadId  uint32
+}
+
+// Invented values to support what package os expects.
+type Stat_t struct {
+	Windata Win32finddata
+	Mode    uint32
+}
+
+type Systemtime struct {
+	Year         uint16
+	Month        uint16
+	DayOfWeek    uint16
+	Day          uint16
+	Hour         uint16
+	Minute       uint16
+	Second       uint16
+	Milliseconds uint16
+}
+
+type Timezoneinformation struct {
+	Bias         int32
+	StandardName [32]uint16
+	StandardDate Systemtime
+	StandardBias int32
+	DaylightName [32]uint16
+	DaylightDate Systemtime
+	DaylightBias int32
+}
+
+// Socket related.
+
+const (
+	AF_UNSPEC  = 0
+	AF_UNIX    = 1
+	AF_INET    = 2
+	AF_INET6   = 23
+	AF_NETBIOS = 17
+
+	SOCK_STREAM    = 1
+	SOCK_DGRAM     = 2
+	SOCK_RAW       = 3
+	SOCK_SEQPACKET = 5
+
+	IPPROTO_IP  = 0
+	IPPROTO_TCP = 6
+	IPPROTO_UDP = 17
+
+	SOL_SOCKET               = 0xffff
+	SO_REUSEADDR             = 4
+	SO_KEEPALIVE             = 8
+	SO_DONTROUTE             = 16
+	SO_BROADCAST             = 32
+	SO_LINGER                = 128
+	SO_RCVBUF                = 0x1002
+	SO_SNDBUF                = 0x1001
+	SO_UPDATE_ACCEPT_CONTEXT = 0x700b
+
+	IPPROTO_IPV6 = 0x29
+	IPV6_V6ONLY  = 0x1b
+
+	SOMAXCONN = 5
+
+	TCP_NODELAY = 1
+
+	SHUT_RD   = 0
+	SHUT_WR   = 1
+	SHUT_RDWR = 2
+
+	WSADESCRIPTION_LEN = 256
+	WSASYS_STATUS_LEN  = 128
+)
+
+type WSAData struct {
+	Version      uint16
+	HighVersion  uint16
+	Description  [WSADESCRIPTION_LEN + 1]byte
+	SystemStatus [WSASYS_STATUS_LEN + 1]byte
+	MaxSockets   uint16
+	MaxUdpDg     uint16
+	VendorInfo   *byte
+}
+
+type WSABuf struct {
+	Len uint32
+	Buf *byte
+}
+
+// TODO(brainman): fix all needed for os
+
+const (
+	PROT_READ  = 0x1
+	PROT_WRITE = 0x2
+	MAP_SHARED = 0x1
+	SYS_FORK   = 0
+	SYS_PTRACE = 0
+	SYS_CHDIR  = 0
+	SYS_DUP2   = 0
+	SYS_FCNTL  = 0
+	SYS_EXECVE = 0
+	F_GETFD    = 0x1
+	F_SETFD    = 0x2
+	F_GETFL    = 0x3
+	F_SETFL    = 0x4
+	FD_CLOEXEC = 0
+	S_IFMT     = 0x1f000
+	S_IFIFO    = 0x1000
+	S_IFCHR    = 0x2000
+	S_IFDIR    = 0x4000
+	S_IFBLK    = 0x6000
+	S_IFREG    = 0x8000
+	S_IFLNK    = 0xa000
+	S_IFSOCK   = 0xc000
+	S_ISUID    = 0x800
+	S_ISGID    = 0x400
+	S_ISVTX    = 0x200
+	S_IRUSR    = 0x100
+	S_IWRITE   = 0x80
+	S_IWUSR    = 0x80
+	S_IXUSR    = 0x40
+)
+
+const (
+	FILE_TYPE_CHAR    = 0x0002
+	FILE_TYPE_DISK    = 0x0001
+	FILE_TYPE_PIPE    = 0x0003
+	FILE_TYPE_REMOTE  = 0x8000
+	FILE_TYPE_UNKNOWN = 0x0000
+)
+
+type Hostent struct {
+	Name     *byte
+	Aliases  **byte
+	AddrType uint16
+	Length   uint16
+	AddrList **byte
+}
+
+type Servent struct {
+	Name    *byte
+	Aliases **byte
+	Port    uint16
+	Proto   *byte
+}
+
+const (
+	DNS_TYPE_A       = 0x0001
+	DNS_TYPE_NS      = 0x0002
+	DNS_TYPE_MD      = 0x0003
+	DNS_TYPE_MF      = 0x0004
+	DNS_TYPE_CNAME   = 0x0005
+	DNS_TYPE_SOA     = 0x0006
+	DNS_TYPE_MB      = 0x0007
+	DNS_TYPE_MG      = 0x0008
+	DNS_TYPE_MR      = 0x0009
+	DNS_TYPE_NULL    = 0x000a
+	DNS_TYPE_WKS     = 0x000b
+	DNS_TYPE_PTR     = 0x000c
+	DNS_TYPE_HINFO   = 0x000d
+	DNS_TYPE_MINFO   = 0x000e
+	DNS_TYPE_MX      = 0x000f
+	DNS_TYPE_TEXT    = 0x0010
+	DNS_TYPE_RP      = 0x0011
+	DNS_TYPE_AFSDB   = 0x0012
+	DNS_TYPE_X25     = 0x0013
+	DNS_TYPE_ISDN    = 0x0014
+	DNS_TYPE_RT      = 0x0015
+	DNS_TYPE_NSAP    = 0x0016
+	DNS_TYPE_NSAPPTR = 0x0017
+	DNS_TYPE_SIG     = 0x0018
+	DNS_TYPE_KEY     = 0x0019
+	DNS_TYPE_PX      = 0x001a
+	DNS_TYPE_GPOS    = 0x001b
+	DNS_TYPE_AAAA    = 0x001c
+	DNS_TYPE_LOC     = 0x001d
+	DNS_TYPE_NXT     = 0x001e
+	DNS_TYPE_EID     = 0x001f
+	DNS_TYPE_NIMLOC  = 0x0020
+	DNS_TYPE_SRV     = 0x0021
+	DNS_TYPE_ATMA    = 0x0022
+	DNS_TYPE_NAPTR   = 0x0023
+	DNS_TYPE_KX      = 0x0024
+	DNS_TYPE_CERT    = 0x0025
+	DNS_TYPE_A6      = 0x0026
+	DNS_TYPE_DNAME   = 0x0027
+	DNS_TYPE_SINK    = 0x0028
+	DNS_TYPE_OPT     = 0x0029
+	DNS_TYPE_DS      = 0x002B
+	DNS_TYPE_RRSIG   = 0x002E
+	DNS_TYPE_NSEC    = 0x002F
+	DNS_TYPE_DNSKEY  = 0x0030
+	DNS_TYPE_DHCID   = 0x0031
+	DNS_TYPE_UINFO   = 0x0064
+	DNS_TYPE_UID     = 0x0065
+	DNS_TYPE_GID     = 0x0066
+	DNS_TYPE_UNSPEC  = 0x0067
+	DNS_TYPE_ADDRS   = 0x00f8
+	DNS_TYPE_TKEY    = 0x00f9
+	DNS_TYPE_TSIG    = 0x00fa
+	DNS_TYPE_IXFR    = 0x00fb
+	DNS_TYPE_AXFR    = 0x00fc
+	DNS_TYPE_MAILB   = 0x00fd
+	DNS_TYPE_MAILA   = 0x00fe
+	DNS_TYPE_ALL     = 0x00ff
+	DNS_TYPE_ANY     = 0x00ff
+	DNS_TYPE_WINS    = 0xff01
+	DNS_TYPE_WINSR   = 0xff02
+	DNS_TYPE_NBSTAT  = 0xff01
+)
+
+type DNSSRVData struct {
+	Target   *uint16
+	Priority uint16
+	Weight   uint16
+	Port     uint16
+	Pad      uint16
+}
+
+type DNSPTRData struct {
+	Host *uint16
+}
+
+type DNSRecord struct {
+	Next     *DNSRecord
+	Name     *uint16
+	Type     uint16
+	Length   uint16
+	Dw       uint32
+	Ttl      uint32
+	Reserved uint32
+	Data     [40]byte
+}
+
+const (
+	TF_DISCONNECT         = 1
+	TF_REUSE_SOCKET       = 2
+	TF_WRITE_BEHIND       = 4
+	TF_USE_DEFAULT_WORKER = 0
+	TF_USE_SYSTEM_THREAD  = 16
+	TF_USE_KERNEL_APC     = 32
+)
+
+type TransmitFileBuffers struct {
+	Head       uintptr
+	HeadLength uint32
+	Tail       uintptr
+	TailLength uint32
+}
+
+const (
+	IFF_UP           = 1
+	IFF_BROADCAST    = 2
+	IFF_LOOPBACK     = 4
+	IFF_POINTTOPOINT = 8
+	IFF_MULTICAST    = 16
+)
+
+const SIO_GET_INTERFACE_LIST = 0x4004747F
+
+// TODO(mattn): SockaddrGen is union of sockaddr/sockaddr_in/sockaddr_in6_old.
+// will be fixed to change variable type as suitable.
+
+type SockaddrGen [24]byte
+
+type InterfaceInfo struct {
+	Flags            uint32
+	Address          SockaddrGen
+	BroadcastAddress SockaddrGen
+	Netmask          SockaddrGen
+}
+
+type IpAddressString struct {
+	String [16]byte
+}
+
+type IpMaskString IpAddressString
+
+type IpAddrString struct {
+	Next      *IpAddrString
+	IpAddress IpAddressString
+	IpMask    IpMaskString
+	Context   uint32
+}
+
+const MAX_ADAPTER_NAME_LENGTH = 256
+const MAX_ADAPTER_DESCRIPTION_LENGTH = 128
+const MAX_ADAPTER_ADDRESS_LENGTH = 8
+
+type IpAdapterInfo struct {
+	Next                *IpAdapterInfo
+	ComboIndex          uint32
+	AdapterName         [MAX_ADAPTER_NAME_LENGTH + 4]byte
+	Description         [MAX_ADAPTER_DESCRIPTION_LENGTH + 4]byte
+	AddressLength       uint32
+	Address             [MAX_ADAPTER_ADDRESS_LENGTH]byte
+	Index               uint32
+	Type                uint32
+	DhcpEnabled         uint32
+	CurrentIpAddress    *IpAddrString
+	IpAddressList       IpAddrString
+	GatewayList         IpAddrString
+	DhcpServer          IpAddrString
+	HaveWins            bool
+	PrimaryWinsServer   IpAddrString
+	SecondaryWinsServer IpAddrString
+	LeaseObtained       int64
+	LeaseExpires        int64
+}
+
+const MAXLEN_PHYSADDR = 8
+const MAX_INTERFACE_NAME_LEN = 256
+const MAXLEN_IFDESCR = 256
+
+type MibIfRow struct {
+	Name            [MAX_INTERFACE_NAME_LEN]uint16
+	Index           uint32
+	Type            uint32
+	Mtu             uint32
+	Speed           uint32
+	PhysAddrLen     uint32
+	PhysAddr        [MAXLEN_PHYSADDR]byte
+	AdminStatus     uint32
+	OperStatus      uint32
+	LastChange      uint32
+	InOctets        uint32
+	InUcastPkts     uint32
+	InNUcastPkts    uint32
+	InDiscards      uint32
+	InErrors        uint32
+	InUnknownProtos uint32
+	OutOctets       uint32
+	OutUcastPkts    uint32
+	OutNUcastPkts   uint32
+	OutDiscards     uint32
+	OutErrors       uint32
+	OutQLen         uint32
+	DescrLen        uint32
+	Descr           [MAXLEN_IFDESCR]byte
+}
diff --git a/src/pkg/syscall/ztypes_windows_386.go b/src/pkg/syscall/ztypes_windows_386.go
index 6ea85e2..d1008bd 100644
--- a/src/pkg/syscall/ztypes_windows_386.go
+++ b/src/pkg/syscall/ztypes_windows_386.go
@@ -1,656 +1,5 @@
-package syscall
-
-// TODO(brainman): autogenerate types in ztypes_windows_386.go
-
-//import "unsafe"
-
-// Constants
-const (
-	sizeofPtr      = 0x4
-	sizeofShort    = 0x2
-	sizeofInt      = 0x4
-	sizeofLong     = 0x4
-	sizeofLongLong = 0x8
-	PathMax        = 0x1000
-	SizeofLinger   = 0x8
-	SizeofMsghdr   = 0x1c
-	SizeofCmsghdr  = 0xc
-)
-
-const (
-	// Windows errors.
-	ERROR_FILE_NOT_FOUND      = 2
-	ERROR_PATH_NOT_FOUND      = 3
-	ERROR_NO_MORE_FILES       = 18
-	ERROR_BROKEN_PIPE         = 109
-	ERROR_BUFFER_OVERFLOW     = 111
-	ERROR_INSUFFICIENT_BUFFER = 122
-	ERROR_MOD_NOT_FOUND       = 126
-	ERROR_PROC_NOT_FOUND      = 127
-	ERROR_ENVVAR_NOT_FOUND    = 203
-	ERROR_DIRECTORY           = 267
-	ERROR_OPERATION_ABORTED   = 995
-	ERROR_IO_PENDING          = 997
-)
-
-const (
-	// Invented values to support what package os expects.
-	O_RDONLY   = 0x00000
-	O_WRONLY   = 0x00001
-	O_RDWR     = 0x00002
-	O_CREAT    = 0x00040
-	O_EXCL     = 0x00080
-	O_NOCTTY   = 0x00100
-	O_TRUNC    = 0x00200
-	O_NONBLOCK = 0x00800
-	O_APPEND   = 0x00400
-	O_SYNC     = 0x01000
-	O_ASYNC    = 0x02000
-	O_CLOEXEC  = 0x80000
-)
-
-const (
-	// More invented values for signals
-	SIGHUP  = 0x1
-	SIGINT  = 0x2
-	SIGQUIT = 0x3
-	SIGILL  = 0x4
-	SIGTRAP = 0x5
-	SIGABRT = 0x6
-	SIGBUS  = 0x7
-	SIGFPE  = 0x8
-	SIGKILL = 0x9
-	SIGSEGV = 0xb
-	SIGPIPE = 0xd
-	SIGALRM = 0xe
-	SIGTERM = 0xf
-)
-
-const (
-	GENERIC_READ    = 0x80000000
-	GENERIC_WRITE   = 0x40000000
-	GENERIC_EXECUTE = 0x20000000
-	GENERIC_ALL     = 0x10000000
-
-	FILE_APPEND_DATA      = 0x00000004
-	FILE_WRITE_ATTRIBUTES = 0x00000100
-
-	FILE_SHARE_READ          = 0x00000001
-	FILE_SHARE_WRITE         = 0x00000002
-	FILE_SHARE_DELETE        = 0x00000004
-	FILE_ATTRIBUTE_READONLY  = 0x00000001
-	FILE_ATTRIBUTE_HIDDEN    = 0x00000002
-	FILE_ATTRIBUTE_SYSTEM    = 0x00000004
-	FILE_ATTRIBUTE_DIRECTORY = 0x00000010
-	FILE_ATTRIBUTE_ARCHIVE   = 0x00000020
-	FILE_ATTRIBUTE_NORMAL    = 0x00000080
-
-	INVALID_FILE_ATTRIBUTES = 0xffffffff
-
-	CREATE_NEW        = 1
-	CREATE_ALWAYS     = 2
-	OPEN_EXISTING     = 3
-	OPEN_ALWAYS       = 4
-	TRUNCATE_EXISTING = 5
-
-	HANDLE_FLAG_INHERIT    = 0x00000001
-	STARTF_USESTDHANDLES   = 0x00000100
-	STARTF_USESHOWWINDOW   = 0x00000001
-	DUPLICATE_CLOSE_SOURCE = 0x00000001
-	DUPLICATE_SAME_ACCESS  = 0x00000002
-
-	STD_INPUT_HANDLE  = -10
-	STD_OUTPUT_HANDLE = -11
-	STD_ERROR_HANDLE  = -12
-
-	FILE_BEGIN   = 0
-	FILE_CURRENT = 1
-	FILE_END     = 2
-
-	FORMAT_MESSAGE_ALLOCATE_BUFFER = 256
-	FORMAT_MESSAGE_IGNORE_INSERTS  = 512
-	FORMAT_MESSAGE_FROM_STRING     = 1024
-	FORMAT_MESSAGE_FROM_HMODULE    = 2048
-	FORMAT_MESSAGE_FROM_SYSTEM     = 4096
-	FORMAT_MESSAGE_ARGUMENT_ARRAY  = 8192
-	FORMAT_MESSAGE_MAX_WIDTH_MASK  = 255
-
-	MAX_PATH      = 260
-	MAX_LONG_PATH = 32768
-
-	MAX_COMPUTERNAME_LENGTH = 15
-
-	TIME_ZONE_ID_UNKNOWN  = 0
-	TIME_ZONE_ID_STANDARD = 1
-
-	TIME_ZONE_ID_DAYLIGHT = 2
-	IGNORE                = 0
-	INFINITE              = 0xffffffff
-
-	WAIT_TIMEOUT   = 258
-	WAIT_ABANDONED = 0x00000080
-	WAIT_OBJECT_0  = 0x00000000
-	WAIT_FAILED    = 0xFFFFFFFF
-
-	CREATE_UNICODE_ENVIRONMENT = 0x00000400
-
-	STANDARD_RIGHTS_READ      = 0x00020000
-	PROCESS_QUERY_INFORMATION = 0x00000400
-	SYNCHRONIZE               = 0x00100000
-
-	PAGE_READONLY          = 0x02
-	PAGE_READWRITE         = 0x04
-	PAGE_WRITECOPY         = 0x08
-	PAGE_EXECUTE_READ      = 0x20
-	PAGE_EXECUTE_READWRITE = 0x40
-	PAGE_EXECUTE_WRITECOPY = 0x80
-
-	FILE_MAP_COPY    = 0x01
-	FILE_MAP_WRITE   = 0x02
-	FILE_MAP_READ    = 0x04
-	FILE_MAP_EXECUTE = 0x20
-)
-
-const (
-	// wincrypt.h
-	PROV_RSA_FULL                    = 1
-	PROV_RSA_SIG                     = 2
-	PROV_DSS                         = 3
-	PROV_FORTEZZA                    = 4
-	PROV_MS_EXCHANGE                 = 5
-	PROV_SSL                         = 6
-	PROV_RSA_SCHANNEL                = 12
-	PROV_DSS_DH                      = 13
-	PROV_EC_ECDSA_SIG                = 14
-	PROV_EC_ECNRA_SIG                = 15
-	PROV_EC_ECDSA_FULL               = 16
-	PROV_EC_ECNRA_FULL               = 17
-	PROV_DH_SCHANNEL                 = 18
-	PROV_SPYRUS_LYNKS                = 20
-	PROV_RNG                         = 21
-	PROV_INTEL_SEC                   = 22
-	PROV_REPLACE_OWF                 = 23
-	PROV_RSA_AES                     = 24
-	CRYPT_VERIFYCONTEXT              = 0xF0000000
-	CRYPT_NEWKEYSET                  = 0x00000008
-	CRYPT_DELETEKEYSET               = 0x00000010
-	CRYPT_MACHINE_KEYSET             = 0x00000020
-	CRYPT_SILENT                     = 0x00000040
-	CRYPT_DEFAULT_CONTAINER_OPTIONAL = 0x00000080
-)
-
-// Types
-
-type _C_short int16
-
-type _C_int int32
-
-type _C_long int32
-
-type _C_long_long int64
-
-// Invented values to support what package os expects.
-type Timeval struct {
-	Sec  int32
-	Usec int32
-}
-
-func (tv *Timeval) Nanoseconds() int64 {
-	return (int64(tv.Sec)*1e6 + int64(tv.Usec)) * 1e3
-}
-
-func NsecToTimeval(nsec int64) (tv Timeval) {
-	tv.Sec = int32(nsec / 1e9)
-	tv.Usec = int32(nsec % 1e9 / 1e3)
-	return
-}
-
-type SecurityAttributes struct {
-	Length             uint32
-	SecurityDescriptor uintptr
-	InheritHandle      uint32
-}
-
-type Overlapped struct {
-	Internal     uint32
-	InternalHigh uint32
-	Offset       uint32
-	OffsetHigh   uint32
-	HEvent       int32
-}
-
-type Filetime struct {
-	LowDateTime  uint32
-	HighDateTime uint32
-}
-
-func (ft *Filetime) Nanoseconds() int64 {
-	// 100-nanosecond intervals since January 1, 1601
-	nsec := int64(ft.HighDateTime)<<32 + int64(ft.LowDateTime)
-	// change starting time to the Epoch (00:00:00 UTC, January 1, 1970)
-	nsec -= 116444736000000000
-	// convert into nanoseconds
-	nsec *= 100
-	return nsec
-}
-
-func NsecToFiletime(nsec int64) (ft Filetime) {
-	// convert into 100-nanosecond
-	nsec /= 100
-	// change starting time to January 1, 1601
-	nsec += 116444736000000000
-	// split into high / low
-	ft.LowDateTime = uint32(nsec & 0xffffffff)
-	ft.HighDateTime = uint32(nsec >> 32 & 0xffffffff)
-	return ft
-}
-
-type Win32finddata struct {
-	FileAttributes    uint32
-	CreationTime      Filetime
-	LastAccessTime    Filetime
-	LastWriteTime     Filetime
-	FileSizeHigh      uint32
-	FileSizeLow       uint32
-	Reserved0         uint32
-	Reserved1         uint32
-	FileName          [MAX_PATH - 1]uint16
-	AlternateFileName [13]uint16
-}
-
-type ByHandleFileInformation struct {
-	FileAttributes     uint32
-	CreationTime       Filetime
-	LastAccessTime     Filetime
-	LastWriteTime      Filetime
-	VolumeSerialNumber uint32
-	FileSizeHigh       uint32
-	FileSizeLow        uint32
-	NumberOfLinks      uint32
-	FileIndexHigh      uint32
-	FileIndexLow       uint32
-}
+// 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.
 
-// ShowWindow constants
-const (
-	// winuser.h
-	SW_HIDE            = 0
-	SW_NORMAL          = 1
-	SW_SHOWNORMAL      = 1
-	SW_SHOWMINIMIZED   = 2
-	SW_SHOWMAXIMIZED   = 3
-	SW_MAXIMIZE        = 3
-	SW_SHOWNOACTIVATE  = 4
-	SW_SHOW            = 5
-	SW_MINIMIZE        = 6
-	SW_SHOWMINNOACTIVE = 7
-	SW_SHOWNA          = 8
-	SW_RESTORE         = 9
-	SW_SHOWDEFAULT     = 10
-	SW_FORCEMINIMIZE   = 11
-)
-
-type StartupInfo struct {
-	Cb            uint32
-	_             *uint16
-	Desktop       *uint16
-	Title         *uint16
-	X             uint32
-	Y             uint32
-	XSize         uint32
-	YSize         uint32
-	XCountChars   uint32
-	YCountChars   uint32
-	FillAttribute uint32
-	Flags         uint32
-	ShowWindow    uint16
-	_             uint16
-	_             *byte
-	StdInput      int32
-	StdOutput     int32
-	StdErr        int32
-}
-
-type ProcessInformation struct {
-	Process   int32
-	Thread    int32
-	ProcessId uint32
-	ThreadId  uint32
-}
-
-// Invented values to support what package os expects.
-type Stat_t struct {
-	Windata Win32finddata
-	Mode    uint32
-}
-
-type Systemtime struct {
-	Year         uint16
-	Month        uint16
-	DayOfWeek    uint16
-	Day          uint16
-	Hour         uint16
-	Minute       uint16
-	Second       uint16
-	Milliseconds uint16
-}
-
-type Timezoneinformation struct {
-	Bias         int32
-	StandardName [32]uint16
-	StandardDate Systemtime
-	StandardBias int32
-	DaylightName [32]uint16
-	DaylightDate Systemtime
-	DaylightBias int32
-}
-
-// Socket related.
-
-const (
-	AF_UNSPEC  = 0
-	AF_UNIX    = 1
-	AF_INET    = 2
-	AF_INET6   = 23
-	AF_NETBIOS = 17
-
-	SOCK_STREAM    = 1
-	SOCK_DGRAM     = 2
-	SOCK_RAW       = 3
-	SOCK_SEQPACKET = 5
-
-	IPPROTO_IP  = 0
-	IPPROTO_TCP = 6
-	IPPROTO_UDP = 17
-
-	SOL_SOCKET               = 0xffff
-	SO_REUSEADDR             = 4
-	SO_KEEPALIVE             = 8
-	SO_DONTROUTE             = 16
-	SO_BROADCAST             = 32
-	SO_LINGER                = 128
-	SO_RCVBUF                = 0x1002
-	SO_SNDBUF                = 0x1001
-	SO_UPDATE_ACCEPT_CONTEXT = 0x700b
-
-	IPPROTO_IPV6 = 0x29
-	IPV6_V6ONLY  = 0x1b
-
-	SOMAXCONN = 5
-
-	TCP_NODELAY = 1
-
-	SHUT_RD   = 0
-	SHUT_WR   = 1
-	SHUT_RDWR = 2
-
-	WSADESCRIPTION_LEN = 256
-	WSASYS_STATUS_LEN  = 128
-)
-
-type WSAData struct {
-	Version      uint16
-	HighVersion  uint16
-	Description  [WSADESCRIPTION_LEN + 1]byte
-	SystemStatus [WSASYS_STATUS_LEN + 1]byte
-	MaxSockets   uint16
-	MaxUdpDg     uint16
-	VendorInfo   *byte
-}
-
-type WSABuf struct {
-	Len uint32
-	Buf *byte
-}
-
-// TODO(brainman): fix all needed for os
-
-const (
-	PROT_READ  = 0x1
-	PROT_WRITE = 0x2
-	MAP_SHARED = 0x1
-	SYS_FORK   = 0
-	SYS_PTRACE = 0
-	SYS_CHDIR  = 0
-	SYS_DUP2   = 0
-	SYS_FCNTL  = 0
-	SYS_EXECVE = 0
-	F_GETFD    = 0x1
-	F_SETFD    = 0x2
-	F_GETFL    = 0x3
-	F_SETFL    = 0x4
-	FD_CLOEXEC = 0
-	S_IFMT     = 0x1f000
-	S_IFIFO    = 0x1000
-	S_IFCHR    = 0x2000
-	S_IFDIR    = 0x4000
-	S_IFBLK    = 0x6000
-	S_IFREG    = 0x8000
-	S_IFLNK    = 0xa000
-	S_IFSOCK   = 0xc000
-	S_ISUID    = 0x800
-	S_ISGID    = 0x400
-	S_ISVTX    = 0x200
-	S_IRUSR    = 0x100
-	S_IWRITE   = 0x80
-	S_IWUSR    = 0x80
-	S_IXUSR    = 0x40
-)
-
-const (
-	FILE_TYPE_CHAR    = 0x0002
-	FILE_TYPE_DISK    = 0x0001
-	FILE_TYPE_PIPE    = 0x0003
-	FILE_TYPE_REMOTE  = 0x8000
-	FILE_TYPE_UNKNOWN = 0x0000
-)
-
-type Hostent struct {
-	Name     *byte
-	Aliases  **byte
-	AddrType uint16
-	Length   uint16
-	AddrList **byte
-}
-
-type Servent struct {
-	Name    *byte
-	Aliases **byte
-	Port    uint16
-	Proto   *byte
-}
-
-const (
-	DNS_TYPE_A       = 0x0001
-	DNS_TYPE_NS      = 0x0002
-	DNS_TYPE_MD      = 0x0003
-	DNS_TYPE_MF      = 0x0004
-	DNS_TYPE_CNAME   = 0x0005
-	DNS_TYPE_SOA     = 0x0006
-	DNS_TYPE_MB      = 0x0007
-	DNS_TYPE_MG      = 0x0008
-	DNS_TYPE_MR      = 0x0009
-	DNS_TYPE_NULL    = 0x000a
-	DNS_TYPE_WKS     = 0x000b
-	DNS_TYPE_PTR     = 0x000c
-	DNS_TYPE_HINFO   = 0x000d
-	DNS_TYPE_MINFO   = 0x000e
-	DNS_TYPE_MX      = 0x000f
-	DNS_TYPE_TEXT    = 0x0010
-	DNS_TYPE_RP      = 0x0011
-	DNS_TYPE_AFSDB   = 0x0012
-	DNS_TYPE_X25     = 0x0013
-	DNS_TYPE_ISDN    = 0x0014
-	DNS_TYPE_RT      = 0x0015
-	DNS_TYPE_NSAP    = 0x0016
-	DNS_TYPE_NSAPPTR = 0x0017
-	DNS_TYPE_SIG     = 0x0018
-	DNS_TYPE_KEY     = 0x0019
-	DNS_TYPE_PX      = 0x001a
-	DNS_TYPE_GPOS    = 0x001b
-	DNS_TYPE_AAAA    = 0x001c
-	DNS_TYPE_LOC     = 0x001d
-	DNS_TYPE_NXT     = 0x001e
-	DNS_TYPE_EID     = 0x001f
-	DNS_TYPE_NIMLOC  = 0x0020
-	DNS_TYPE_SRV     = 0x0021
-	DNS_TYPE_ATMA    = 0x0022
-	DNS_TYPE_NAPTR   = 0x0023
-	DNS_TYPE_KX      = 0x0024
-	DNS_TYPE_CERT    = 0x0025
-	DNS_TYPE_A6      = 0x0026
-	DNS_TYPE_DNAME   = 0x0027
-	DNS_TYPE_SINK    = 0x0028
-	DNS_TYPE_OPT     = 0x0029
-	DNS_TYPE_DS      = 0x002B
-	DNS_TYPE_RRSIG   = 0x002E
-	DNS_TYPE_NSEC    = 0x002F
-	DNS_TYPE_DNSKEY  = 0x0030
-	DNS_TYPE_DHCID   = 0x0031
-	DNS_TYPE_UINFO   = 0x0064
-	DNS_TYPE_UID     = 0x0065
-	DNS_TYPE_GID     = 0x0066
-	DNS_TYPE_UNSPEC  = 0x0067
-	DNS_TYPE_ADDRS   = 0x00f8
-	DNS_TYPE_TKEY    = 0x00f9
-	DNS_TYPE_TSIG    = 0x00fa
-	DNS_TYPE_IXFR    = 0x00fb
-	DNS_TYPE_AXFR    = 0x00fc
-	DNS_TYPE_MAILB   = 0x00fd
-	DNS_TYPE_MAILA   = 0x00fe
-	DNS_TYPE_ALL     = 0x00ff
-	DNS_TYPE_ANY     = 0x00ff
-	DNS_TYPE_WINS    = 0xff01
-	DNS_TYPE_WINSR   = 0xff02
-	DNS_TYPE_NBSTAT  = 0xff01
-)
-
-type DNSSRVData struct {
-	Target   *uint16
-	Priority uint16
-	Weight   uint16
-	Port     uint16
-	Pad      uint16
-}
-
-type DNSPTRData struct {
-	Host *uint16
-}
-
-type DNSRecord struct {
-	Next     *DNSRecord
-	Name     *uint16
-	Type     uint16
-	Length   uint16
-	Dw       uint32
-	Ttl      uint32
-	Reserved uint32
-	Data     [40]byte
-}
-
-const (
-	TF_DISCONNECT         = 1
-	TF_REUSE_SOCKET       = 2
-	TF_WRITE_BEHIND       = 4
-	TF_USE_DEFAULT_WORKER = 0
-	TF_USE_SYSTEM_THREAD  = 16
-	TF_USE_KERNEL_APC     = 32
-)
-
-type TransmitFileBuffers struct {
-	Head       uintptr
-	HeadLength uint32
-	Tail       uintptr
-	TailLength uint32
-}
-
-const (
-	IFF_UP           = 1
-	IFF_BROADCAST    = 2
-	IFF_LOOPBACK     = 4
-	IFF_POINTTOPOINT = 8
-	IFF_MULTICAST    = 16
-)
-
-const SIO_GET_INTERFACE_LIST = 0x4004747F
-
-// TODO(mattn): SockaddrGen is union of sockaddr/sockaddr_in/sockaddr_in6_old.
-// will be fixed to change variable type as suitable.
-
-type SockaddrGen [24]byte
-
-type InterfaceInfo struct {
-	Flags            uint32
-	Address          SockaddrGen
-	BroadcastAddress SockaddrGen
-	Netmask          SockaddrGen
-}
-
-type IpAddressString struct {
-	String [16]byte
-}
-
-type IpMaskString IpAddressString
-
-type IpAddrString struct {
-	Next      *IpAddrString
-	IpAddress IpAddressString
-	IpMask    IpMaskString
-	Context   uint32
-}
-
-const MAX_ADAPTER_NAME_LENGTH = 256
-const MAX_ADAPTER_DESCRIPTION_LENGTH = 128
-const MAX_ADAPTER_ADDRESS_LENGTH = 8
-
-type IpAdapterInfo struct {
-	Next                *IpAdapterInfo
-	ComboIndex          uint32
-	AdapterName         [MAX_ADAPTER_NAME_LENGTH + 4]byte
-	Description         [MAX_ADAPTER_DESCRIPTION_LENGTH + 4]byte
-	AddressLength       uint32
-	Address             [MAX_ADAPTER_ADDRESS_LENGTH]byte
-	Index               uint32
-	Type                uint32
-	DhcpEnabled         uint32
-	CurrentIpAddress    *IpAddrString
-	IpAddressList       IpAddrString
-	GatewayList         IpAddrString
-	DhcpServer          IpAddrString
-	HaveWins            bool
-	PrimaryWinsServer   IpAddrString
-	SecondaryWinsServer IpAddrString
-	LeaseObtained       int64
-	LeaseExpires        int64
-}
-
-const MAXLEN_PHYSADDR = 8
-const MAX_INTERFACE_NAME_LEN = 256
-const MAXLEN_IFDESCR = 256
-
-type MibIfRow struct {
-	Name            [MAX_INTERFACE_NAME_LEN]uint16
-	Index           uint32
-	Type            uint32
-	Mtu             uint32
-	Speed           uint32
-	PhysAddrLen     uint32
-	PhysAddr        [MAXLEN_PHYSADDR]byte
-	AdminStatus     uint32
-	OperStatus      uint32
-	LastChange      uint32
-	InOctets        uint32
-	InUcastPkts     uint32
-	InNUcastPkts    uint32
-	InDiscards      uint32
-	InErrors        uint32
-	InUnknownProtos uint32
-	OutOctets       uint32
-	OutUcastPkts    uint32
-	OutNUcastPkts   uint32
-	OutDiscards     uint32
-	OutErrors       uint32
-	OutQLen         uint32
-	DescrLen        uint32
-	Descr           [MAXLEN_IFDESCR]byte
-}
+package syscall
diff --git a/src/pkg/syscall/ztypes_windows_amd64.go b/src/pkg/syscall/ztypes_windows_amd64.go
new file mode 100644
index 0000000..d1008bd
--- /dev/null
+++ b/src/pkg/syscall/ztypes_windows_amd64.go
@@ -0,0 +1,5 @@
+// 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 syscall
diff --git a/src/pkg/template/execute.go b/src/pkg/template/execute.go
index 5bc7ff7..464b620 100644
--- a/src/pkg/template/execute.go
+++ b/src/pkg/template/execute.go
@@ -114,7 +114,7 @@ func (t *Template) findVar(st *state, s string) reflect.Value {
 	if s == "@" {
 		return indirectPtr(data, numStars)
 	}
-	for _, elem := range strings.Split(s, ".", -1) {
+	for _, elem := range strings.Split(s, ".") {
 		// Look up field; data must be a struct or map.
 		data = t.lookup(st, data, elem)
 		if !data.IsValid() {
diff --git a/src/pkg/template/parse.go b/src/pkg/template/parse.go
index b4aa5fc..dedf9ad 100644
--- a/src/pkg/template/parse.go
+++ b/src/pkg/template/parse.go
@@ -483,7 +483,7 @@ func extractFormatters(words []string) (formatters []string) {
 		}
 	}
 	words[len(words)-1] = lastWord[0:bar]
-	formatters = strings.Split(lastWord[bar+1:], "|", -1)
+	formatters = strings.Split(lastWord[bar+1:], "|")
 	return
 }
 
diff --git a/src/pkg/testing/benchmark.go b/src/pkg/testing/benchmark.go
index f8b53e6..3b416ac 100644
--- a/src/pkg/testing/benchmark.go
+++ b/src/pkg/testing/benchmark.go
@@ -13,6 +13,7 @@ import (
 )
 
 var matchBenchmarks = flag.String("test.bench", "", "regular expression to select benchmarks to run")
+var benchTime = flag.Float64("test.benchtime", 1, "approximate run time for each benchmark, in seconds")
 
 // An internal type but exported because it is cross-package; part of the implementation
 // of gotest.
@@ -34,7 +35,11 @@ type B struct {
 // StartTimer starts timing a test.  This function is called automatically
 // before a benchmark starts, but it can also used to resume timing after
 // a call to StopTimer.
-func (b *B) StartTimer() { b.start = time.Nanoseconds() }
+func (b *B) StartTimer() {
+	if b.start == 0 {
+		b.start = time.Nanoseconds()
+	}
+}
 
 // StopTimer stops timing a test.  This can be used to pause the timer
 // while performing complex initialization that you don't
@@ -46,9 +51,12 @@ func (b *B) StopTimer() {
 	b.start = 0
 }
 
-// ResetTimer stops the timer and sets the elapsed benchmark time to zero.
+// ResetTimer sets the elapsed benchmark time to zero.
+// It does not affect whether the timer is running.
 func (b *B) ResetTimer() {
-	b.start = 0
+	if b.start > 0 {
+		b.start = time.Nanoseconds()
+	}
 	b.ns = 0
 }
 
@@ -125,14 +133,15 @@ func (b *B) run() BenchmarkResult {
 	// Run the benchmark for a single iteration in case it's expensive.
 	n := 1
 	b.runN(n)
-	// Run the benchmark for at least a second.
-	for b.ns < 1e9 && n < 1e9 {
+	// Run the benchmark for at least the specified amount of time.
+	time := int64(*benchTime * 1e9)
+	for b.ns < time && n < 1e9 {
 		last := n
 		// Predict iterations/sec.
 		if b.nsPerOp() == 0 {
 			n = 1e9
 		} else {
-			n = 1e9 / int(b.nsPerOp())
+			n = int(time / b.nsPerOp())
 		}
 		// Run more iterations than we think we'll need for a second (1.5x).
 		// Don't grow too fast in case we had timing errors previously.
@@ -172,7 +181,18 @@ func (r BenchmarkResult) String() string {
 	if mbs != 0 {
 		mb = fmt.Sprintf("\t%7.2f MB/s", mbs)
 	}
-	return fmt.Sprintf("%8d\t%10d ns/op%s", r.N, r.NsPerOp(), mb)
+	nsop := r.NsPerOp()
+	ns := fmt.Sprintf("%10d ns/op", nsop)
+	if r.N > 0 && nsop < 100 {
+		// The format specifiers here make sure that
+		// the ones digits line up for all three possible formats.
+		if nsop < 10 {
+			ns = fmt.Sprintf("%13.2f ns/op", float64(r.Ns)/float64(r.N))
+		} else {
+			ns = fmt.Sprintf("%12.1f ns/op", float64(r.Ns)/float64(r.N))
+		}
+	}
+	return fmt.Sprintf("%8d\t%s%s", r.N, ns, mb)
 }
 
 // An internal function but exported because it is cross-package; part of the implementation
@@ -182,7 +202,6 @@ func RunBenchmarks(matchString func(pat, str string) (bool, os.Error), benchmark
 	if len(*matchBenchmarks) == 0 {
 		return
 	}
-	procs := runtime.GOMAXPROCS(-1)
 	for _, Benchmark := range benchmarks {
 		matched, err := matchString(*matchBenchmarks, Benchmark.Name)
 		if err != nil {
@@ -192,14 +211,19 @@ func RunBenchmarks(matchString func(pat, str string) (bool, os.Error), benchmark
 		if !matched {
 			continue
 		}
-		b := &B{benchmark: Benchmark}
-		r := b.run()
-		print(fmt.Sprintf("%s\t%v\n", Benchmark.Name, r))
-		if p := runtime.GOMAXPROCS(-1); p != procs {
-			print(fmt.Sprintf("%s left GOMAXPROCS set to %d\n", Benchmark.Name, p))
-			procs = p
+		for _, procs := range cpuList {
+			runtime.GOMAXPROCS(procs)
+			b := &B{benchmark: Benchmark}
+			r := b.run()
+			benchName := Benchmark.Name
+			if procs != 1 {
+				benchName = fmt.Sprintf("%s-%d", Benchmark.Name, procs)
+			}
+			print(fmt.Sprintf("%s\t%v\n", benchName, r))
+			if p := runtime.GOMAXPROCS(-1); p != procs {
+				print(fmt.Sprintf("%s left GOMAXPROCS set to %d\n", benchName, p))
+			}
 		}
-
 	}
 }
 
diff --git a/src/pkg/testing/iotest/reader.go b/src/pkg/testing/iotest/reader.go
index e4003d7..daa6ede 100644
--- a/src/pkg/testing/iotest/reader.go
+++ b/src/pkg/testing/iotest/reader.go
@@ -58,7 +58,7 @@ func (r *dataErrReader) Read(p []byte) (n int, err os.Error) {
 			r.unread = r.data[0:n1]
 			err = err1
 		}
-		if n > 0 {
+		if n > 0 || err != nil {
 			break
 		}
 		n = copy(p, r.unread)
@@ -66,3 +66,22 @@ func (r *dataErrReader) Read(p []byte) (n int, err os.Error) {
 	}
 	return
 }
+
+var ErrTimeout = os.NewError("timeout")
+
+// TimeoutReader returns ErrTimeout on the second read
+// with no data.  Subsequent calls to read succeed.
+func TimeoutReader(r io.Reader) io.Reader { return &timeoutReader{r, 0} }
+
+type timeoutReader struct {
+	r     io.Reader
+	count int
+}
+
+func (r *timeoutReader) Read(p []byte) (int, os.Error) {
+	r.count++
+	if r.count == 2 {
+		return 0, ErrTimeout
+	}
+	return r.r.Read(p)
+}
diff --git a/src/pkg/testing/testing.go b/src/pkg/testing/testing.go
index 3b2dd37..ba72152 100644
--- a/src/pkg/testing/testing.go
+++ b/src/pkg/testing/testing.go
@@ -44,6 +44,8 @@ import (
 	"os"
 	"runtime"
 	"runtime/pprof"
+	"strings"
+	"strconv"
 	"time"
 )
 
@@ -62,6 +64,9 @@ var (
 	memProfileRate = flag.Int("test.memprofilerate", 0, "if >=0, sets runtime.MemProfileRate")
 	cpuProfile     = flag.String("test.cpuprofile", "", "write a cpu profile to the named file during execution")
 	timeout        = flag.Int64("test.timeout", 0, "if > 0, sets time limit for tests in seconds")
+	cpuListStr     = flag.String("test.cpu", "", "comma-separated list of number of CPUs to use for each test")
+
+	cpuList []int
 )
 
 // Short reports whether the -test.short flag is set.
@@ -157,6 +162,7 @@ func tRunner(t *T, test *InternalTest) {
 // of gotest.
 func Main(matchString func(pat, str string) (bool, os.Error), tests []InternalTest, benchmarks []InternalBenchmark) {
 	flag.Parse()
+	parseCpuList()
 
 	before()
 	startAlarm()
@@ -171,7 +177,6 @@ func RunTests(matchString func(pat, str string) (bool, os.Error), tests []Intern
 	if len(tests) == 0 {
 		println("testing: warning: no tests to run")
 	}
-	procs := runtime.GOMAXPROCS(-1)
 	for i := 0; i < len(tests); i++ {
 		matched, err := matchString(*match, tests[i].Name)
 		if err != nil {
@@ -181,28 +186,34 @@ func RunTests(matchString func(pat, str string) (bool, os.Error), tests []Intern
 		if !matched {
 			continue
 		}
-		if *chatty {
-			println("=== RUN ", tests[i].Name)
-		}
-		ns := -time.Nanoseconds()
-		t := new(T)
-		t.ch = make(chan *T)
-		go tRunner(t, &tests[i])
-		<-t.ch
-		ns += time.Nanoseconds()
-		tstr := fmt.Sprintf("(%.2f seconds)", float64(ns)/1e9)
-		if p := runtime.GOMAXPROCS(-1); t.failed == false && p != procs {
-			t.failed = true
-			t.errors = fmt.Sprintf("%s left GOMAXPROCS set to %d\n", tests[i].Name, p)
-			procs = p
-		}
-		if t.failed {
-			println("--- FAIL:", tests[i].Name, tstr)
-			print(t.errors)
-			ok = false
-		} else if *chatty {
-			println("--- PASS:", tests[i].Name, tstr)
-			print(t.errors)
+		for _, procs := range cpuList {
+			runtime.GOMAXPROCS(procs)
+			testName := tests[i].Name
+			if procs != 1 {
+				testName = fmt.Sprintf("%s-%d", tests[i].Name, procs)
+			}
+			if *chatty {
+				println("=== RUN ", testName)
+			}
+			ns := -time.Nanoseconds()
+			t := new(T)
+			t.ch = make(chan *T)
+			go tRunner(t, &tests[i])
+			<-t.ch
+			ns += time.Nanoseconds()
+			tstr := fmt.Sprintf("(%.2f seconds)", float64(ns)/1e9)
+			if p := runtime.GOMAXPROCS(-1); t.failed == false && p != procs {
+				t.failed = true
+				t.errors = fmt.Sprintf("%s left GOMAXPROCS set to %d\n", testName, p)
+			}
+			if t.failed {
+				println("--- FAIL:", testName, tstr)
+				print(t.errors)
+				ok = false
+			} else if *chatty {
+				println("--- PASS:", testName, tstr)
+				print(t.errors)
+			}
 		}
 	}
 	if !ok {
@@ -271,3 +282,18 @@ func stopAlarm() {
 func alarm() {
 	panic("test timed out")
 }
+
+func parseCpuList() {
+	if len(*cpuListStr) == 0 {
+		cpuList = append(cpuList, runtime.GOMAXPROCS(-1))
+	} else {
+		for _, val := range strings.Split(*cpuListStr, ",") {
+			cpu, err := strconv.Atoi(val)
+			if err != nil || cpu <= 0 {
+				println("invalid value for -test.cpu")
+				os.Exit(1)
+			}
+			cpuList = append(cpuList, cpu)
+		}
+	}
+}
diff --git a/src/pkg/time/format.go b/src/pkg/time/format.go
index e0f5612..26f40d1 100644
--- a/src/pkg/time/format.go
+++ b/src/pkg/time/format.go
@@ -248,7 +248,7 @@ func (t *Time) Format(layout string) string {
 		var p string
 		switch std {
 		case stdYear:
-			p = strconv.Itoa64(t.Year % 100)
+			p = zeroPad(int(t.Year % 100))
 		case stdLongYear:
 			p = strconv.Itoa64(t.Year)
 		case stdMonth:
diff --git a/src/pkg/time/sleep_test.go b/src/pkg/time/sleep_test.go
index 25e79f9..a4a1a42 100644
--- a/src/pkg/time/sleep_test.go
+++ b/src/pkg/time/sleep_test.go
@@ -172,7 +172,7 @@ func testAfterQueuing(t *testing.T) os.Error {
 	for _, slot := range slots {
 		go await(slot, result, After(int64(slot)*Delta))
 	}
-	sort.SortInts(slots)
+	sort.Ints(slots)
 	for _, slot := range slots {
 		r := <-result
 		if r.slot != slot {
diff --git a/src/pkg/time/time_test.go b/src/pkg/time/time_test.go
index eb676bf..eec8a7a 100644
--- a/src/pkg/time/time_test.go
+++ b/src/pkg/time/time_test.go
@@ -142,21 +142,22 @@ type FormatTest struct {
 }
 
 var formatTests = []FormatTest{
-	{"ANSIC", ANSIC, "Thu Feb  4 21:00:57 2010"},
-	{"UnixDate", UnixDate, "Thu Feb  4 21:00:57 PST 2010"},
-	{"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0800 2010"},
-	{"RFC822", RFC822, "04 Feb 10 2100 PST"},
-	{"RFC850", RFC850, "Thursday, 04-Feb-10 21:00:57 PST"},
-	{"RFC1123", RFC1123, "Thu, 04 Feb 2010 21:00:57 PST"},
-	{"RFC3339", RFC3339, "2010-02-04T21:00:57-08:00"},
+	{"ANSIC", ANSIC, "Wed Feb  4 21:00:57 2009"},
+	{"UnixDate", UnixDate, "Wed Feb  4 21:00:57 PST 2009"},
+	{"RubyDate", RubyDate, "Wed Feb 04 21:00:57 -0800 2009"},
+	{"RFC822", RFC822, "04 Feb 09 2100 PST"},
+	{"RFC850", RFC850, "Wednesday, 04-Feb-09 21:00:57 PST"},
+	{"RFC1123", RFC1123, "Wed, 04 Feb 2009 21:00:57 PST"},
+	{"RFC3339", RFC3339, "2009-02-04T21:00:57-08:00"},
 	{"Kitchen", Kitchen, "9:00PM"},
 	{"am/pm", "3pm", "9pm"},
 	{"AM/PM", "3PM", "9PM"},
+	{"two-digit year", "06 01 02", "09 02 04"},
 }
 
 func TestFormat(t *testing.T) {
 	// The numeric time represents Thu Feb  4 21:00:57 PST 2010
-	time := SecondsToLocalTime(1265346057)
+	time := SecondsToLocalTime(1233810057)
 	for _, test := range formatTests {
 		result := time.Format(test.format)
 		if result != test.result {
diff --git a/src/pkg/unicode/maketables.go b/src/pkg/unicode/maketables.go
index 421d294..07b931d 100644
--- a/src/pkg/unicode/maketables.go
+++ b/src/pkg/unicode/maketables.go
@@ -73,7 +73,7 @@ var category = map[string]bool{
 // UnicodeData.txt has form:
 //	0037;DIGIT SEVEN;Nd;0;EN;;7;7;7;N;;;;;
 //	007A;LATIN SMALL LETTER Z;Ll;0;L;;;;;N;;;005A;;005A
-// See http://www.unicode.org/Public/5.1.0/ucd/UCD.html for full explanation
+// See http://www.unicode.org/reports/tr44/ for a full explanation
 // The fields:
 const (
 	FCodePoint = iota
@@ -81,10 +81,10 @@ const (
 	FGeneralCategory
 	FCanonicalCombiningClass
 	FBidiClass
-	FDecompositionType
-	FDecompositionMapping
+	FDecompositionTypeAndMapping
 	FNumericType
-	FNumericValue
+	FNumericDigit // If a decimal digit.
+	FNumericValue // Includes non-decimal, e.g. U+2155=1/5
 	FBidiMirrored
 	FUnicode1Name
 	FISOComment
@@ -97,21 +97,21 @@ const (
 )
 
 var fieldName = []string{
-	"CodePoint",
-	"Name",
-	"GeneralCategory",
-	"CanonicalCombiningClass",
-	"BidiClass",
-	"DecompositionType",
-	"DecompositionMapping",
-	"NumericType",
-	"NumericValue",
-	"BidiMirrored",
-	"Unicode1Name",
-	"ISOComment",
-	"SimpleUppercaseMapping",
-	"SimpleLowercaseMapping",
-	"SimpleTitlecaseMapping",
+	FCodePoint:                   "CodePoint",
+	FName:                        "Name",
+	FGeneralCategory:             "GeneralCategory",
+	FCanonicalCombiningClass:     "CanonicalCombiningClass",
+	FBidiClass:                   "BidiClass",
+	FDecompositionTypeAndMapping: "DecompositionTypeAndMapping",
+	FNumericType:                 "NumericType",
+	FNumericDigit:                "NumericDigit",
+	FNumericValue:                "NumericValue",
+	FBidiMirrored:                "BidiMirrored",
+	FUnicode1Name:                "Unicode1Name",
+	FISOComment:                  "ISOComment",
+	FSimpleUppercaseMapping:      "SimpleUppercaseMapping",
+	FSimpleLowercaseMapping:      "SimpleLowercaseMapping",
+	FSimpleTitlecaseMapping:      "SimpleTitlecaseMapping",
 }
 
 // This contains only the properties we're interested in.
@@ -156,7 +156,7 @@ const (
 )
 
 func parseCategory(line string) (state State) {
-	field := strings.Split(line, ";", -1)
+	field := strings.Split(line, ";")
 	if len(field) != NumField {
 		logger.Fatalf("%5s: %d fields (expected %d)\n", line, len(field), NumField)
 	}
@@ -253,7 +253,7 @@ func all(scripts map[string][]Script) []string {
 // Extract the version number from the URL
 func version() string {
 	// Break on slashes and look for the first numeric field
-	fields := strings.Split(*url, "/", -1)
+	fields := strings.Split(*url, "/")
 	for _, f := range fields {
 		if len(f) > 0 && '0' <= f[0] && f[0] <= '9' {
 			return f
@@ -336,7 +336,7 @@ func loadCasefold() {
 		if line[0] == '#' {
 			continue
 		}
-		field := strings.Split(line, "; ", -1)
+		field := strings.Split(line, "; ")
 		if len(field) != 4 {
 			logger.Fatalf("CaseFolding.txt %.5s...: %d fields (expected %d)\n", line, len(field), 4)
 		}
@@ -372,7 +372,7 @@ func printCategories() {
 		return
 	}
 	// Find out which categories to dump
-	list := strings.Split(*tablelist, ",", -1)
+	list := strings.Split(*tablelist, ",")
 	if *tablelist == "all" {
 		list = allCategories()
 	}
@@ -588,7 +588,7 @@ func parseScript(line string, scripts map[string][]Script) {
 	if len(line) == 0 {
 		return
 	}
-	field := strings.Split(line, ";", -1)
+	field := strings.Split(line, ";")
 	if len(field) != 2 {
 		logger.Fatalf("%s: %d fields (expected 2)\n", line, len(field))
 	}
@@ -685,7 +685,7 @@ func printScriptOrProperty(doProps bool) {
 	resp.Body.Close()
 
 	// Find out which scripts to dump
-	list := strings.Split(flaglist, ",", -1)
+	list := strings.Split(flaglist, ",")
 	if flaglist == "all" {
 		list = all(table)
 	}
@@ -1042,7 +1042,7 @@ func printCasefold() {
 		if orb == nil {
 			continue
 		}
-		sort.SortInts(orb)
+		sort.Ints(orb)
 		c := orb[len(orb)-1]
 		for _, d := range orb {
 			chars[c].caseOrbit = d
diff --git a/src/pkg/xml/Makefile b/src/pkg/xml/Makefile
index b780fac..d66c498 100644
--- a/src/pkg/xml/Makefile
+++ b/src/pkg/xml/Makefile
@@ -7,6 +7,7 @@ include ../../Make.inc
 TARG=xml
 
 GOFILES=\
+	marshal.go\
 	read.go\
 	xml.go\
 
diff --git a/src/pkg/xml/atom_test.go b/src/pkg/xml/atom_test.go
new file mode 100644
index 0000000..d365510
--- /dev/null
+++ b/src/pkg/xml/atom_test.go
@@ -0,0 +1,50 @@
+// 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 xml
+
+var atomValue = &Feed{
+	Title:   "Example Feed",
+	Link:    []Link{{Href: "http://example.org/"}},
+	Updated: ParseTime("2003-12-13T18:30:02Z"),
+	Author:  Person{Name: "John Doe"},
+	Id:      "urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6",
+
+	Entry: []Entry{
+		{
+			Title:   "Atom-Powered Robots Run Amok",
+			Link:    []Link{{Href: "http://example.org/2003/12/13/atom03"}},
+			Id:      "urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a",
+			Updated: ParseTime("2003-12-13T18:30:02Z"),
+			Summary: NewText("Some text."),
+		},
+	},
+}
+
+var atomXml = `` +
+	`<feed xmlns="http://www.w3.org/2005/Atom">` +
+	`<Title>Example Feed</Title>` +
+	`<Id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6</Id>` +
+	`<Link href="http://example.org/"></Link>` +
+	`<Updated>2003-12-13T18:30:02Z</Updated>` +
+	`<Author><Name>John Doe</Name><URI></URI><Email></Email></Author>` +
+	`<Entry>` +
+	`<Title>Atom-Powered Robots Run Amok</Title>` +
+	`<Id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</Id>` +
+	`<Link href="http://example.org/2003/12/13/atom03"></Link>` +
+	`<Updated>2003-12-13T18:30:02Z</Updated>` +
+	`<Author><Name></Name><URI></URI><Email></Email></Author>` +
+	`<Summary>Some text.</Summary>` +
+	`</Entry>` +
+	`</feed>`
+
+func ParseTime(str string) Time {
+	return Time(str)
+}
+
+func NewText(text string) Text {
+	return Text{
+		Body: text,
+	}
+}
diff --git a/src/pkg/xml/embed_test.go b/src/pkg/xml/embed_test.go
index abfe781..ec7f478 100644
--- a/src/pkg/xml/embed_test.go
+++ b/src/pkg/xml/embed_test.go
@@ -12,14 +12,14 @@ type C struct {
 }
 
 type A struct {
-	XMLName Name "http://domain a"
+	XMLName Name `xml:"http://domain a"`
 	C
 	B      B
 	FieldA string
 }
 
 type B struct {
-	XMLName Name "b"
+	XMLName Name `xml:"b"`
 	C
 	FieldB string
 }
@@ -65,7 +65,7 @@ func TestEmbedded1(t *testing.T) {
 }
 
 type A2 struct {
-	XMLName Name "http://domain a"
+	XMLName Name `xml:"http://domain a"`
 	XY      string
 	Xy      string
 }
@@ -92,7 +92,7 @@ func TestEmbedded2(t *testing.T) {
 }
 
 type A3 struct {
-	XMLName Name "http://domain a"
+	XMLName Name `xml:"http://domain a"`
 	xy      string
 }
 
@@ -108,7 +108,7 @@ func TestEmbedded3(t *testing.T) {
 }
 
 type A4 struct {
-	XMLName Name "http://domain a"
+	XMLName Name `xml:"http://domain a"`
 	Any     string
 }
 
diff --git a/src/pkg/xml/marshal.go b/src/pkg/xml/marshal.go
new file mode 100644
index 0000000..2ac03a9
--- /dev/null
+++ b/src/pkg/xml/marshal.go
@@ -0,0 +1,228 @@
+// 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 xml
+
+import (
+	"bufio"
+	"io"
+	"os"
+	"reflect"
+	"strconv"
+	"strings"
+)
+
+const (
+	// A generic XML header suitable for use with the output of Marshal and MarshalIndent.
+	// This is not automatically added to any output of this package, it is provided as a
+	// convenience.
+	Header = `<?xml version="1.0" encoding="UTF-8">\n`
+)
+
+// A Marshaler can produce well-formatted XML representing its internal state.
+// It is used by both Marshal and MarshalIndent.
+type Marshaler interface {
+	MarshalXML() ([]byte, os.Error)
+}
+
+type printer struct {
+	*bufio.Writer
+}
+
+// Marshal writes an XML-formatted representation of v to w.
+//
+// If v implements Marshaler, then Marshal calls its MarshalXML method.
+// Otherwise, Marshal uses the following procedure to create the XML.
+//
+// Marshal handles an array or slice by marshalling each of the elements.
+// Marshal handles a pointer by marshalling the value it points at or, if the
+// pointer is nil, by writing nothing.  Marshal handles an interface value by
+// marshalling the value it contains or, if the interface value is nil, by
+// writing nothing.  Marshal handles all other data by writing a single XML
+// element containing the data.
+//
+// The name of that XML element is taken from, in order of preference:
+//     - the tag on an XMLName field, if the data is a struct
+//     - the value of an XMLName field of type xml.Name
+//     - the tag of the struct field used to obtain the data
+//     - the name of the struct field used to obtain the data
+//     - the name '???'.
+//
+// The XML element for a struct contains marshalled elements for each of the
+// exported fields of the struct, with these exceptions:
+//     - the XMLName field, described above, is omitted.
+//     - a field with tag "attr" becomes an attribute in the XML element.
+//     - a field with tag "chardata" is written as character data,
+//        not as an XML element.
+//     - a field with tag "innerxml" is written verbatim,
+//        not subject to the usual marshalling procedure.
+//
+// Marshal will return an error if asked to marshal a channel, function, or map.
+func Marshal(w io.Writer, v interface{}) (err os.Error) {
+	p := &printer{bufio.NewWriter(w)}
+	err = p.marshalValue(reflect.ValueOf(v), "???")
+	p.Flush()
+	return err
+}
+
+func (p *printer) marshalValue(val reflect.Value, name string) os.Error {
+	if !val.IsValid() {
+		return nil
+	}
+
+	kind := val.Kind()
+	typ := val.Type()
+
+	// Try Marshaler
+	if typ.NumMethod() > 0 {
+		if marshaler, ok := val.Interface().(Marshaler); ok {
+			bytes, err := marshaler.MarshalXML()
+			if err != nil {
+				return err
+			}
+			p.Write(bytes)
+			return nil
+		}
+	}
+
+	// Drill into pointers/interfaces
+	if kind == reflect.Ptr || kind == reflect.Interface {
+		if val.IsNil() {
+			return nil
+		}
+		return p.marshalValue(val.Elem(), name)
+	}
+
+	// Slices and arrays iterate over the elements. They do not have an enclosing tag.
+	if (kind == reflect.Slice || kind == reflect.Array) && typ.Elem().Kind() != reflect.Uint8 {
+		for i, n := 0, val.Len(); i < n; i++ {
+			if err := p.marshalValue(val.Index(i), name); err != nil {
+				return err
+			}
+		}
+		return nil
+	}
+
+	// Find XML name
+	xmlns := ""
+	if kind == reflect.Struct {
+		if f, ok := typ.FieldByName("XMLName"); ok {
+			if tag := f.Tag.Get("xml"); tag != "" {
+				if i := strings.Index(tag, " "); i >= 0 {
+					xmlns, name = tag[:i], tag[i+1:]
+				} else {
+					name = tag
+				}
+			} else if v, ok := val.FieldByIndex(f.Index).Interface().(Name); ok && v.Local != "" {
+				xmlns, name = v.Space, v.Local
+			}
+		}
+	}
+
+	p.WriteByte('<')
+	p.WriteString(name)
+
+	// Attributes
+	if kind == reflect.Struct {
+		if len(xmlns) > 0 {
+			p.WriteString(` xmlns="`)
+			Escape(p, []byte(xmlns))
+			p.WriteByte('"')
+		}
+
+		for i, n := 0, typ.NumField(); i < n; i++ {
+			if f := typ.Field(i); f.PkgPath == "" && f.Tag.Get("xml") == "attr" {
+				if f.Type.Kind() == reflect.String {
+					if str := val.Field(i).String(); str != "" {
+						p.WriteByte(' ')
+						p.WriteString(strings.ToLower(f.Name))
+						p.WriteString(`="`)
+						Escape(p, []byte(str))
+						p.WriteByte('"')
+					}
+				}
+			}
+		}
+	}
+	p.WriteByte('>')
+
+	switch k := val.Kind(); k {
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		p.WriteString(strconv.Itoa64(val.Int()))
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+		p.WriteString(strconv.Uitoa64(val.Uint()))
+	case reflect.Float32, reflect.Float64:
+		p.WriteString(strconv.Ftoa64(val.Float(), 'g', -1))
+	case reflect.String:
+		Escape(p, []byte(val.String()))
+	case reflect.Bool:
+		p.WriteString(strconv.Btoa(val.Bool()))
+	case reflect.Array:
+		// will be [...]byte
+		bytes := make([]byte, val.Len())
+		for i := range bytes {
+			bytes[i] = val.Index(i).Interface().(byte)
+		}
+		Escape(p, bytes)
+	case reflect.Slice:
+		// will be []byte
+		bytes := val.Interface().([]byte)
+		Escape(p, bytes)
+	case reflect.Struct:
+		for i, n := 0, val.NumField(); i < n; i++ {
+			if f := typ.Field(i); f.Name != "XMLName" && f.PkgPath == "" {
+				name := f.Name
+				switch tag := f.Tag.Get("xml"); tag {
+				case "":
+				case "chardata":
+					if tk := f.Type.Kind(); tk == reflect.String {
+						p.Write([]byte(val.Field(i).String()))
+					} else if tk == reflect.Slice {
+						if elem, ok := val.Field(i).Interface().([]byte); ok {
+							Escape(p, elem)
+						}
+					}
+					continue
+				case "innerxml":
+					iface := val.Field(i).Interface()
+					switch raw := iface.(type) {
+					case []byte:
+						p.Write(raw)
+						continue
+					case string:
+						p.WriteString(raw)
+						continue
+					}
+				case "attr":
+					continue
+				default:
+					name = tag
+				}
+
+				if err := p.marshalValue(val.Field(i), name); err != nil {
+					return err
+				}
+			}
+		}
+	default:
+		return &UnsupportedTypeError{typ}
+	}
+
+	p.WriteByte('<')
+	p.WriteByte('/')
+	p.WriteString(name)
+	p.WriteByte('>')
+
+	return nil
+}
+
+// A MarshalXMLError is returned when Marshal or MarshalIndent encounter a type
+// that cannot be converted into XML.
+type UnsupportedTypeError struct {
+	Type reflect.Type
+}
+
+func (e *UnsupportedTypeError) String() string {
+	return "xml: unsupported type: " + e.Type.String()
+}
diff --git a/src/pkg/xml/marshal_test.go b/src/pkg/xml/marshal_test.go
new file mode 100644
index 0000000..77b2e72
--- /dev/null
+++ b/src/pkg/xml/marshal_test.go
@@ -0,0 +1,299 @@
+// 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 xml
+
+import (
+	"reflect"
+	"testing"
+
+	"os"
+	"bytes"
+	"strings"
+	"strconv"
+)
+
+type DriveType int
+
+const (
+	HyperDrive DriveType = iota
+	ImprobabilityDrive
+)
+
+type Passenger struct {
+	Name   []string `xml:"name"`
+	Weight float32  `xml:"weight"`
+}
+
+type Ship struct {
+	XMLName Name `xml:"spaceship"`
+
+	Name      string       `xml:"attr"`
+	Pilot     string       `xml:"attr"`
+	Drive     DriveType    `xml:"drive"`
+	Age       uint         `xml:"age"`
+	Passenger []*Passenger `xml:"passenger"`
+	secret    string
+}
+
+type RawXML string
+
+func (rx RawXML) MarshalXML() ([]byte, os.Error) {
+	return []byte(rx), nil
+}
+
+type NamedType string
+
+type Port struct {
+	XMLName Name   `xml:"port"`
+	Type    string `xml:"attr"`
+	Number  string `xml:"chardata"`
+}
+
+type Domain struct {
+	XMLName Name   `xml:"domain"`
+	Country string `xml:"attr"`
+	Name    []byte `xml:"chardata"`
+}
+
+type SecretAgent struct {
+	XMLName   Name   `xml:"agent"`
+	Handle    string `xml:"attr"`
+	Identity  string
+	Obfuscate string `xml:"innerxml"`
+}
+
+var nilStruct *Ship
+
+var marshalTests = []struct {
+	Value     interface{}
+	ExpectXML string
+}{
+	// Test nil marshals to nothing
+	{Value: nil, ExpectXML: ``},
+	{Value: nilStruct, ExpectXML: ``},
+
+	// Test value types (no tag name, so ???)
+	{Value: true, ExpectXML: `<???>true</???>`},
+	{Value: int(42), ExpectXML: `<???>42</???>`},
+	{Value: int8(42), ExpectXML: `<???>42</???>`},
+	{Value: int16(42), ExpectXML: `<???>42</???>`},
+	{Value: int32(42), ExpectXML: `<???>42</???>`},
+	{Value: uint(42), ExpectXML: `<???>42</???>`},
+	{Value: uint8(42), ExpectXML: `<???>42</???>`},
+	{Value: uint16(42), ExpectXML: `<???>42</???>`},
+	{Value: uint32(42), ExpectXML: `<???>42</???>`},
+	{Value: float32(1.25), ExpectXML: `<???>1.25</???>`},
+	{Value: float64(1.25), ExpectXML: `<???>1.25</???>`},
+	{Value: uintptr(0xFFDD), ExpectXML: `<???>65501</???>`},
+	{Value: "gopher", ExpectXML: `<???>gopher</???>`},
+	{Value: []byte("gopher"), ExpectXML: `<???>gopher</???>`},
+	{Value: "</>", ExpectXML: `<???></></???>`},
+	{Value: []byte("</>"), ExpectXML: `<???></></???>`},
+	{Value: [3]byte{'<', '/', '>'}, ExpectXML: `<???></></???>`},
+	{Value: NamedType("potato"), ExpectXML: `<???>potato</???>`},
+	{Value: []int{1, 2, 3}, ExpectXML: `<???>1</???><???>2</???><???>3</???>`},
+	{Value: [3]int{1, 2, 3}, ExpectXML: `<???>1</???><???>2</???><???>3</???>`},
+
+	// Test innerxml
+	{Value: RawXML("</>"), ExpectXML: `</>`},
+	{
+		Value: &SecretAgent{
+			Handle:    "007",
+			Identity:  "James Bond",
+			Obfuscate: "<redacted/>",
+		},
+		//ExpectXML: `<agent handle="007"><redacted/></agent>`,
+		ExpectXML: `<agent handle="007"><Identity>James Bond</Identity><redacted/></agent>`,
+	},
+
+	// Test structs
+	{Value: &Port{Type: "ssl", Number: "443"}, ExpectXML: `<port type="ssl">443</port>`},
+	{Value: &Port{Number: "443"}, ExpectXML: `<port>443</port>`},
+	{Value: &Port{Type: "<unix>"}, ExpectXML: `<port type="<unix>"></port>`},
+	{Value: &Domain{Name: []byte("google.com&friends")}, ExpectXML: `<domain>google.com&friends</domain>`},
+	{Value: atomValue, ExpectXML: atomXml},
+	{
+		Value: &Ship{
+			Name:  "Heart of Gold",
+			Pilot: "Computer",
+			Age:   1,
+			Drive: ImprobabilityDrive,
+			Passenger: []*Passenger{
+				&Passenger{
+					Name:   []string{"Zaphod", "Beeblebrox"},
+					Weight: 7.25,
+				},
+				&Passenger{
+					Name:   []string{"Trisha", "McMillen"},
+					Weight: 5.5,
+				},
+				&Passenger{
+					Name:   []string{"Ford", "Prefect"},
+					Weight: 7,
+				},
+				&Passenger{
+					Name:   []string{"Arthur", "Dent"},
+					Weight: 6.75,
+				},
+			},
+		},
+		ExpectXML: `<spaceship name="Heart of Gold" pilot="Computer">` +
+			`<drive>` + strconv.Itoa(int(ImprobabilityDrive)) + `</drive>` +
+			`<age>1</age>` +
+			`<passenger>` +
+			`<name>Zaphod</name>` +
+			`<name>Beeblebrox</name>` +
+			`<weight>7.25</weight>` +
+			`</passenger>` +
+			`<passenger>` +
+			`<name>Trisha</name>` +
+			`<name>McMillen</name>` +
+			`<weight>5.5</weight>` +
+			`</passenger>` +
+			`<passenger>` +
+			`<name>Ford</name>` +
+			`<name>Prefect</name>` +
+			`<weight>7</weight>` +
+			`</passenger>` +
+			`<passenger>` +
+			`<name>Arthur</name>` +
+			`<name>Dent</name>` +
+			`<weight>6.75</weight>` +
+			`</passenger>` +
+			`</spaceship>`,
+	},
+}
+
+func TestMarshal(t *testing.T) {
+	for idx, test := range marshalTests {
+		buf := bytes.NewBuffer(nil)
+		err := Marshal(buf, test.Value)
+		if err != nil {
+			t.Errorf("#%d: Error: %s", idx, err)
+			continue
+		}
+		if got, want := buf.String(), test.ExpectXML; got != want {
+			if strings.Contains(want, "\n") {
+				t.Errorf("#%d: marshal(%#v) - GOT:\n%s\nWANT:\n%s", idx, test.Value, got, want)
+			} else {
+				t.Errorf("#%d: marshal(%#v) = %#q want %#q", idx, test.Value, got, want)
+			}
+		}
+	}
+}
+
+var marshalErrorTests = []struct {
+	Value      interface{}
+	ExpectErr  string
+	ExpectKind reflect.Kind
+}{
+	{
+		Value:      make(chan bool),
+		ExpectErr:  "xml: unsupported type: chan bool",
+		ExpectKind: reflect.Chan,
+	},
+	{
+		Value: map[string]string{
+			"question": "What do you get when you multiply six by nine?",
+			"answer":   "42",
+		},
+		ExpectErr:  "xml: unsupported type: map[string] string",
+		ExpectKind: reflect.Map,
+	},
+	{
+		Value:      map[*Ship]bool{nil: false},
+		ExpectErr:  "xml: unsupported type: map[*xml.Ship] bool",
+		ExpectKind: reflect.Map,
+	},
+}
+
+func TestMarshalErrors(t *testing.T) {
+	for idx, test := range marshalErrorTests {
+		buf := bytes.NewBuffer(nil)
+		err := Marshal(buf, test.Value)
+		if got, want := err, test.ExpectErr; got == nil {
+			t.Errorf("#%d: want error %s", idx, want)
+			continue
+		} else if got.String() != want {
+			t.Errorf("#%d: marshal(%#v) = [error] %q, want %q", idx, test.Value, got, want)
+		}
+		if got, want := err.(*UnsupportedTypeError).Type.Kind(), test.ExpectKind; got != want {
+			t.Errorf("#%d: marshal(%#v) = [error kind] %s, want %s", idx, test.Value, got, want)
+		}
+	}
+}
+
+// Do invertibility testing on the various structures that we test
+func TestUnmarshal(t *testing.T) {
+	for i, test := range marshalTests {
+		// Skip the nil pointers
+		if i <= 1 {
+			continue
+		}
+
+		var dest interface{}
+
+		switch test.Value.(type) {
+		case *Ship, Ship:
+			dest = &Ship{}
+		case *Port, Port:
+			dest = &Port{}
+		case *Domain, Domain:
+			dest = &Domain{}
+		case *Feed, Feed:
+			dest = &Feed{}
+		default:
+			continue
+		}
+
+		buffer := bytes.NewBufferString(test.ExpectXML)
+		err := Unmarshal(buffer, dest)
+
+		// Don't compare XMLNames
+		switch fix := dest.(type) {
+		case *Ship:
+			fix.XMLName = Name{}
+		case *Port:
+			fix.XMLName = Name{}
+		case *Domain:
+			fix.XMLName = Name{}
+		case *Feed:
+			fix.XMLName = Name{}
+			fix.Author.InnerXML = ""
+			for i := range fix.Entry {
+				fix.Entry[i].Author.InnerXML = ""
+			}
+		}
+
+		if err != nil {
+			t.Errorf("#%d: unexpected error: %#v", i, err)
+		} else if got, want := dest, test.Value; !reflect.DeepEqual(got, want) {
+			t.Errorf("#%d: unmarshal(%#s) = %#v, want %#v", i, test.ExpectXML, got, want)
+		}
+	}
+}
+
+func BenchmarkMarshal(b *testing.B) {
+	idx := len(marshalTests) - 1
+	test := marshalTests[idx]
+
+	buf := bytes.NewBuffer(nil)
+	for i := 0; i < b.N; i++ {
+		Marshal(buf, test.Value)
+		buf.Truncate(0)
+	}
+}
+
+func BenchmarkUnmarshal(b *testing.B) {
+	idx := len(marshalTests) - 1
+	test := marshalTests[idx]
+	sm := &Ship{}
+	xml := []byte(test.ExpectXML)
+
+	for i := 0; i < b.N; i++ {
+		buffer := bytes.NewBuffer(xml)
+		Unmarshal(buffer, sm)
+	}
+}
diff --git a/src/pkg/xml/read.go b/src/pkg/xml/read.go
index 427c311..786b69f 100644
--- a/src/pkg/xml/read.go
+++ b/src/pkg/xml/read.go
@@ -31,16 +31,16 @@ import (
 // For example, given these definitions:
 //
 //	type Email struct {
-//		Where string "attr"
+//		Where string `xml:"attr"`
 //		Addr  string
 //	}
 //
 //	type Result struct {
-//		XMLName xml.Name "result"
+//		XMLName xml.Name `xml:"result"`
 //		Name	string
 //		Phone	string
 //		Email	[]Email
-//		Groups  []string "group>value"
+//		Groups  []string `xml:"group>value"`
 //	}
 //
 //	result := Result{Name: "name", Phone: "phone", Email: nil}
@@ -79,11 +79,13 @@ import (
 // Groups was assigned considering the element path provided in the
 // field tag.
 //
-// Because Unmarshal uses the reflect package, it can only
-// assign to upper case fields.  Unmarshal uses a case-insensitive
+// Because Unmarshal uses the reflect package, it can only assign
+// to exported (upper case) fields.  Unmarshal uses a case-insensitive
 // comparison to match XML element names to struct field names.
 //
-// Unmarshal maps an XML element to a struct using the following rules:
+// Unmarshal maps an XML element to a struct using the following rules.
+// In the rules, the tag of a field refers to the value associated with the
+// key 'xml' in the struct field's tag (see the example above).
 //
 //   * If the struct has a field of type []byte or string with tag "innerxml",
 //      Unmarshal accumulates the raw XML nested inside the element
@@ -92,9 +94,9 @@ import (
 //   * If the struct has a field named XMLName of type xml.Name,
 //      Unmarshal records the element name in that field.
 //
-//   * If the XMLName field has an associated tag string of the form
-//      "tag" or "namespace-URL tag", the XML element must have
-//      the given tag (and, optionally, name space) or else Unmarshal
+//   * If the XMLName field has an associated tag of the form
+//      "name" or "namespace-URL name", the XML element must have
+//      the given name (and, optionally, name space) or else Unmarshal
 //      returns an error.
 //
 //   * If the XML element has an attribute whose name matches a
@@ -112,14 +114,14 @@ import (
 //      field, the comments are discarded.
 //
 //   * If the XML element contains a sub-element whose name matches
-//      the prefix of a struct field tag formatted as "a>b>c", unmarshal
+//      the prefix of a tag formatted as "a>b>c", unmarshal
 //      will descend into the XML structure looking for elements with the
 //      given names, and will map the innermost elements to that struct field.
-//      A struct field tag starting with ">" is equivalent to one starting
+//      A tag starting with ">" is equivalent to one starting
 //      with the field name followed by ">".
 //
 //   * If the XML element contains a sub-element whose name
-//      matches a struct field whose tag is neither "attr" nor "chardata",
+//      matches a field whose tag is neither "attr" nor "chardata",
 //      Unmarshal maps the sub-element to that struct field.
 //      Otherwise, if the struct has a field named Any, unmarshal
 //      maps the sub-element to that struct field.
@@ -297,8 +299,7 @@ func (p *Parser) unmarshal(val reflect.Value, start *StartElement) os.Error {
 		// Assign name.
 		if f, ok := typ.FieldByName("XMLName"); ok {
 			// Validate element name.
-			if f.Tag != "" {
-				tag := f.Tag
+			if tag := f.Tag.Get("xml"); tag != "" {
 				ns := ""
 				i := strings.LastIndex(tag, " ")
 				if i >= 0 {
@@ -330,7 +331,7 @@ func (p *Parser) unmarshal(val reflect.Value, start *StartElement) os.Error {
 		// Also, determine whether we need to save character data or comments.
 		for i, n := 0, typ.NumField(); i < n; i++ {
 			f := typ.Field(i)
-			switch f.Tag {
+			switch f.Tag.Get("xml") {
 			case "attr":
 				strv := sv.FieldByIndex(f.Index)
 				// Look for attribute.
@@ -366,15 +367,15 @@ func (p *Parser) unmarshal(val reflect.Value, start *StartElement) os.Error {
 				}
 
 			default:
-				if strings.Contains(f.Tag, ">") {
+				if tag := f.Tag.Get("xml"); strings.Contains(tag, ">") {
 					if fieldPaths == nil {
 						fieldPaths = make(map[string]pathInfo)
 					}
-					path := strings.ToLower(f.Tag)
-					if strings.HasPrefix(f.Tag, ">") {
+					path := strings.ToLower(tag)
+					if strings.HasPrefix(tag, ">") {
 						path = strings.ToLower(f.Name) + path
 					}
-					if strings.HasSuffix(f.Tag, ">") {
+					if strings.HasSuffix(tag, ">") {
 						path = path[:len(path)-1]
 					}
 					err := addFieldPath(sv, fieldPaths, path, f.Index)
@@ -574,7 +575,7 @@ func tagError(sv reflect.Value, idx1 []int, idx2 []int) os.Error {
 	t := sv.Type()
 	f1 := t.FieldByIndex(idx1)
 	f2 := t.FieldByIndex(idx2)
-	return &TagPathError{t, f1.Name, f1.Tag, f2.Name, f2.Tag}
+	return &TagPathError{t, f1.Name, f1.Tag.Get("xml"), f2.Name, f2.Tag.Get("xml")}
 }
 
 // unmarshalPaths walks down an XML structure looking for
diff --git a/src/pkg/xml/read_test.go b/src/pkg/xml/read_test.go
index e07cb15..2126da3 100644
--- a/src/pkg/xml/read_test.go
+++ b/src/pkg/xml/read_test.go
@@ -78,7 +78,7 @@ not being used from outside intra_region_diff.py.
 </summary></entry></feed> 	   `
 
 type Feed struct {
-	XMLName Name "http://www.w3.org/2005/Atom feed"
+	XMLName Name `xml:"http://www.w3.org/2005/Atom feed"`
 	Title   string
 	Id      string
 	Link    []Link
@@ -97,20 +97,20 @@ type Entry struct {
 }
 
 type Link struct {
-	Rel  string "attr"
-	Href string "attr"
+	Rel  string `xml:"attr"`
+	Href string `xml:"attr"`
 }
 
 type Person struct {
 	Name     string
 	URI      string
 	Email    string
-	InnerXML string "innerxml"
+	InnerXML string `xml:"innerxml"`
 }
 
 type Text struct {
-	Type string "attr"
-	Body string "chardata"
+	Type string `xml:"attr"`
+	Body string `xml:"chardata"`
 }
 
 type Time string
@@ -255,18 +255,18 @@ type PathTestItem struct {
 }
 
 type PathTestA struct {
-	Items         []PathTestItem ">item1"
+	Items         []PathTestItem `xml:">item1"`
 	Before, After string
 }
 
 type PathTestB struct {
-	Other         []PathTestItem "items>Item1"
+	Other         []PathTestItem `xml:"items>Item1"`
 	Before, After string
 }
 
 type PathTestC struct {
-	Values1       []string "items>item1>value"
-	Values2       []string "items>item2>value"
+	Values1       []string `xml:"items>item1>value"`
+	Values2       []string `xml:"items>item2>value"`
 	Before, After string
 }
 
@@ -275,7 +275,7 @@ type PathTestSet struct {
 }
 
 type PathTestD struct {
-	Other         PathTestSet "items>"
+	Other         PathTestSet `xml:"items>"`
 	Before, After string
 }
 
@@ -299,15 +299,15 @@ func TestUnmarshalPaths(t *testing.T) {
 }
 
 type BadPathTestA struct {
-	First  string "items>item1"
-	Other  string "items>item2"
-	Second string "items>"
+	First  string `xml:"items>item1"`
+	Other  string `xml:"items>item2"`
+	Second string `xml:"items>"`
 }
 
 type BadPathTestB struct {
-	Other  string "items>item2>value"
-	First  string "items>item1"
-	Second string "items>item1>value"
+	Other  string `xml:"items>item2>value"`
+	First  string `xml:"items>item1"`
+	Second string `xml:"items>item1>value"`
 }
 
 var badPathTests = []struct {
@@ -342,13 +342,13 @@ type AttrTest struct {
 }
 
 type Test1 struct {
-	Int   int     "attr"
-	Float float64 "attr"
-	Uint8 uint8   "attr"
+	Int   int     `xml:"attr"`
+	Float float64 `xml:"attr"`
+	Uint8 uint8   `xml:"attr"`
 }
 
 type Test2 struct {
-	Bool bool "attr"
+	Bool bool `xml:"attr"`
 }
 
 const attrString = `
diff --git a/src/run.bash b/src/run.bash
index bb3d06c..d125fd4 100755
--- a/src/run.bash
+++ b/src/run.bash
@@ -34,7 +34,7 @@ if $rebuild; then
 	(xcd pkg
 		gomake clean
 		time gomake install
-	) || exit $i
+	) || exit $?
 fi
 
 (xcd pkg
diff --git a/src/version.bash b/src/version.bash
index b45f15a..ce5a996 100755
--- a/src/version.bash
+++ b/src/version.bash
@@ -16,8 +16,15 @@ if [ $? != 0 ]; then
 	VERSION=$(echo $OLD | awk '{print $1}')
 fi
 
-# Find most recent known release tag.
+# Get branch type
+BRANCH=release
+if [ "$(hg identify -b 2>/dev/null)" == "default" ]; then
+	BRANCH=weekly
+fi
+
+# Find most recent known release or weekly tag.
 TAG=$(hg tags |
+	grep $BRANCH |
 	sed 's/:.*//' |
 	sort -rn -k2 |
 	awk -v ver=$VERSION '$2 <= ver && $1~/^(release|weekly)\./ {print $1}' |
diff --git a/test/fixedbugs/bug345.dir/io.go b/test/fixedbugs/bug345.dir/io.go
new file mode 100644
index 0000000..1d695c3
--- /dev/null
+++ b/test/fixedbugs/bug345.dir/io.go
@@ -0,0 +1,15 @@
+// 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 io
+
+type Writer interface {
+	WrongWrite()
+}
+
+type SectionReader struct {
+	X int
+}
+
+func SR(*SectionReader) {}
diff --git a/test/fixedbugs/bug345.dir/main.go b/test/fixedbugs/bug345.dir/main.go
new file mode 100644
index 0000000..5bdc713
--- /dev/null
+++ b/test/fixedbugs/bug345.dir/main.go
@@ -0,0 +1,28 @@
+// 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 main
+
+import (
+	"bufio"
+	"./io"
+	goio "io"
+)
+
+func main() {
+	// The errors here complain that io.X != io.X
+	// for different values of io so they should be
+	// showing the full import path, which for the
+	// "./io" import is really ..../go/test/io.
+	// For example:
+	//
+	// main.go:25: cannot use w (type "/Users/rsc/g/go/test/fixedbugs/bug345.dir/io".Writer) as type "io".Writer in function argument:
+	//	io.Writer does not implement io.Writer (missing Write method)
+	// main.go:27: cannot use &x (type *"io".SectionReader) as type *"/Users/rsc/g/go/test/fixedbugs/bug345.dir/io".SectionReader in function argument
+
+	var w io.Writer
+	bufio.NewWriter(w)  // ERROR "test/io"
+	var x goio.SectionReader
+	io.SR(&x)  // ERROR "test/io"
+}
diff --git a/test/fixedbugs/bug345.go b/test/fixedbugs/bug345.go
new file mode 100644
index 0000000..874710c
--- /dev/null
+++ b/test/fixedbugs/bug345.go
@@ -0,0 +1,7 @@
+// $G $D/$F.dir/io.go && errchk $G -e $D/$F.dir/main.go
+
+// 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 ignored

-- 
Packaging for Google Go



More information about the Pkg-google-commits mailing list