summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Pike <r@golang.org>2008-03-27 00:06:21 -0700
committerRob Pike <r@golang.org>2008-03-27 00:06:21 -0700
commit281b270ba26499019bad97700103f38f3df5f0d2 (patch)
tree4706e11209d99fc5b608582cf1fb7b735e1658b5
parentb9829f88caae9d67410240956843ea812d44fe22 (diff)
downloadgolang-281b270ba26499019bad97700103f38f3df5f0d2.tar.gz
Basic formatted I/O library plus one support lib.
SVN=113977
-rw-r--r--src/lib/fmt.go484
-rw-r--r--src/lib/sys.go16
2 files changed, 500 insertions, 0 deletions
diff --git a/src/lib/fmt.go b/src/lib/fmt.go
new file mode 100644
index 000000000..715643432
--- /dev/null
+++ b/src/lib/fmt.go
@@ -0,0 +1,484 @@
+// 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
+
+/*
+ f := fmt.New();
+ print f.d(1234).s("\n").str(); // create string, print it
+ f.d(-1234).s("\n").put(); // print string
+ f.ud(^0).putnl(); // print string with automatic newline
+*/
+
+import sys "sys"
+
+export Fmt, New;
+
+var ldigits [16]byte; // BUG: should be constants
+var udigits [16]byte; // BUG: can they be strings? looks like trouble with buf[i] = digits[val];
+var inited bool;
+var pows10 [160] double;
+
+type Fmt struct {
+ buf string;
+ wid int;
+ wid_present bool;
+ prec int;
+ prec_present bool;
+}
+
+func (f *Fmt) clearflags() {
+ f.wid_present = false;
+ f.prec_present = false;
+}
+
+func (f *Fmt) clearbuf() {
+ f.buf = "";
+}
+
+func (f *Fmt) init() {
+ f.clearbuf();
+ f.clearflags();
+ if inited {
+ return;
+ }
+ var i byte;
+ for i = 0; i < 10; i++ {
+ ldigits[i] = '0' + i;
+ udigits[i] = '0' + i;
+ }
+ for i = 0; i < 6; i++ {
+ ldigits[i+10] = 'a' + i;
+ udigits[i+10] = 'A' + i;
+ }
+ // BUG: should be done with initialization
+ var p double = 1.0;
+ for i = 0; i < 160; i++ { // BUG: len(pows10)
+ pows10[i] = p;
+ p *= 10.0;
+ }
+ inited = true;
+}
+
+func New() *Fmt {
+ f := new(Fmt);
+ f.init();
+ return f;
+}
+
+func (f *Fmt) str() string {
+ s := f.buf;
+ f.clearbuf();
+ f.clearflags();
+ f.buf = "";
+ return s;
+}
+
+func (f *Fmt) put() {
+ print f.buf;
+ f.clearbuf();
+ f.clearflags();
+}
+
+func (f *Fmt) putnl() {
+ print f.buf, "\n";
+ f.clearbuf();
+ f.clearflags();
+}
+
+func (f *Fmt) wp(w, p int) *Fmt {
+ f.wid_present = true;
+ f.wid = w;
+ f.prec_present = true;
+ f.prec = p;
+ return f;
+}
+
+func (f *Fmt) p(p int) *Fmt {
+ f.prec_present = true;
+ f.prec = p;
+ return f;
+}
+
+func (f *Fmt) w(x int) *Fmt {
+ f.wid_present = true;
+ f.wid = x;
+ return f;
+}
+
+// append s to buf, padded on left (w > 0) or right (w < 0)
+// 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;
+ w := f.wid;
+ if w < 0 {
+ left = false;
+ w = -w;
+ }
+ w -= len(s);
+ if w > 0 {
+ if w > 64 { // BUG: should be able to use a const
+ w = 64;
+ }
+ var buf[64] byte; // BUG: should be able to allocate a size
+ for i := 0; i < w; i++ {
+ buf[i] = ' ';
+ }
+ if left {
+ s = string(buf)[0:w] + s;
+ } else {
+ s = s + string(buf)[0:w];
+ }
+ }
+ }
+ f.buf = f.buf + s; // BUG: += should work
+}
+
+// format val into buf, ending at buf[i]. (printing is easier right-to-left;
+// that's why the bidi languages are right-to-left except for numbers. wait,
+// never mind.) val is known to be unsigned. we could make things maybe
+// marginally faster by splitting the 32-bit case out into a separate function
+// but it's not worth the duplication, so val has 64 bits.
+func putint(buf *[64]byte, i int, base, val uint64, digits *[16]byte) int {
+ for val >= base {
+ buf[i] = digits[val%base];
+ i--;
+ val /= base;
+ }
+ buf[i] = digits[val];
+ return i-1;
+}
+
+// integer; interprets prec but not wid.
+func (f *Fmt) integer(a int64, base uint, is_signed bool, digits *[16]byte) string {
+ var buf [64]byte;
+ negative := is_signed && a < 0;
+ if negative {
+ a = -a;
+ }
+ i := putint(&buf, 63, uint64(base), uint64(a), digits);
+ if f.prec_present {
+ for i > 0 && f.prec > (63-i) {
+ buf[i] = '0';
+ i--;
+ }
+ }
+ if negative {
+ buf[i] = '-';
+ i--;
+ }
+ return string(buf)[i+1:64];
+}
+
+// decimal
+func (f *Fmt) d(a int32) *Fmt {
+ f.pad(f.integer(int64(a), 10, true, &ldigits));
+ f.clearflags();
+ return f;
+}
+
+func (f *Fmt) D(a int64) *Fmt {
+ f.pad(f.integer(a, 10, true, &ldigits));
+ f.clearflags();
+ return f;
+}
+
+// unsigned decimal
+func (f *Fmt) ud(a int32) *Fmt {
+ f.pad(f.integer(int64(uint32(a)), 10, false, &ldigits));
+ f.clearflags();
+ return f;
+}
+
+func (f *Fmt) uD(a int64) *Fmt {
+ f.pad(f.integer(a, 10, false, &ldigits));
+ f.clearflags();
+ return f;
+}
+
+// hexdecimal
+func (f *Fmt) x(a int32) *Fmt {
+ f.pad(f.integer(int64(a), 16, true, &ldigits));
+ f.clearflags();
+ return f;
+}
+
+func (f *Fmt) X(a int64) *Fmt {
+ f.pad(f.integer(a, 16, true, &ldigits));
+ f.clearflags();
+ return f;
+}
+
+// unsigned hexdecimal
+func (f *Fmt) ux(a int32) *Fmt {
+ f.pad(f.integer(int64(uint32(a)), 16, false, &ldigits));
+ f.clearflags();
+ return f;
+}
+
+func (f *Fmt) uX(a int64) *Fmt {
+ f.pad(f.integer(a, 16, false, &ldigits));
+ f.clearflags();
+ return f;
+}
+
+// HEXADECIMAL
+func (f *Fmt) Ux(a int32) *Fmt {
+ f.pad(f.integer(int64(a), 16, true, &udigits));
+ f.clearflags();
+ return f;
+}
+
+func (f *Fmt) UX(a int64) *Fmt {
+ f.pad(f.integer(a, 16, true, &udigits));
+ f.clearflags();
+ return f;
+}
+
+// unsigned HEXADECIMAL
+func (f *Fmt) uUx(a int32) *Fmt {
+ f.pad(f.integer(int64(uint32(a)), 16, false, &udigits));
+ f.clearflags();
+ return f;
+}
+
+func (f *Fmt) uUX(a int64) *Fmt {
+ f.pad(f.integer(a, 16, false, &udigits));
+ f.clearflags();
+ return f;
+}
+
+// octal
+func (f *Fmt) o(a int32) *Fmt {
+ f.pad(f.integer(int64(a), 8, true, &ldigits));
+ f.clearflags();
+ return f;
+}
+
+func (f *Fmt) O(a int64) *Fmt {
+ f.pad(f.integer(a, 8, true, &ldigits));
+ f.clearflags();
+ return f;
+}
+
+// unsigned octal
+func (f *Fmt) uo(a int32) *Fmt {
+ f.pad(f.integer(int64(uint32(a)), 8, false, &ldigits));
+ f.clearflags();
+ return f;
+}
+
+func (f *Fmt) uO(a int64) *Fmt {
+ f.pad(f.integer(a, 8, false, &ldigits));
+ f.clearflags();
+ return f;
+}
+
+// binary
+func (f *Fmt) b(a int32) *Fmt {
+ f.pad(f.integer(int64(uint32(a)), 2, false, &ldigits));
+ f.clearflags();
+ return f;
+}
+
+func (f *Fmt) B(a int64) *Fmt {
+ f.pad(f.integer(a, 2, false, &ldigits));
+ f.clearflags();
+ return f;
+}
+
+// character
+func (f *Fmt) c(a int) *Fmt {
+ f.pad(string(a));
+ f.clearflags();
+ return f;
+}
+
+// string
+func (f *Fmt) s(s string) *Fmt {
+ if f.prec_present {
+ if f.prec < len(s) {
+ w := f.prec; // BUG: can't use f.prec in slice
+ s = s[0:w];
+ }
+ }
+ f.pad(s);
+ f.clearflags();
+ return f;
+}
+
+func pow10(n int) double {
+ var d double;
+ npows10 := 160; // nelem(pows10); BUG: why not a const?
+
+ neg := false;
+ if n < 0 {
+ if n < -307 { // DBL_MIN_10_EXP
+ return 0.;
+ }
+ neg = true;
+ n = -n;
+ }else if n > 308 { // DBL_MAX_10_EXP
+ return 1.79769e+308; // HUGE_VAL
+ }
+
+ if n < npows10 {
+ d = pows10[n];
+ } else {
+ d = pows10[npows10-1];
+ for {
+ n -= npows10 - 1;
+ if n < npows10 {
+ d *= pows10[n];
+ break;
+ }
+ d *= pows10[npows10 - 1];
+ }
+ }
+ if neg {
+ return 1/d;
+ }
+ return d;
+}
+
+func unpack(a double) (negative bool, exp int, num double) {
+ neg := a < 0;
+ if neg {
+ a = -a;
+ }
+ // find g,e such that a = g*10^e.
+ // guess 10-exponent using 2-exponent, then fine tune.
+ var g double;
+ var e2 int;
+ e2, g = sys.frexp(a);
+ e := int(e2 * .301029995663981);
+ g := a * pow10(-e);
+ for g < 1 {
+ e--;
+ g = a * pow10(-e);
+ }
+ for g >= 10 {
+ e++;
+ g = a * pow10(-e);
+ }
+ return neg, e, g;
+}
+
+// double
+func (f *Fmt) E(a double) *Fmt {
+ var negative bool;
+ var g double;
+ var exp int;
+ negative, exp, g = unpack(a);
+ prec := 6;
+ if f.prec_present {
+ prec = f.prec;
+ }
+ prec++; // one digit left of decimal
+ // multiply by 10^prec to get decimal places; put decimal after first digit
+ g *= pow10(prec);
+ s := f.integer(int64(g + .5), 10, true, &ldigits); // get the digits into a string
+ s = s[0:1] + "." + s[1:prec]; // insert a decimal point
+ // print exponent with leading 0 if appropriate.
+ es := New().p(2).integer(int64(exp), 10, true, &ldigits);
+ if exp > 0 {
+ es = "+" + es; // BUG: should do this with a fmt flag
+ }
+ s = s + "e" + es;
+ if negative {
+ s = "-" + s;
+ }
+ f.pad(s);
+ f.clearflags();
+ return f;
+}
+
+// double
+func (f *Fmt) F(a double) *Fmt {
+ var negative bool;
+ var g double;
+ var exp int;
+ negative, exp, g = unpack(a);
+ if exp > 19 || exp < -19 { // too big for this sloppy code
+ return f.E(a);
+ }
+ prec := 6;
+ if f.prec_present {
+ prec = f.prec;
+ }
+ // prec is number of digits after decimal point
+ s := "NO";
+ if exp >= 0 {
+ g *= pow10(exp);
+ gi := int64(g);
+ s = New().integer(gi, 10, true, &ldigits);
+ s = s + ".";
+ g -= double(gi);
+ s = s + New().p(prec).integer(int64(g*pow10(prec) + .5), 10, true, &ldigits);
+ } else {
+ g *= pow10(prec + exp);
+ s = "0." + New().p(prec).integer(int64(g + .5), 10, true, &ldigits);
+ }
+ if negative {
+ s = "-" + s;
+ }
+ f.pad(s);
+ f.clearflags();
+ return f;
+}
+
+// double
+func (f *Fmt) G(a double) *Fmt {
+ f1 := New();
+ f2 := New();
+ if f.wid_present {
+ f1.w(f.wid);
+ f2.w(f.wid);
+ }
+ if f.prec_present {
+ f1.p(f.prec);
+ f2.p(f.prec);
+ }
+ efmt := f1.E(a).str();
+ ffmt := f2.F(a).str();
+ // ffmt can return e in my bogus world; don't trim trailing 0s if so.
+ f_is_e := false;
+ for i := 0; i < len(ffmt); i++ {
+ if ffmt[i] == 'e' {
+ f_is_e = true;
+ break;
+ }
+ }
+ if !f_is_e {
+ // strip trailing zeros
+ l := len(ffmt);
+ for ffmt[l-1]=='0' {
+ l--;
+ }
+ ffmt = ffmt[0:l];
+ }
+ if len(efmt) < len(ffmt) {
+ f.pad(efmt);
+ } else {
+ f.pad(ffmt);
+ }
+ f.clearflags();
+ return f;
+}
+
+// float
+func (x *Fmt) f(a float) *Fmt {
+ return x.F(double(a));
+}
+
+// float
+func (x *Fmt) e(a float) *Fmt {
+ return x.E(double(a));
+}
+
+// float
+func (x *Fmt) g(a float) *Fmt {
+ return x.G(double(a));
+}
diff --git a/src/lib/sys.go b/src/lib/sys.go
new file mode 100644
index 000000000..eddfd1fad
--- /dev/null
+++ b/src/lib/sys.go
@@ -0,0 +1,16 @@
+// 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 sys
+
+func modf(a double) (double, double);
+func frexp(a double) (int, double);
+func ldexp(double, int) double;
+
+func Inf(n int) double;
+func NaN() double;
+func isInf(arg double, n int) bool;
+
+export modf, frexp, ldexp
+export NaN, isInf, Inf