replay CL 19916 and CL 19913 now that the build can handle them

TBR=r
OCL=19924
CL=19934
diff --git a/src/lib/bufio.go b/src/lib/bufio.go
index f41c4cd..11813d6 100644
--- a/src/lib/bufio.go
+++ b/src/lib/bufio.go
@@ -3,8 +3,12 @@
 // license that can be found in the LICENSE file.
 
 package bufio
-import "os"
-import "io"
+
+import (
+	"os";
+	"io";
+	"utf8";
+)
 
 
 // TODO:
@@ -65,7 +69,7 @@
 	}
 
 	// Slide existing data to beginning.
-	if b.w >  b.r {
+	if b.w > b.r {
 		CopySlice(b.buf[0:b.w-b.r], b.buf[b.r:b.w]);
 		b.w -= b.r;
 	} else {
@@ -140,6 +144,30 @@
 	return nil
 }
 
+// Read a single Unicode character; returns the rune and its size.
+func (b *BufRead) ReadRune() (rune int, size int, err *os.Error) {
+	for b.r + utf8.UTFMax > b.w && !utf8.FullRune(b.buf[b.r:b.w]) {
+		n := b.w - b.r;
+		b.Fill();
+		if b.err != nil {
+			return 0, 0, b.err
+		}
+		if b.w - b.r == n {
+			// no bytes read
+			if b.r == b.w {
+				return 0, 0, EndOfFile
+			}
+			break;
+		}
+	}
+	rune, size = int(b.buf[b.r]), 1;
+	if rune >= 0x80 {
+		rune, size = utf8.DecodeRune(b.buf[b.r:b.w]);
+	}
+	b.r += size;
+	return rune, size, nil
+}
+
 // Helper function: look for byte c in array p,
 // returning its index or -1.
 func FindByte(p *[]byte, c byte) int {
diff --git a/src/lib/fmt/fmt_test.go b/src/lib/fmt/fmt_test.go
new file mode 100644
index 0000000..ec1e995
--- /dev/null
+++ b/src/lib/fmt/fmt_test.go
@@ -0,0 +1,164 @@
+// 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 fmt
+
+import (
+	"fmt";
+	"syscall";
+	"testing";
+)
+
+export func TestFmtInterface(t *testing.T) {
+	var i1 interface{};
+	i1 = "abc";
+	s := fmt.sprintf("%s", i1);
+	if s != "abc" {
+		t.Errorf(`fmt.sprintf("%%s", empty("abc")) = %q want %q`, s, "abc");
+	}
+}
+
+type FmtTest struct {
+	fmt string;
+	val interface { };
+	out string;
+}
+
+func Bytes(s string) *[]byte {
+	b := new([]byte, len(s)+1);
+	syscall.StringToBytes(b, s);
+	return b[0:len(s)];
+}
+
+const B32 uint32 = 1<<32 - 1
+const B64 uint64 = 1<<64 - 1
+
+var fmttests = []FmtTest{
+	// basic string
+	FmtTest{ "%s",	"abc",	"abc" },
+	FmtTest{ "%x",	"abc",	"616263" },
+	FmtTest{ "%x",	"xyz",	"78797a" },
+	FmtTest{ "%X",	"xyz",	"78797A" },
+	FmtTest{ "%q",	"abc",	`"abc"` },
+
+	// basic bytes
+	FmtTest{ "%s",	Bytes("abc"),	"abc" },
+	FmtTest{ "%x",	Bytes("abc"),	"616263" },
+	FmtTest{ "%x",	Bytes("xyz"),	"78797a" },
+	FmtTest{ "%X",	Bytes("xyz"),	"78797A" },
+	FmtTest{ "%q",	Bytes("abc"),	`"abc"` },
+
+	// escaped strings
+	FmtTest{ "%#q",	`abc`,		"`abc`" },
+	FmtTest{ "%#q",	`"`,		"`\"`" },
+	FmtTest{ "1 %#q", `\n`,		"1 `\\n`" },
+	FmtTest{ "2 %#q", "\n",		`2 "\n"` },
+	FmtTest{ "%q",	`"`,		`"\""` },
+	FmtTest{ "%q",	"\a\b\f\r\n\t\v",	`"\a\b\f\r\n\t\v"` },
+	FmtTest{ "%q",	"abc\xffdef",		`"abc\xffdef"` },
+	FmtTest{ "%q",	"\u263a",	`"\u263a"` },
+	FmtTest{ "%q",	"\U0010ffff",	`"\U0010ffff"` },
+
+	// width
+	FmtTest{ "%5s",		"abc",	"  abc" },
+	FmtTest{ "%-5s",	"abc",	"abc  " },
+	FmtTest{ "%05s",	"abc",	"00abc" },
+
+	// integers
+	FmtTest{ "%d",		12345,	"12345" },
+	FmtTest{ "%d",		-12345,	"-12345" },
+	FmtTest{ "%10d",	12345,	"     12345" },
+	FmtTest{ "%10d",	-12345,	"    -12345" },
+	FmtTest{ "%+10d",	12345,	"    +12345" },
+	FmtTest{ "%010d",	12345,	"0000012345" },
+	FmtTest{ "%010d",	-12345,	"-000012345" },
+	FmtTest{ "%-10d",	12345,	"12345     " },
+	FmtTest{ "%010.3d",	1,	"       001" },
+	FmtTest{ "%010.3d",	-1,	"      -001" },
+	FmtTest{ "%+d",		12345,	"+12345" },
+	FmtTest{ "%+d",		-12345,	"-12345" },
+	FmtTest{ "% d",		12345,	" 12345" },
+	FmtTest{ "% d",		-12345,	"-12345" },
+
+	// old test/fmt_test.go
+	FmtTest{ "%d",		1234,			"1234" },
+	FmtTest{ "%d",		-1234,			"-1234" },
+	FmtTest{ "%d",		uint(1234),		"1234" },
+	FmtTest{ "%d",		uint32(B32),		"4294967295" },
+	FmtTest{ "%d",		uint64(B64),		"18446744073709551615" },
+	FmtTest{ "%o",		01234,			"1234" },
+	FmtTest{ "%o",		uint32(B32),		"37777777777" },
+	FmtTest{ "%o",		uint64(B64),		"1777777777777777777777" },
+	FmtTest{ "%x",		0x1234abcd,		"1234abcd" },
+	FmtTest{ "%x",		B32-0x1234567,		"fedcba98" },
+	FmtTest{ "%X",		0x1234abcd,		"1234ABCD" },
+	FmtTest{ "%X",		B32-0x1234567,		"FEDCBA98" },
+	FmtTest{ "%x",		B64,			"ffffffffffffffff" },
+	FmtTest{ "%b",		7,			"111" },
+	FmtTest{ "%b",		B64,			"1111111111111111111111111111111111111111111111111111111111111111" },
+	FmtTest{ "%e",		float64(1),		"1.000000e+00" },
+	FmtTest{ "%e",		float64(1234.5678e3),	"1.234568e+06" },
+	FmtTest{ "%e",		float64(1234.5678e-8),	"1.234568e-05" },
+	FmtTest{ "%e",		float64(-7),		"-7.000000e+00" },
+	FmtTest{ "%e",		float64(-1e-9),		"-1.000000e-09" },
+	FmtTest{ "%f",		float64(1234.5678e3),	"1234567.800000" },
+	FmtTest{ "%f",		float64(1234.5678e-8),	"0.000012" },
+	FmtTest{ "%f",		float64(-7),		"-7.000000" },
+	FmtTest{ "%f",		float64(-1e-9),		"-0.000000" },
+	FmtTest{ "%g",		float64(1234.5678e3),	"1.2345678e+06" },
+	FmtTest{ "%g",		float32(1234.5678e3),	"1.2345678e+06" },
+	FmtTest{ "%g",		float64(1234.5678e-8),	"1.2345678e-05" },
+	FmtTest{ "%g",		float64(-7),		"-7" },
+	FmtTest{ "%g",		float64(-1e-9),		"-1e-09",	 },
+	FmtTest{ "%g",		float32(-1e-9),		"-1e-09" },
+	FmtTest{ "%c",		'x',			"x" },
+	FmtTest{ "%c",		0xe4,			"ä" },
+	FmtTest{ "%c",		0x672c,			"本" },
+	FmtTest{ "%c",		'日',			"日" },
+	FmtTest{ "%20.8d",	1234,			"            00001234" },
+	FmtTest{ "%20.8d",	-1234,			"           -00001234" },
+	FmtTest{ "%20d",	1234,			"                1234" },
+	FmtTest{ "%-20.8d",	1234,			"00001234            " },
+	FmtTest{ "%-20.8d",	-1234,			"-00001234           " },
+	FmtTest{ "%.20b",	7,			"00000000000000000111" },
+	FmtTest{ "%20.5s",	"qwertyuiop",		"               qwert" },
+	FmtTest{ "%.5s",	"qwertyuiop",		"qwert" },
+	FmtTest{ "%-20.5s",	"qwertyuiop",		"qwert               " },
+	FmtTest{ "%20c",	'x',			"                   x" },
+	FmtTest{ "%-20c",	'x',			"x                   " },
+	FmtTest{ "%20.6e",	1.2345e3,		"        1.234500e+03" },
+	FmtTest{ "%20.6e",	1.2345e-3,		"        1.234500e-03" },
+	FmtTest{ "%20e",	1.2345e3,		"        1.234500e+03" },
+	FmtTest{ "%20e",	1.2345e-3,		"        1.234500e-03" },
+	FmtTest{ "%20.8e",	1.2345e3,		"      1.23450000e+03" },
+	FmtTest{ "%20f",	float64(1.23456789e3),	"         1234.567890" },
+	FmtTest{ "%20f",	float64(1.23456789e-3),	"            0.001235" },
+	FmtTest{ "%20f",	float64(12345678901.23456789),	"  12345678901.234568" },
+	FmtTest{ "%-20f",	float64(1.23456789e3),	"1234.567890         " },
+	FmtTest{ "%20.8f",	float64(1.23456789e3),	"       1234.56789000" },
+	FmtTest{ "%20.8f",	float64(1.23456789e-3),	"          0.00123457" },
+	FmtTest{ "%g",		float64(1.23456789e3),	"1234.56789" },
+	FmtTest{ "%g",		float64(1.23456789e-3),	"0.00123456789" },
+	FmtTest{ "%g",		float64(1.23456789e20),	"1.23456789e+20" },
+	FmtTest{ "%20e",	sys.Inf(1),		"                +Inf" },
+	FmtTest{ "%-20f",	sys.Inf(-1),		"-Inf                " },
+	FmtTest{ "%20g",	sys.NaN(),		"                 NaN" },
+}
+
+export func TestSprintf(t *testing.T) {
+	for i := 0; i < len(fmttests); i++ {
+		tt := fmttests[i];
+		s := fmt.sprintf(tt.fmt, tt.val);
+		if s != tt.out {
+			if ss, ok := tt.val.(string); ok {
+				// Don't requote the already-quoted strings.
+				// It's too confusing to read the errors.
+				t.Errorf("fmt.sprintf(%q, %q) = %s want %s", tt.fmt, tt.val, s, tt.out);
+			} else {
+				t.Errorf("fmt.sprintf(%q, %v) = %q want %q", tt.fmt, tt.val, s, tt.out);
+			}
+		}
+	}
+}
+
diff --git a/src/lib/fmt/format.go b/src/lib/fmt/format.go
index 058c619..64d6c9b 100644
--- a/src/lib/fmt/format.go
+++ b/src/lib/fmt/format.go
@@ -4,7 +4,9 @@
 
 package fmt
 
-import "strconv"
+import (
+	"strconv";
+)
 
 /*
 	Raw formatter. See print.go for a more palatable interface.
@@ -39,11 +41,22 @@
 	wid_present bool;
 	prec int;
 	prec_present bool;
+	// flags
+	minus bool;
+	plus bool;
+	sharp bool;
+	space bool;
+	zero bool;
 }
 
 func (f *Fmt) clearflags() {
 	f.wid_present = false;
 	f.prec_present = false;
+	f.minus = false;
+	f.plus = false;
+	f.sharp = false;
+	f.space = false;
+	f.zero = false;
 }
 
 func (f *Fmt) clearbuf() {
@@ -101,24 +114,28 @@
 	return f;
 }
 
-// append s to buf, padded on left (w > 0) or right (w < 0)
+// append s to buf, padded on left (w > 0) or right (w < 0 or f.minus)
 // padding is in bytes, not characters (agrees with ANSIC C, not Plan 9 C)
 func (f *Fmt) pad(s string) {
 	if f.wid_present && f.wid != 0 {
-		left := true;
+		left := !f.minus;
 		w := f.wid;
 		if w < 0 {
 			left = false;
 			w = -w;
 		}
 		w -= len(s);
+		padchar := byte(' ');
+		if left && f.zero {
+			padchar = '0';
+		}
 		if w > 0 {
 			if w > NByte {
 				w = NByte;
 			}
 			buf := new([]byte, w);
 			for i := 0; i < w; i++ {
-				buf[i] = ' ';
+				buf[i] = padchar;
 			}
 			if left {
 				s = string(buf) + s;
@@ -163,16 +180,35 @@
 	if negative {
 		a = -a;
 	}
-	i := putint(&buf, NByte-1, uint64(base), uint64(a), digits);
+
+	// two ways to ask for extra leading zero digits: %.3d or %03d.
+	// apparently the first cancels the second.
+	prec := 0;
 	if f.prec_present {
-		for i > 0 && f.prec > (NByte-1-i) {
-			buf[i] = '0';
-			i--;
+		prec = f.prec;
+		f.zero = false;
+	} else if f.zero && f.wid_present && !f.minus && f.wid > 0{
+		prec = f.wid;
+		if negative || f.plus || f.space {
+			prec--;  // leave room for sign
 		}
 	}
+
+	i := putint(&buf, NByte-1, uint64(base), uint64(a), digits);
+	for i > 0 && prec > (NByte-1-i) {
+		buf[i] = '0';
+		i--;
+	}
+
 	if negative {
 		buf[i] = '-';
 		i--;
+	} else if f.plus {
+		buf[i] = '+';
+		i--;
+	} else if f.space {
+		buf[i] = ' ';
+		i--;
 	}
 	return string(buf)[i+1:NByte];
 }
@@ -334,6 +370,44 @@
 	return f;
 }
 
+// hexadecimal string
+func (f *Fmt) sx(s string) *Fmt {
+	t := "";
+	for i := 0; i < len(s); i++ {
+		v := s[i];
+		t += string(ldigits[v>>4]);
+		t += string(ldigits[v&0xF]);
+	}
+	f.pad(t);
+	f.clearflags();
+	return f;
+}
+
+func (f *Fmt) sX(s string) *Fmt {
+	t := "";
+	for i := 0; i < len(s); i++ {
+		v := s[i];
+		t += string(udigits[v>>4]);
+		t += string(udigits[v&0xF]);
+	}
+	f.pad(t);
+	f.clearflags();
+	return f;
+}
+
+// quoted string
+func (f *Fmt) q(s string) *Fmt {
+	var quoted string;
+	if f.sharp && strconv.CanBackquote(s) {
+		quoted = "`"+s+"`";
+	} else {
+		quoted = strconv.Quote(s);
+	}
+	f.pad(quoted);
+	f.clearflags();
+	return f;
+}
+
 // floating-point
 
 func Prec(f *Fmt, def int) int {
@@ -370,7 +444,7 @@
 // cannot defer to float64 versions
 // because it will get rounding wrong in corner cases.
 func (f *Fmt) e32(a float32) *Fmt {
-	return FmtString(f, strconv.ftoa32(a, 'e', Prec(f, -1)));
+	return FmtString(f, strconv.ftoa32(a, 'e', Prec(f, 6)));
 }
 
 func (f *Fmt) f32(a float32) *Fmt {
diff --git a/src/lib/fmt/print.go b/src/lib/fmt/print.go
index ce7a4f2..5a2dc67 100644
--- a/src/lib/fmt/print.go
+++ b/src/lib/fmt/print.go
@@ -186,6 +186,19 @@
 	return s;
 }
 
+
+// Get the i'th arg of the struct value.
+// If the arg itself is an interface, return a value for
+// the thing inside the interface, not the interface itself.
+func getField(v reflect.StructValue, i int) reflect.Value {
+	val := v.Field(i);
+	if val.Kind() == reflect.InterfaceKind {
+		inter := val.(reflect.InterfaceValue).Get();
+		return reflect.NewValue(inter);
+	}
+	return val;
+}
+
 // Getters for the fields of the argument structure.
 
 func getBool(v reflect.Value) (val bool, ok bool) {
@@ -227,6 +240,9 @@
 	case reflect.StringKind:
 		return v.(reflect.StringValue).Get(), true;
 	}
+	if valb, okb := v.Interface().(*[]byte); okb {
+		return string(valb), true;
+	}
 	return "", false;
 }
 
@@ -280,12 +296,6 @@
 	if start >= end {
 		return 0, false, end
 	}
-	if s[start] == '-' {
-		a, b, c := parsenum(s, start+1, end);
-		if b {
-			return -a, b, c;
-		}
-	}
 	isnum := false;
 	num := 0;
 	for '0' <= s[start] && s[start] <= '9' {
@@ -371,10 +381,28 @@
 			i += w;
 			continue;
 		}
-		// saw % - do we have %20 (width)?
-		p.wid, p.wid_ok, i = parsenum(format, i+1, end);
+		i++;
+		// flags
+		F: for ; i < end; i++ {
+			switch format[i] {
+			case '#':
+				p.fmt.sharp = true;
+			case '0':
+				p.fmt.zero = true;
+			case '+':
+				p.fmt.plus = true;
+			case '-':
+				p.fmt.minus = true;
+			case ' ':
+				p.fmt.space = true;
+			default:
+				break F;
+			}
+		}
+		// do we have 20 (width)?
+		p.wid, p.wid_ok, i = parsenum(format, i, end);
 		p.prec_ok = false;
-		// do we have %.20 (precision)?
+		// do we have .20 (precision)?
 		if i < end && format[i] == '.' {
 			p.prec, p.prec_ok, i = parsenum(format, i+1, end);
 		}
@@ -391,7 +419,7 @@
 			p.addstr("(missing)");
 			continue;
 		}
-		field := v.Field(fieldnum);
+		field := getField(v, fieldnum);
 		fieldnum++;
 		if c != 'T' {	// don't want thing to describe itself if we're asking for its type
 			if formatter, ok := field.Interface().(Format); ok {
@@ -463,6 +491,20 @@
 					} else {
 						s = p.fmt.ux64(uint64(v)).str()
 					}
+				} else if v, ok := getString(field); ok {
+					s = p.fmt.sx(v).str();
+				} else {
+					goto badtype
+				}
+			case 'X':
+				if v, signed, ok := getInt(field); ok {
+					if signed {
+						s = p.fmt.X64(v).str()
+					} else {
+						s = p.fmt.uX64(uint64(v)).str()
+					}
+				} else if v, ok := getString(field); ok {
+					s = p.fmt.sX(v).str();
 				} else {
 					goto badtype
 				}
@@ -500,6 +542,12 @@
 				} else {
 					goto badtype
 				}
+			case 'q':
+				if v, ok := getString(field); ok {
+					s = p.fmt.q(v).str()
+				} else {
+					goto badtype
+				}
 
 			// pointer
 			case 'p':
@@ -530,7 +578,7 @@
 	if fieldnum < v.Len() {
 		p.addstr("?(extra ");
 		for ; fieldnum < v.Len(); fieldnum++ {
-			p.addstr(v.Field(fieldnum).Type().String());
+			p.addstr(getField(v, fieldnum).Type().String());
 			if fieldnum + 1 < v.Len() {
 				p.addstr(", ");
 			}
@@ -543,7 +591,7 @@
 	prev_string := false;
 	for fieldnum := 0; fieldnum < v.Len();  fieldnum++ {
 		// always add spaces if we're doing println
-		field := v.Field(fieldnum);
+		field := getField(v, fieldnum);
 		if fieldnum > 0 {
 			if addspace {
 				p.add(' ')
diff --git a/src/lib/reflect/all_test.go b/src/lib/reflect/all_test.go
index 203413e..a6ac1a7 100644
--- a/src/lib/reflect/all_test.go
+++ b/src/lib/reflect/all_test.go
@@ -283,3 +283,14 @@
 		println(a[i]);
 	}
 }
+
+export func TestInterfaceGet(t *testing.T) {
+	var inter struct { e interface{ } };
+	inter.e = 123.456;
+	v1 := reflect.NewValue(&inter);
+	v2 := v1.(reflect.PtrValue).Sub().(reflect.StructValue).Field(0);
+	assert(v2.Type().String(), "interface { }");
+	i2 := v2.(reflect.InterfaceValue).Get();
+	v3 := reflect.NewValue(i2);
+	assert(v3.Type().String(), "float");
+}
diff --git a/src/lib/reflect/cast_amd64.s b/src/lib/reflect/cast_amd64.s
index a136371..d0e97a3 100644
--- a/src/lib/reflect/cast_amd64.s
+++ b/src/lib/reflect/cast_amd64.s
@@ -181,3 +181,13 @@
 	MOVQ	AX, 16(SP)
 	RET
 
+TEXT reflect·AddrToPtrInterface(SB),7,$-8
+	MOVQ	8(SP), AX
+	MOVQ	AX, 16(SP)
+	RET
+
+TEXT reflect·PtrInterfaceToAddr(SB),7,$-8
+	MOVQ	8(SP), AX
+	MOVQ	AX, 16(SP)
+	RET
+
diff --git a/src/lib/reflect/gencast.sh b/src/lib/reflect/gencast.sh
index af90d8d..afb60de 100755
--- a/src/lib/reflect/gencast.sh
+++ b/src/lib/reflect/gencast.sh
@@ -38,4 +38,5 @@
 String
 Bool
 RuntimeArray
+Interface
 !
diff --git a/src/lib/reflect/value.go b/src/lib/reflect/value.go
index ef6ddce..65d4b5c 100644
--- a/src/lib/reflect/value.go
+++ b/src/lib/reflect/value.go
@@ -36,14 +36,13 @@
 func AddrToPtrBool(Addr) *bool
 func AddrToPtrRuntimeArray(Addr) *RuntimeArray
 func PtrRuntimeArrayToAddr(*RuntimeArray) Addr
-
-export type Empty interface {}	// TODO(r): Delete when no longer needed?
+func AddrToPtrInterface(Addr) *interface{}
 
 export type Value interface {
 	Kind()	int;
 	Type()	Type;
 	Addr()	Addr;
-	Interface()	Empty;
+	Interface()	interface {};
 }
 
 // Common fields and functionality for all values
@@ -66,7 +65,7 @@
 	return c.addr
 }
 
-func (c *Common) Interface() Empty {
+func (c *Common) Interface() interface {} {
 	return sys.unreflect(*AddrToPtrAddr(c.addr), c.typ.String());
 }
 
@@ -714,12 +713,17 @@
 export type InterfaceValue interface {
 	Kind()	int;
 	Type()	Type;
+	Get()	interface {};
 }
 
 type InterfaceValueStruct struct {
 	Common
 }
 
+func (v *InterfaceValueStruct) Get() interface{} {
+	return *AddrToPtrInterface(v.addr);
+}
+
 func InterfaceCreator(typ Type, addr Addr) Value {
 	return &InterfaceValueStruct{ Common{InterfaceKind, typ, addr} }
 }
@@ -824,7 +828,7 @@
 	return NewValueAddr(typ, PtrRuntimeArrayToAddr(array));
 }
 
-export func NewValue(e Empty) Value {
+export func NewValue(e interface {}) Value {
 	value, typestring  := sys.reflect(e);
 	p, ok := typecache[typestring];
 	if !ok {
diff --git a/src/lib/strconv/Makefile b/src/lib/strconv/Makefile
index 399360a..cf74d58 100644
--- a/src/lib/strconv/Makefile
+++ b/src/lib/strconv/Makefile
@@ -33,8 +33,9 @@
 
 O1=\
 	atoi.$O\
-	decimal.$O\
 	itoa.$O\
+	decimal.$O\
+	quote.$O\
 
 O2=\
 	ftoa.$O\
@@ -45,7 +46,7 @@
 strconv.a: a1 a2 a3
 
 a1:	$(O1)
-	$(AR) grc strconv.a atoi.$O decimal.$O itoa.$O
+	$(AR) grc strconv.a atoi.$O itoa.$O decimal.$O quote.$O
 	rm -f $(O1)
 
 a2:	$(O2)
diff --git a/src/lib/strconv/ftoa_test.go b/src/lib/strconv/ftoa_test.go
index 914ecd9..643abb0 100644
--- a/src/lib/strconv/ftoa_test.go
+++ b/src/lib/strconv/ftoa_test.go
@@ -25,6 +25,7 @@
 	Test{ 1, 'g', 5, "1" },
 	Test{ 1, 'g', -1, "1" },
 	Test{ 20, 'g', -1, "20" },
+	Test{ 1234567.8, 'g', -1, "1.2345678e+06" },
 	Test{ 200000, 'g', -1, "200000" },
 	Test{ 2000000, 'g', -1, "2e+06" },
 
diff --git a/src/lib/strconv/quote.go b/src/lib/strconv/quote.go
new file mode 100644
index 0000000..122af92
--- /dev/null
+++ b/src/lib/strconv/quote.go
@@ -0,0 +1,76 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package strconv
+
+import (
+	"utf8";
+)
+
+const ldigits = "0123456789abcdef"
+const udigits = "0123456789ABCDEF"
+
+export func Quote(s string) string {
+	t := `"`;
+	for i := 0; i < len(s); i++ {
+		switch {
+		case s[i] == '"':
+			t += `\"`;
+		case s[i] == '\\':
+			t += `\\`;
+		case ' ' <= s[i] && s[i] <= '~':
+			t += string(s[i]);
+		case s[i] == '\a':
+			t += `\a`;
+		case s[i] == '\b':
+			t += `\b`;
+		case s[i] == '\f':
+			t += `\f`;
+		case s[i] == '\n':
+			t += `\n`;
+		case s[i] == '\r':
+			t += `\r`;
+		case s[i] == '\t':
+			t += `\t`;
+		case s[i] == '\v':
+			t += `\v`;
+
+		case utf8.FullRuneInString(s, i):
+			r, size := utf8.DecodeRuneInString(s, i);
+			if r == utf8.RuneError && size == 1 {
+				goto EscX;
+			}
+			i += size-1;  // i++ on next iteration
+			if r < 0x10000 {
+				t += `\u`;
+				for j:=uint(0); j<4; j++ {
+					t += string(ldigits[(r>>(12-4*j))&0xF]);
+				}
+			} else {
+				t += `\U`;
+				for j:=uint(0); j<8; j++ {
+					t += string(ldigits[(r>>(28-4*j))&0xF]);
+				}
+			}
+
+		default:
+		EscX:
+			t += `\x`;
+			t += string(ldigits[s[i]>>4]);
+			t += string(ldigits[s[i]&0xF]);
+		}
+	}
+	t += `"`;
+	return t;
+}
+
+export func CanBackquote(s string) bool {
+	for i := 0; i < len(s); i++ {
+		if s[i] < ' ' || s[i] == '`' {
+			return false;
+		}
+	}
+	return true;
+}
+
diff --git a/src/lib/strconv/quote_test.go b/src/lib/strconv/quote_test.go
new file mode 100644
index 0000000..2c0e98e
--- /dev/null
+++ b/src/lib/strconv/quote_test.go
@@ -0,0 +1,87 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package strconv
+
+import (
+	"strconv";
+	"testing";
+)
+
+type QuoteTest struct {
+	in string;
+	out string;
+}
+
+var quotetests = []QuoteTest {
+	QuoteTest{ "\a\b\f\r\n\t\v", `"\a\b\f\r\n\t\v"` },
+	QuoteTest{ "\\", `"\\"` },
+	QuoteTest{ "abc\xffdef", `"abc\xffdef"` },
+	QuoteTest{ "\u263a", `"\u263a"` },
+	QuoteTest{ "\U0010ffff", `"\U0010ffff"` },
+}
+
+export func TestQuote(t *testing.T) {
+	for i := 0; i < len(quotetests); i++ {
+		tt := quotetests[i];
+		if out := Quote(tt.in); out != tt.out {
+			t.Errorf("Quote(%s) = %s, want %s", tt.in, out, tt.out);
+		}
+	}
+}
+
+type CanBackquoteTest struct {
+	in string;
+	out bool;
+}
+
+var canbackquotetests = []CanBackquoteTest {
+	CanBackquoteTest{ "`", false },
+	CanBackquoteTest{ string(0), false },
+	CanBackquoteTest{ string(1), false },
+	CanBackquoteTest{ string(2), false },
+	CanBackquoteTest{ string(3), false },
+	CanBackquoteTest{ string(4), false },
+	CanBackquoteTest{ string(5), false },
+	CanBackquoteTest{ string(6), false },
+	CanBackquoteTest{ string(7), false },
+	CanBackquoteTest{ string(8), false },
+	CanBackquoteTest{ string(9), false },
+	CanBackquoteTest{ string(10), false },
+	CanBackquoteTest{ string(11), false },
+	CanBackquoteTest{ string(12), false },
+	CanBackquoteTest{ string(13), false },
+	CanBackquoteTest{ string(14), false },
+	CanBackquoteTest{ string(15), false },
+	CanBackquoteTest{ string(16), false },
+	CanBackquoteTest{ string(17), false },
+	CanBackquoteTest{ string(18), false },
+	CanBackquoteTest{ string(19), false },
+	CanBackquoteTest{ string(20), false },
+	CanBackquoteTest{ string(21), false },
+	CanBackquoteTest{ string(22), false },
+	CanBackquoteTest{ string(23), false },
+	CanBackquoteTest{ string(24), false },
+	CanBackquoteTest{ string(25), false },
+	CanBackquoteTest{ string(26), false },
+	CanBackquoteTest{ string(27), false },
+	CanBackquoteTest{ string(28), false },
+	CanBackquoteTest{ string(29), false },
+	CanBackquoteTest{ string(30), false },
+	CanBackquoteTest{ string(31), false },
+	CanBackquoteTest{ `' !"#$%&'()*+,-./:;<=>?@[\]^_{|}~`, true },
+	CanBackquoteTest{ `0123456789`, true },
+	CanBackquoteTest{ `ABCDEFGHIJKLMNOPQRSTUVWXYZ`, true },
+	CanBackquoteTest{ `abcdefghijklmnopqrstuvwxyz`, true },
+	CanBackquoteTest{ `☺`, true },
+}
+
+export func TestCanBackquote(t *testing.T) {
+	for i := 0; i < len(canbackquotetests); i++ {
+		tt := canbackquotetests[i];
+		if out := CanBackquote(tt.in); out != tt.out {
+			t.Errorf("CanBackquote(%q) = %v, want %v", tt.in, out, tt.out);
+		}
+	}
+}
diff --git a/src/lib/utf8.go b/src/lib/utf8.go
index 7b0f15d..9ece25f 100644
--- a/src/lib/utf8.go
+++ b/src/lib/utf8.go
@@ -9,7 +9,8 @@
 export const (
 	RuneError = 0xFFFD;
 	RuneSelf = 0x80;
-	RuneMax = 1<<21 - 1;
+	RuneMax = 0x10FFFF;
+	UTFMax = 4;
 )
 
 const (
@@ -32,7 +33,8 @@
 )
 
 func DecodeRuneInternal(p *[]byte) (rune, size int, short bool) {
-	if len(p) < 1 {
+	n := len(p);
+	if n < 1 {
 		return RuneError, 0, true;
 	}
 	c0 := p[0];
@@ -48,7 +50,7 @@
 	}
 
 	// need first continuation byte
-	if len(p) < 2 {
+	if n < 2 {
 		return RuneError, 1, true
 	}
 	c1 := p[1];
@@ -66,7 +68,7 @@
 	}
 
 	// need second continuation byte
-	if len(p) < 3 {
+	if n < 3 {
 		return RuneError, 1, true
 	}
 	c2 := p[2];
@@ -84,7 +86,7 @@
 	}
 
 	// need third continuation byte
-	if len(p) < 4 {
+	if n < 4 {
 		return RuneError, 1, true
 	}
 	c3 := p[3];
@@ -105,17 +107,103 @@
 	return RuneError, 1, false
 }
 
+func DecodeRuneInStringInternal(s string, i int) (rune, size int, short bool) {
+	n := len(s) - i;
+	if n < 1 {
+		return RuneError, 0, true;
+	}
+	c0 := s[i];
+
+	// 1-byte, 7-bit sequence?
+	if c0 < Tx {
+		return int(c0), 1, false
+	}
+
+	// unexpected continuation byte?
+	if c0 < T2 {
+		return RuneError, 1, false
+	}
+
+	// need first continuation byte
+	if n < 2 {
+		return RuneError, 1, true
+	}
+	c1 := s[i+1];
+	if c1 < Tx || T2 <= c1 {
+		return RuneError, 1, false
+	}
+
+	// 2-byte, 11-bit sequence?
+	if c0 < T3 {
+		rune = int(c0&Mask2)<<6 | int(c1&Maskx);
+		if rune <= Rune1Max {
+			return RuneError, 1, false
+		}
+		return rune, 2, false
+	}
+
+	// need second continuation byte
+	if n < 3 {
+		return RuneError, 1, true
+	}
+	c2 := s[i+2];
+	if c2 < Tx || T2 <= c2 {
+		return RuneError, 1, false
+	}
+
+	// 3-byte, 16-bit sequence?
+	if c0 < T4 {
+		rune = int(c0&Mask3)<<12 | int(c1&Maskx)<<6 | int(c2&Maskx);
+		if rune <= Rune2Max {
+			return RuneError, 1, false
+		}
+		return rune, 3, false
+	}
+
+	// need third continuation byte
+	if n < 4 {
+		return RuneError, 1, true
+	}
+	c3 := s[i+3];
+	if c3 < Tx || T2 <= c3 {
+		return RuneError, 1, false
+	}
+
+	// 4-byte, 21-bit sequence?
+	if c0 < T5 {
+		rune = int(c0&Mask4)<<18 | int(c1&Maskx)<<12 | int(c2&Maskx)<<6 | int(c3&Maskx);
+		if rune <= Rune3Max {
+			return RuneError, 1, false
+		}
+		return rune, 4, false
+	}
+
+	// error
+	return RuneError, 1, false
+}
+
 export func FullRune(p *[]byte) bool {
 	rune, size, short := DecodeRuneInternal(p);
 	return !short
 }
 
+export func FullRuneInString(s string, i int) bool {
+	rune, size, short := DecodeRuneInStringInternal(s, i);
+	return !short
+}
+
 export func DecodeRune(p *[]byte) (rune, size int) {
 	var short bool;
 	rune, size, short = DecodeRuneInternal(p);
 	return;
 }
 
+export func DecodeRuneInString(s string, i int) (rune, size int) {
+	var short bool;
+	rune, size, short = DecodeRuneInStringInternal(s, i);
+	return;
+}
+
 export func RuneLen(rune int) int {
 	switch {
 	case rune <= Rune1Max:
diff --git a/src/lib/utf8_test.go b/src/lib/utf8_test.go
index 550f4ba..18c06c2 100644
--- a/src/lib/utf8_test.go
+++ b/src/lib/utf8_test.go
@@ -44,27 +44,6 @@
 	Utf8Map{ 0x10ffff, "\xf4\x8f\xbf\xbf" },
 }
 
-func CEscape(s *[]byte) string {
-	t := "\"";
-	for i := 0; i < len(s); i++ {
-		switch {
-		case s[i] == '\\' || s[i] == '"':
-			t += `\`;
-			t += string(s[i]);
-		case s[i] == '\n':
-			t += `\n`;
-		case s[i] == '\t':
-			t += `\t`;
-		case ' ' <= s[i] && s[i] <= '~':
-			t += string(s[i]);
-		default:
-			t += fmt.sprintf(`\x%02x`, s[i]);
-		}
-	}
-	t += "\"";
-	return t;
-}
-
 func Bytes(s string) *[]byte {
 	b := new([]byte, len(s)+1);
 	if !syscall.StringToBytes(b, s) {
@@ -78,10 +57,19 @@
 		m := utf8map[i];
 		b := Bytes(m.str);
 		if !utf8.FullRune(b) {
-			t.Errorf("FullRune(%s) (rune %04x) = false, want true", CEscape(b), m.rune);
+			t.Errorf("FullRune(%q) (rune %04x) = false, want true", b, m.rune);
 		}
-		if b1 := b[0:len(b)-1]; utf8.FullRune(b1) {
-			t.Errorf("FullRune(%s) = true, want false", CEscape(b1));
+		s := "xx"+m.str;
+		if !utf8.FullRuneInString(s, 2) {
+			t.Errorf("FullRuneInString(%q, 2) (rune %04x) = false, want true", s, m.rune);
+		}
+		b1 := b[0:len(b)-1];
+		if utf8.FullRune(b1) {
+			t.Errorf("FullRune(%q) = true, want false", b1);
+		}
+		s1 := "xxx"+string(b1);
+		if utf8.FullRuneInString(s1, 3) {
+			t.Errorf("FullRune(%q, 3) = true, want false", s1);
 		}
 	}
 }
@@ -106,7 +94,7 @@
 		n := utf8.EncodeRune(m.rune, &buf);
 		b1 := (&buf)[0:n];
 		if !EqualBytes(b, b1) {
-			t.Errorf("EncodeRune(0x%04x) = %s want %s", m.rune, CEscape(b1), CEscape(b));
+			t.Errorf("EncodeRune(0x%04x) = %q want %q", m.rune, b1, b);
 		}
 	}
 }
@@ -117,23 +105,38 @@
 		b := Bytes(m.str);
 		rune, size := utf8.DecodeRune(b);
 		if rune != m.rune || size != len(b) {
-			t.Errorf("DecodeRune(%s) = 0x%04x, %d want 0x%04x, %d", CEscape(b), rune, size, m.rune, len(b));
+			t.Errorf("DecodeRune(%q) = 0x%04x, %d want 0x%04x, %d", b, rune, size, m.rune, len(b));
+		}
+		s := "xx"+m.str;
+		rune, size = utf8.DecodeRuneInString(s, 2);
+		if rune != m.rune || size != len(b) {
+			t.Errorf("DecodeRune(%q, 2) = 0x%04x, %d want 0x%04x, %d", s, rune, size, m.rune, len(b));
 		}
 
 		// there's an extra byte that Bytes left behind - make sure trailing byte works
 		rune, size = utf8.DecodeRune(b[0:cap(b)]);
 		if rune != m.rune || size != len(b) {
-			t.Errorf("DecodeRune(%s) = 0x%04x, %d want 0x%04x, %d", CEscape(b), rune, size, m.rune, len(b));
+			t.Errorf("DecodeRune(%q) = 0x%04x, %d want 0x%04x, %d", b, rune, size, m.rune, len(b));
+		}
+		s = "x"+m.str+"\x00";
+		rune, size = utf8.DecodeRuneInString(s, 1);
+		if rune != m.rune || size != len(b) {
+			t.Errorf("DecodeRuneInString(%q, 1) = 0x%04x, %d want 0x%04x, %d", s, rune, size, m.rune, len(b));
 		}
 
 		// make sure missing bytes fail
-		rune, size = utf8.DecodeRune(b[0:len(b)-1]);
 		wantsize := 1;
 		if wantsize >= len(b) {
 			wantsize = 0;
 		}
+		rune, size = utf8.DecodeRune(b[0:len(b)-1]);
 		if rune != RuneError || size != wantsize {
-			t.Errorf("DecodeRune(%s) = 0x%04x, %d want 0x%04x, %d", CEscape(b[0:len(b)-1]), rune, size, RuneError, wantsize);
+			t.Errorf("DecodeRune(%q) = 0x%04x, %d want 0x%04x, %d", b[0:len(b)-1], rune, size, RuneError, wantsize);
+		}
+		s = "xxx"+m.str[0:len(m.str)-1];
+		rune, size = utf8.DecodeRuneInString(s, 3);
+		if rune != RuneError || size != wantsize {
+			t.Errorf("DecodeRuneInString(%q, 3) = 0x%04x, %d want 0x%04x, %d", s, rune, size, RuneError, wantsize);
 		}
 
 		// make sure bad sequences fail
@@ -144,7 +147,12 @@
 		}
 		rune, size = utf8.DecodeRune(b);
 		if rune != RuneError || size != 1 {
-			t.Errorf("DecodeRune(%s) = 0x%04x, %d want 0x%04x, %d", CEscape(b), rune, size, RuneError, 1);
+			t.Errorf("DecodeRune(%q) = 0x%04x, %d want 0x%04x, %d", b, rune, size, RuneError, 1);
+		}
+		s = "xxxx"+string(b);
+		rune, size = utf8.DecodeRune(b);
+		if rune != RuneError || size != 1 {
+			t.Errorf("DecodeRuneInString(%q, 4) = 0x%04x, %d want 0x%04x, %d", s, rune, size, RuneError, 1);
 		}
 	}
 }