From f67c90f941aaef64cacbedf374e08b5da3caa5af Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 31 Mar 2010 16:01:22 -0700 Subject: [PATCH] tabwriter: use panic/recover to handle errors R=rsc, r CC=golang-dev https://golang.org/cl/864042 --- src/pkg/tabwriter/tabwriter.go | 97 ++++++++++++++++------------------ 1 file changed, 47 insertions(+), 50 deletions(-) diff --git a/src/pkg/tabwriter/tabwriter.go b/src/pkg/tabwriter/tabwriter.go index bca3228e2c..f37be51411 100644 --- a/src/pkg/tabwriter/tabwriter.go +++ b/src/pkg/tabwriter/tabwriter.go @@ -221,23 +221,30 @@ func (b *Writer) dump() { } -func (b *Writer) write0(buf []byte) os.Error { +// local error wrapper so we can distinguish os.Errors we want to return +// as errors from genuine panics (which we don't want to return as errors) +type osError struct { + err os.Error +} + + +func (b *Writer) write0(buf []byte) { n, err := b.output.Write(buf) if n != len(buf) && err == nil { err = os.EIO } - return err + if err != nil { + panic(osError{err}) + } } -func (b *Writer) writeN(src []byte, n int) os.Error { +func (b *Writer) writeN(src []byte, n int) { for n > len(src) { - if err := b.write0(src); err != nil { - return err - } + b.write0(src) n -= len(src) } - return b.write0(src[0:n]) + b.write0(src[0:n]) } @@ -247,11 +254,11 @@ var ( ) -func (b *Writer) writePadding(textw, cellw int, useTabs bool) os.Error { +func (b *Writer) writePadding(textw, cellw int, useTabs bool) { if b.padbytes[0] == '\t' || useTabs { // padding is done with tabs if b.tabwidth == 0 { - return nil // tabs have no width - can't do any padding + return // tabs have no width - can't do any padding } // make cellw the smallest multiple of b.tabwidth cellw = (cellw + b.tabwidth - 1) / b.tabwidth * b.tabwidth @@ -259,17 +266,18 @@ func (b *Writer) writePadding(textw, cellw int, useTabs bool) os.Error { if n < 0 { panic("internal error") } - return b.writeN(tabs, (n+b.tabwidth-1)/b.tabwidth) + b.writeN(tabs, (n+b.tabwidth-1)/b.tabwidth) + return } // padding is done with non-tab characters - return b.writeN(&b.padbytes, cellw-textw) + b.writeN(&b.padbytes, cellw-textw) } var vbar = []byte{'|'} -func (b *Writer) writeLines(pos0 int, line0, line1 int) (pos int, err os.Error) { +func (b *Writer) writeLines(pos0 int, line0, line1 int) (pos int) { pos = pos0 for i := line0; i < line1; i++ { line := b.line(i) @@ -282,40 +290,28 @@ func (b *Writer) writeLines(pos0 int, line0, line1 int) (pos int, err os.Error) if j > 0 && b.flags&Debug != 0 { // indicate column break - if err = b.write0(vbar); err != nil { - return - } + b.write0(vbar) } if c.size == 0 { // empty cell if j < b.widths.Len() { - if err = b.writePadding(c.width, b.widths.At(j), useTabs); err != nil { - return - } + b.writePadding(c.width, b.widths.At(j), useTabs) } } else { // non-empty cell useTabs = false if b.flags&AlignRight == 0 { // align left - if err = b.write0(b.buf.Bytes()[pos : pos+c.size]); err != nil { - return - } + b.write0(b.buf.Bytes()[pos : pos+c.size]) pos += c.size if j < b.widths.Len() { - if err = b.writePadding(c.width, b.widths.At(j), false); err != nil { - return - } + b.writePadding(c.width, b.widths.At(j), false) } } else { // align right if j < b.widths.Len() { - if err = b.writePadding(c.width, b.widths.At(j), false); err != nil { - return - } - } - if err = b.write0(b.buf.Bytes()[pos : pos+c.size]); err != nil { - return + b.writePadding(c.width, b.widths.At(j), false) } + b.write0(b.buf.Bytes()[pos : pos+c.size]) pos += c.size } } @@ -324,15 +320,11 @@ func (b *Writer) writeLines(pos0 int, line0, line1 int) (pos int, err os.Error) if i+1 == b.lines.Len() { // last buffered line - we don't have a newline, so just write // any outstanding buffered data - if err = b.write0(b.buf.Bytes()[pos : pos+b.cell.size]); err != nil { - return - } + b.write0(b.buf.Bytes()[pos : pos+b.cell.size]) pos += b.cell.size } else { // not the last line - write newline - if err = b.write0(newline); err != nil { - return - } + b.write0(newline) } } return @@ -344,7 +336,7 @@ func (b *Writer) writeLines(pos0 int, line0, line1 int) (pos int, err os.Error) // Returns the buffer position corresponding to the beginning of // line1 and an error, if any. // -func (b *Writer) format(pos0 int, line0, line1 int) (pos int, err os.Error) { +func (b *Writer) format(pos0 int, line0, line1 int) (pos int) { pos = pos0 column := b.widths.Len() for this := line0; this < line1; this++ { @@ -359,9 +351,7 @@ func (b *Writer) format(pos0 int, line0, line1 int) (pos int, err os.Error) { // to a column) // print unprinted lines until beginning of block - if pos, err = b.writeLines(pos, line0, this); err != nil { - return - } + pos = b.writeLines(pos, line0, this) line0 = this // column block begin @@ -394,7 +384,7 @@ func (b *Writer) format(pos0 int, line0, line1 int) (pos int, err os.Error) { // 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, err = b.format(pos, line0, this) + pos = b.format(pos, line0, this) b.widths.Pop() line0 = this } @@ -472,12 +462,22 @@ func (b *Writer) terminateCell(htab bool) int { } +func handlePanic(err *os.Error) { + if e := recover(); e != nil { + *err = e.(osError).err // re-panics if it's not a local osError + } +} + + // Flush should be called after the last call to Write to ensure // that any data buffered in the Writer is written to output. Any // incomplete escape sequence at the end is simply considered // complete for formatting purposes. // -func (b *Writer) Flush() os.Error { +func (b *Writer) Flush() (err os.Error) { + defer b.reset() // even in the presence of errors + defer handlePanic(&err) + // add current cell if not empty if b.cell.size > 0 { if b.endChar != 0 { @@ -488,12 +488,9 @@ func (b *Writer) Flush() os.Error { } // format contents of buffer - _, err := b.format(0, 0, b.lines.Len()) + b.format(0, 0, b.lines.Len()) - // reset, even in the presence of errors - b.reset() - - return err + return } @@ -504,6 +501,8 @@ var hbar = []byte("---\n") // while writing to the underlying output stream. // func (b *Writer) Write(buf []byte) (n int, err os.Error) { + defer handlePanic(&err) + // split text into cells n = 0 for i, ch := range buf { @@ -530,9 +529,7 @@ func (b *Writer) Write(buf []byte) (n int, err os.Error) { } if ch == '\f' && b.flags&Debug != 0 { // indicate section break - if err = b.write0(hbar); err != nil { - return - } + b.write0(hbar) } } }