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 {
        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]
                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 == "":
 // 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
                }
 
 // 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:
                }
 
                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)
                }
        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
                }
                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
                        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
 
                        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
 
 
 // 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] {
 
                }
                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
 
 // 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 {
 
        procattr.go\
        reflect.go\
        sortslice.go\
+       stringssplit.go\
        typecheck.go\
 
 include ../../Make.cmd
 
 
        if *allowedRewrites != "" {
                allowed = make(map[string]bool)
-               for _, f := range strings.Split(*allowedRewrites, ",", -1) {
+               for _, f := range strings.Split(*allowedRewrites, ",") {
                        allowed[f] = true
                }
        }
 
--- /dev/null
+// 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
+}
 
--- /dev/null
+// 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)
+}
+`,
+       },
+}
 
        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,
        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 {
 
        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,
        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() {
 
        // 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 {
 
                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)
 
 // 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
        }
 
        flag.Parse()
 
        if *printfuncs != "" {
-               for _, name := range strings.Split(*printfuncs, ",", -1) {
+               for _, name := range strings.Split(*printfuncs, ",") {
                        if len(name) == 0 {
                                flag.Usage()
                        }
 
        // 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])
 
        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.
 
 // 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
 
        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 {
 
 
 import (
        . "bytes"
+       "reflect"
        "testing"
        "unicode"
        "utf8"
 
 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)
 
 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)
                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)
+                       }
+               }
        }
 }
 
 
 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)
                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)
+                       }
+               }
        }
 }
 
 
 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":
 
                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
 
                                        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)
 
                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)
        }
 
        }
 
        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
                }
 
                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 = "."
 
                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
                }
                        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
                        }
 
                }
                println("Attached to", pid)
        } else {
-               parts := strings.Split(path, " ", -1)
+               parts := strings.Split(path, " ")
                if len(parts) == 0 {
                        fname = ""
                } else {
 
 // 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)
 
        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
 
                }
 
                // 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 {
 
 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
 
                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
 
                }
                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)
 
 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
                }
        }
 
        for _, line := range lines {
-               parts := strings.Split(strings.TrimSpace(line), ";", -1)
+               parts := strings.Split(strings.TrimSpace(line), ";")
                if len(parts) == 1 && parts[0] == "" {
                        continue
                }
 
                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")
 
        }
 
        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]
 }
 
 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
                        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))
 
                }
                return nil, err
        }
-       f := strings.Split(line, " ", 3)
+       f := strings.SplitN(line, " ", 3)
        if len(f) < 2 {
                return nil, &badStringError{"malformed HTTP response", line}
        }
 
        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, "<!-- ")
 
                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)
                }
 
                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
 
        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 {
 
                        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])
                }
                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
 
 // 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{""}
        }
 
 }
 
 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")
        }
 
 }
 
 func decode2231Enc(v string) string {
-       sv := strings.Split(v, "'", 3)
+       sv := strings.SplitN(v, "'", 3)
        if len(sv) != 3 {
                return ""
        }
 
 
 // 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) }
 
        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,
 
                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
 
                        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
 
 */
 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")
        }
 
                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 {
                }
        }
        if mechs, ok := ext["AUTH"]; ok {
-               c.auth = strings.Split(mechs, " ", -1)
+               c.auth = strings.Split(mechs, " ")
        }
        c.ext = ext
        return err
 
 }
 
 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)
 
 // 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 {
 // 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 {
                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
 
        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 {
 
 
 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
 
 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
                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)
+                       }
+               }
        }
 }
 
 
 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
                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)
+                       }
+               }
        }
 }
 
        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
 
        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() {
 
                }
        }
        words[len(words)-1] = lastWord[0:bar]
-       formatters = strings.Split(lastWord[bar+1:], "|", -1)
+       formatters = strings.Split(lastWord[bar+1:], "|")
        return
 }
 
 
        if len(*cpuListStr) == 0 {
                cpuList = append(cpuList, runtime.GOMAXPROCS(-1))
        } else {
-               for _, val := range strings.Split(*cpuListStr, ",", -1) {
+               for _, val := range strings.Split(*cpuListStr, ",") {
                        cpu, err := strconv.Atoi(val)
                        if err != nil || cpu <= 0 {
                                println("invalid value for -test.cpu")
 
 )
 
 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)
        }
 // 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
                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)
                }
                return
        }
        // Find out which categories to dump
-       list := strings.Split(*tablelist, ",", -1)
+       list := strings.Split(*tablelist, ",")
        if *tablelist == "all" {
                list = allCategories()
        }
        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))
        }
        resp.Body.Close()
 
        // Find out which scripts to dump
-       list := strings.Split(flaglist, ",", -1)
+       list := strings.Split(flaglist, ",")
        if flaglist == "all" {
                list = all(table)
        }