summaryrefslogtreecommitdiff
path: root/usr
diff options
context:
space:
mode:
authorRobert Griesemer <gri@golang.org>2008-11-20 16:26:43 -0800
committerRobert Griesemer <gri@golang.org>2008-11-20 16:26:43 -0800
commit49954fa9216a25872f4458f9ac9780ba3f8314d4 (patch)
tree2b7c08b6e9c6496e88a65b34d34b87e27957cac1 /usr
parent636fef5640855aeafbb4530b0bee50b9981a047c (diff)
downloadgolang-49954fa9216a25872f4458f9ac9780ba3f8314d4.tar.gz
- correct error handling throughout
- documentation, cleanups - more options R=r OCL=19736 CL=19736
Diffstat (limited to 'usr')
-rw-r--r--usr/gri/pretty/printer.go4
-rw-r--r--usr/gri/pretty/tabwriter.go259
-rw-r--r--usr/gri/pretty/untab.go4
3 files changed, 150 insertions, 117 deletions
diff --git a/usr/gri/pretty/printer.go b/usr/gri/pretty/printer.go
index 3e364618a..cefabb66f 100644
--- a/usr/gri/pretty/printer.go
+++ b/usr/gri/pretty/printer.go
@@ -15,8 +15,8 @@ import OS "os"
import TabWriter "tabwriter"
var (
- usetabs = Flag.Bool("usetabs", false, nil, "align with tabs instead of blanks");
tabwidth = Flag.Int("tabwidth", 4, nil, "tab width");
+ usetabs = Flag.Bool("usetabs", false, nil, "align with tabs instead of blanks");
comments = Flag.Bool("comments", false, nil, "enable printing of comments");
)
@@ -604,7 +604,7 @@ func (P *Printer) Declaration(d *AST.Decl, parenthesized bool) {
func (P *Printer) Program(p *AST.Program) {
// TODO should initialize all fields?
- P.writer = TabWriter.MakeTabWriter(OS.Stdout, usetabs.BVal(), int(tabwidth.IVal()));
+ P.writer = TabWriter.New(OS.Stdout, int(tabwidth.IVal()), 1, usetabs.BVal());
P.clist = p.comments;
P.cindex = 0;
diff --git a/usr/gri/pretty/tabwriter.go b/usr/gri/pretty/tabwriter.go
index 53a275514..58ae5ff1e 100644
--- a/usr/gri/pretty/tabwriter.go
+++ b/usr/gri/pretty/tabwriter.go
@@ -13,7 +13,7 @@ import (
// ----------------------------------------------------------------------------
// ByteArray
-// TODO move this into std lib eventually
+// TODO should use a ByteArray library eventually
type ByteArray struct {
a *[]byte;
@@ -30,21 +30,6 @@ func (b *ByteArray) Clear() {
}
-func (b *ByteArray) Len() int {
- return len(b.a);
-}
-
-
-func (b *ByteArray) At(i int) byte {
- return b.a[i];
-}
-
-
-func (b *ByteArray) Set(i int, x byte) {
- b.a[i] = x;
-}
-
-
func (b *ByteArray) Slice(i, j int) *[]byte {
return b.a[i : j]; // BUG should really be &b.a[i : j]
}
@@ -76,27 +61,42 @@ func (b *ByteArray) Append(s *[]byte) {
// ----------------------------------------------------------------------------
-// Implementation of flexible tab stops.
-
-// TabWriter is a representation for a list of lines consisting of
-// cells. A new cell is added for each Tab() call, and a new line
-// is added for each Newline() call.
+// Tabwriter is a filter implementing the IO.Write interface. It assumes
+// that the incoming bytes represent ASCII encoded text consisting of
+// lines of tab-separated "cells". Cells in adjacent lines constitute
+// a column. Tabwriter rewrites the incoming text such that all cells
+// in a column have the same width; thus it effectively aligns cells.
+// It does this by adding padding where necessary.
+//
+// Formatting can be controlled via parameters:
+//
+// tabwidth the minimal with of a cell
+// padding additional padding
+// usetabs use tabs instead of blanks for padding
+// (for correct-looking results, tabwidth must correspond
+// to the tabwidth in the editor used to look at the result)
//
-// The lines are formatted and printed such that all cells in a column
-// of adjacent cells have the same width (by adding padding). For more
-// details see: http://nickgravgaard.com/elastictabstops/index.html .
+// (See alse http://nickgravgaard.com/elastictabstops/index.html)
+
+// TODO Should support UTF-8
+// TODO Should probably implement a couple of trivial customization options
+// such as arbitrary padding character, left/right alignment, and inde-
+// pendant cell and tab width.
+
export type TabWriter struct {
+ // TODO should not export any of the fields
// configuration
writer io.Write;
- usetabs bool;
tabwidth int;
+ padding int;
+ usetabs bool;
// current state
buf ByteArray; // the collected text w/o tabs and newlines
width int; // width of last incomplete cell
lines array.Array; // list of lines; each line is a list of cell widths
- widths array.IntArray; // list of column widths - (re-)used during formatting
+ widths array.IntArray; // list of column widths - re-used during formatting
}
@@ -105,15 +105,18 @@ func (b *TabWriter) AddLine() {
}
-func (b *TabWriter) Init(writer io.Write, usetabs bool, tabwidth int) {
+func (b *TabWriter) Init(writer io.Write, tabwidth, padding int, usetabs bool) *TabWriter {
b.writer = writer;
- b.usetabs = usetabs;
b.tabwidth = tabwidth;
+ b.padding = padding;
+ b.usetabs = usetabs;
b.buf.Init(1024);
b.lines.Init(0);
b.widths.Init(0);
b.AddLine(); // the very first line
+
+ return b;
}
@@ -135,7 +138,7 @@ func (b *TabWriter) Dump() {
print("(", i, ") ");
for j := 0; j < line.Len(); j++ {
w := line.At(j);
- print("[", string(b.buf.a[pos : pos + w]), "]");
+ print("[", string(b.buf.Slice(pos, pos + w)), "]");
pos += w;
}
print("\n");
@@ -144,59 +147,95 @@ func (b *TabWriter) Dump() {
}
+func (b *TabWriter) Write0(buf *[]byte) *os.Error {
+ n, err := b.writer.Write(buf);
+ if n != len(buf) && err == nil {
+ err = os.EIO;
+ }
+ return err;
+}
+
+
var Tabs = &[]byte{'\t', '\t', '\t', '\t', '\t', '\t', '\t', '\t'}
var Blanks = &[]byte{' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '}
var Newline = &[]byte{'\n'}
-func (b *TabWriter) Padding(textwidth, cellwidth int) {
- n := cellwidth - textwidth;
+func (b *TabWriter) WritePadding(textw, cellw int) (err *os.Error) {
+ if b.usetabs {
+ // make cell width a multiple of tabwidth
+ cellw = ((cellw + b.tabwidth - 1) / b.tabwidth) * b.tabwidth;
+ }
+
+ n := cellw - textw;
if n < 0 {
panic("internal error");
}
+
+ padding := Blanks;
if b.usetabs {
- if cellwidth % b.tabwidth != 0 {
- panic("internal error"); // cellwidth should be a multiple of tabwidth
- }
n = (n + b.tabwidth - 1) / b.tabwidth;
- for n > len(Tabs) {
- m, err := b.writer.Write(Tabs);
- n -= len(Tabs);
- }
- m, err := b.writer.Write(Tabs[0 : n]);
- } else {
- for n > len(Blanks) {
- m, err := b.writer.Write(Blanks);
- n -= len(Blanks);
+ padding = Tabs;
+ }
+
+ for n > len(padding) {
+ err = b.Write0(padding);
+ if err != nil {
+ goto exit;
}
- m, err := b.writer.Write(Blanks[0 : n]);
+ n -= len(padding);
}
+ err = b.Write0(padding[0 : n]);
+
+exit:
+ return err;
}
-func (b *TabWriter) PrintLines(pos int, line0, line1 int) int {
+func (b *TabWriter) WriteLines(pos0 int, line0, line1 int) (pos int, err *os.Error) {
+ pos = pos0;
for i := line0; i < line1; i++ {
line := b.Line(i);
for j := 0; j < line.Len(); j++ {
w := line.At(j);
- m, err := b.writer.Write(b.buf.a[pos : pos + w]);
- if m != w {
- panic();
+ err = b.Write0(b.buf.a[pos : pos + w]);
+ if err != nil {
+ goto exit;
}
pos += w;
if j < b.widths.Len() {
- b.Padding(w, b.widths.At(j));
+ err = b.WritePadding(w, b.widths.At(j));
+ if err != nil {
+ goto exit;
+ }
}
}
- m, err := b.writer.Write(Newline);
+ err = b.Write0(Newline);
+ if err != nil {
+ goto exit;
+ }
}
- return pos;
+
+exit:
+ return pos, err;
}
-func (b *TabWriter) Format(pos int, line0, line1 int) int {
- column := b.widths.Len();
-
+// TODO use utflen for correct formatting
+func utflen(buf *[]byte) int {
+ n := 0;
+ for i := 0; i < len(buf); i++ {
+ if buf[i]&0xC0 != 0x80 {
+ n++
+ }
+ }
+ return n
+}
+
+
+func (b *TabWriter) Format(pos0 int, line0, line1 int) (pos int, err *os.Error) {
+ pos = pos0;
+ column := b.widths.Len();
last := line0;
for this := line0; this < line1; this++ {
line := b.Line(this);
@@ -206,7 +245,10 @@ func (b *TabWriter) Format(pos int, line0, line1 int) int {
// (note that the last cell per line is ignored)
// print unprinted lines until beginning of block
- pos = b.PrintLines(pos, last, this);
+ pos, err = b.WriteLines(pos, last, this);
+ if err != nil {
+ goto exit;
+ }
last = this;
// column block begin
@@ -214,9 +256,8 @@ func (b *TabWriter) Format(pos int, line0, line1 int) int {
for ; this < line1; this++ {
line = b.Line(this);
if column < line.Len() - 1 {
- // cell exists in this column
- // update width
- w := line.At(column) + 1; // 1 = minimum space between cells
+ // cell exists in this column => update width
+ w := line.At(column) + b.padding;
if w > width {
width = w;
}
@@ -226,85 +267,77 @@ func (b *TabWriter) Format(pos int, line0, line1 int) int {
}
// column block end
- if b.usetabs {
- // make width a multiple of the tab width
- width = ((width + b.tabwidth - 1) / b.tabwidth) * b.tabwidth;
- }
-
// format and print all columns to the right of this column
// (we know the widths of this column and all columns to the left)
b.widths.Push(width);
- pos = b.Format(pos, last, this);
+ pos, err = b.Format(pos, last, this);
b.widths.Pop();
last = this;
}
}
// print unprinted lines until end
- return b.PrintLines(pos, last, line1);
+ pos, err = b.WriteLines(pos, last, line1);
+
+exit:
+ return pos, err;
}
-func (b *TabWriter) EmptyLine() bool {
- return b.LastLine().Len() == 0 && b.width == 0;
+func (b *TabWriter) Append(buf *[]byte) {
+ b.buf.Append(buf);
+ b.width += len(buf);
}
-func (b *TabWriter) Tab() {
- b.LastLine().Push(b.width);
+/* export */ func (b *TabWriter) Flush() *os.Error {
+ dummy, err := b.Format(0, 0, b.lines.Len());
+ // reset (even in the presence of errors)
+ b.buf.Clear();
b.width = 0;
-}
-
-
-func (b *TabWriter) Newline() {
- b.Tab(); // add last cell to current line
-
- if b.LastLine().Len() == 1 {
- // The current line has only one cell which does not have an impact
- // on the formatting of the following lines (the last cell per line
- // is ignored by Format), thus we can print the TabWriter contents.
- if b.widths.Len() != 0 {
- panic("internal error");
- }
- b.Format(0, 0, b.lines.Len());
- if b.widths.Len() != 0 {
- panic("internal error");
- }
-
- // reset TabWriter
- b.width = 0;
- b.buf.Clear();
- b.lines.Init(0);
- }
-
+ b.lines.Init(0);
b.AddLine();
+ return err;
}
-func (b *TabWriter) Write(buf *[]byte) (i int, err *os.Error) {
+/* export */ func (b *TabWriter) Write(buf *[]byte) (written int, err *os.Error) {
i0, n := 0, len(buf);
- for i = 0; i < n; i++ {
- switch buf[i] {
- case '\t':
- b.width += i - i0;
- b.buf.Append(buf[i0 : i]);
- i0 = i + 1; // don't append '\t'
- b.Tab();
- case '\n':
- b.width += i - i0;
- b.buf.Append(buf[i0 : i]);
- i0 = i + 1; // don't append '\n'
- b.Newline();
+
+ // split text into cells
+ for i := 0; i < n; i++ {
+ if ch := buf[i]; ch == '\t' || ch == '\n' {
+ b.Append(buf[i0 : i]);
+ i0 = i + 1; // exclude ch from (next) cell
+
+ // terminate cell
+ b.LastLine().Push(b.width);
+ b.width = 0;
+
+ if ch == '\n' {
+ if b.LastLine().Len() == 1 {
+ // The last line has only one cell which does not have an
+ // impact on the formatting of the following lines (the
+ // last cell per line is ignored by Format), thus we can
+ // flush the TabWriter contents.
+ err = b.Flush();
+ if err != nil {
+ return i0, err;
+ }
+ } else {
+ // We can't flush yet - just add a new line.
+ b.AddLine();
+ }
+ }
}
}
- b.width += n - i0;
- b.buf.Append(buf[i0 : n]);
- return i, nil;
+
+ // append leftover text
+ b.Append(buf[i0 : n]);
+ return n, nil;
}
-export func MakeTabWriter(writer io.Write, usetabs bool, tabwidth int) *TabWriter {
- b := new(TabWriter);
- b.Init(writer, usetabs, tabwidth);
- return b;
+export func New(writer io.Write, tabwidth, padding int, usetabs bool) *TabWriter {
+ return new(TabWriter).Init(writer, tabwidth, padding, usetabs)
}
diff --git a/usr/gri/pretty/untab.go b/usr/gri/pretty/untab.go
index a2232b351..d2a26f438 100644
--- a/usr/gri/pretty/untab.go
+++ b/usr/gri/pretty/untab.go
@@ -14,8 +14,8 @@ import (
var (
- usetabs = flag.Bool("usetabs", false, nil, "align with tabs instead of blanks");
tabwidth = flag.Int("tabwidth", 4, nil, "tab width");
+ usetabs = flag.Bool("usetabs", false, nil, "align with tabs instead of blanks");
)
@@ -36,7 +36,7 @@ func Untab(name string, src *os.FD, dst *tabwriter.TabWriter) {
func main() {
flag.Parse();
- dst := tabwriter.MakeTabWriter(os.Stdout, usetabs.BVal(), int(tabwidth.IVal()));
+ dst := tabwriter.New(os.Stdout, int(tabwidth.IVal()), 1, usetabs.BVal());
if flag.NArg() > 0 {
for i := 0; i < flag.NArg(); i++ {
name := flag.Arg(i);