package notation import ( "bytes" "fmt" "io" "os" "reflect" "strconv" "strings" ) type opts int const none opts = 0 const ( wrap opts = 1 << iota types skipTypes allTypes randomMaps ) type wrapLen struct { first, max, last int } type nodeRef struct { id, refCount int } type pending struct { values map[uintptr]nodeRef idCounter int } type node struct { len int wrapLen wrapLen fullWrap wrapLen wrap bool parts []interface{} } type str struct { val string raw string useRaw bool rawLen wrapLen } type wrapMode int const ( block wrapMode = iota line ) type wrapper struct { mode wrapMode sep, suffix string items []node lineEnds []int } type writer struct { w io.Writer n int err error } var stderr io.Writer = os.Stderr func (n node) String() string { var b bytes.Buffer w := &writer{w: &b} fprint(w, 0, n) return b.String() } func (s str) String() string { if s.useRaw { return s.raw } return s.val } func (w *writer) write(o interface{}) { if w.err != nil { return } n, err := fmt.Fprint(w.w, o) w.n += n w.err = err } func (w *writer) blankLine() { w.write("\n") } func (w *writer) tabs(n int) { for i := 0; i < n; i++ { w.write("\t") } } func (w *writer) line(t int) { w.blankLine() w.tabs(t) } func nodeOf(parts ...interface{}) node { return node{parts: parts} } func config(name string, dflt int) int { s := os.Getenv(name) if s == "" { s = os.Getenv(strings.ToLower(name)) } if s == "" { return dflt } v, err := strconv.Atoi(s) if err != nil { return dflt } return v } func fprintValues(w io.Writer, o opts, v []interface{}) (int, error) { tab := config("TABWIDTH", 8) cols0 := config("LINEWIDTH", 80-tab) cols1 := config("LINEWIDTH1", (cols0+tab)*3/2-tab) sortMaps := config("MAPSORT", 1) if sortMaps == 0 { o |= randomMaps } wr := &writer{w: w} for i, vi := range v { if wr.err != nil { return wr.n, wr.err } if i > 0 { if o&wrap == 0 { wr.write(" ") } else { wr.write("\n") } } if vi == nil { fprint(wr, 0, nodeOf("nil")) continue } n := reflectValue( o, &pending{values: make(map[uintptr]nodeRef)}, reflect.ValueOf(vi), ) if o&wrap != 0 { n = nodeLen(tab, n) n = wrapNode(tab, cols0, cols0, cols1, n) } fprint(wr, 0, n) } return wr.n, wr.err } func printValues(o opts, v []interface{}) (int, error) { return fprintValues(stderr, o, v) } func printlnValues(o opts, v []interface{}) (int, error) { n, err := fprintValues(stderr, o, v) if err != nil { return n, err } nn, err := stderr.Write([]byte("\n")) return n + nn, err } func sprintValues(o opts, v []interface{}) string { var b bytes.Buffer fprintValues(&b, o, v) return b.String() } func Fprint(w io.Writer, v ...interface{}) (int, error) { return fprintValues(w, none, v) } func Fprintw(w io.Writer, v ...interface{}) (int, error) { return fprintValues(w, wrap, v) } func Fprintt(w io.Writer, v ...interface{}) (int, error) { return fprintValues(w, types, v) } func Fprintwt(w io.Writer, v ...interface{}) (int, error) { return fprintValues(w, wrap|types, v) } func Fprintv(w io.Writer, v ...interface{}) (int, error) { return fprintValues(w, allTypes, v) } func Fprintwv(w io.Writer, v ...interface{}) (int, error) { return fprintValues(w, wrap|allTypes, v) } func Print(v ...interface{}) (int, error) { return printValues(none, v) } func Printw(v ...interface{}) (int, error) { return printValues(wrap, v) } func Printt(v ...interface{}) (int, error) { return printValues(types, v) } func Printwt(v ...interface{}) (int, error) { return printValues(wrap|types, v) } func Printv(v ...interface{}) (int, error) { return printValues(allTypes, v) } func Printwv(v ...interface{}) (int, error) { return printValues(wrap|allTypes, v) } func Println(v ...interface{}) (int, error) { return printlnValues(none, v) } func Printlnw(v ...interface{}) (int, error) { return printlnValues(wrap, v) } func Printlnt(v ...interface{}) (int, error) { return printlnValues(types, v) } func Printlnwt(v ...interface{}) (int, error) { return printlnValues(wrap|types, v) } func Printlnv(v ...interface{}) (int, error) { return printlnValues(allTypes, v) } func Printlnwv(v ...interface{}) (int, error) { return printlnValues(wrap|allTypes, v) } func Sprint(v ...interface{}) string { return sprintValues(none, v) } func Sprintw(v ...interface{}) string { return sprintValues(wrap, v) } func Sprintt(v ...interface{}) string { return sprintValues(types, v) } func Sprintwt(v ...interface{}) string { return sprintValues(wrap|types, v) } func Sprintv(v ...interface{}) string { return sprintValues(allTypes, v) } func Sprintwv(v ...interface{}) string { return sprintValues(wrap|allTypes, v) }