mirror of https://github.com/golang/go.git
- correct error handling throughout
- documentation, cleanups - more options R=r OCL=19736 CL=19736
This commit is contained in:
parent
bd6e0bc8ba
commit
0998eaf4a1
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
//
|
||||
// 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 .
|
||||
// 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)
|
||||
//
|
||||
// (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);
|
||||
}
|
||||
m, err := b.writer.Write(Blanks[0 : n]);
|
||||
padding = Tabs;
|
||||
}
|
||||
|
||||
for n > len(padding) {
|
||||
err = b.Write0(padding);
|
||||
if err != nil {
|
||||
goto exit;
|
||||
}
|
||||
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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue