101 lines
1.9 KiB
Go
101 lines
1.9 KiB
Go
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"flag"
|
|
"io"
|
|
"os"
|
|
)
|
|
|
|
var (
|
|
stdin io.Reader = os.Stdin
|
|
stdout io.Writer = os.Stdout
|
|
columnDelimiter string
|
|
pageDelimiter string
|
|
minimumInstances int
|
|
)
|
|
|
|
func main() {
|
|
flag.StringVar(&pageDelimiter, "p", "\f", "page delimiter character")
|
|
flag.StringVar(&columnDelimiter, "d", " ", "column delimiter character")
|
|
flag.IntVar(&minimumInstances, "m", 2, "minimum non-leading instances of delimiter to break a column")
|
|
flag.Parse()
|
|
if err := _main(); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
func _main() error {
|
|
r := bufio.NewReader(stdin)
|
|
for {
|
|
b, err := readPage(r)
|
|
if err != nil && err != io.EOF {
|
|
return err
|
|
}
|
|
if err := putPage(b); err != nil {
|
|
return err
|
|
}
|
|
if err == io.EOF {
|
|
break
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func readPage(r *bufio.Reader) ([]byte, error) {
|
|
return _readPage([]byte(pageDelimiter)[0], r)
|
|
}
|
|
|
|
func _readPage(d byte, r *bufio.Reader) ([]byte, error) {
|
|
b, err := r.ReadBytes(d)
|
|
if len(b) > 0 && byte(b[len(b)-1]) == d {
|
|
b = b[:len(b)-1]
|
|
}
|
|
return b, err
|
|
}
|
|
|
|
func putPage(b []byte) error {
|
|
return _putPage(stdout, b, []byte(columnDelimiter)[0], minimumInstances)
|
|
}
|
|
|
|
func _putPage(w io.Writer, b []byte, d byte, instances int) error {
|
|
nonFirstColumn := []byte{}
|
|
for _, line := range lines(b) {
|
|
line = bytes.TrimSpace(line)
|
|
i := 0
|
|
for i < len(line) && line[i] == d {
|
|
i += 1
|
|
}
|
|
if i > 20 {
|
|
nonFirstColumn = append(nonFirstColumn, line...)
|
|
line = line[:0]
|
|
}
|
|
for i < len(line) {
|
|
j := 0
|
|
for j+i < len(line) && line[i+j] == d {
|
|
j += 1
|
|
}
|
|
if j >= instances {
|
|
nonFirstColumn = append(nonFirstColumn, line[i+j:]...)
|
|
line = line[:i+j]
|
|
break
|
|
}
|
|
i += 1
|
|
}
|
|
w.Write(line)
|
|
w.Write([]byte{'\n'})
|
|
}
|
|
if len(nonFirstColumn) > 0 {
|
|
return _putPage(w, nonFirstColumn, d, instances)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func lines(b []byte) [][]byte {
|
|
return bytes.Split(b, []byte{'\n'})
|
|
}
|
|
|
|
func startOfNextColumn(line []byte, d byte, instances int) (int, {
|
|
}
|