You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

99 lines
2.0 KiB
Go

package main
import (
"encoding/csv"
"encoding/json"
"errors"
"flag"
"fmt"
"io"
"os"
"sync"
)
const (
FormatCSV = "csv"
FormatJSON = "json"
FormatStream = "stream"
)
type UnknownFormatError struct{ Format string }
func (e UnknownFormatError) Error() string {
return "unknown format: '" + e.Format + "'"
}
func main() {
if err := run(); err != nil {
_, _ = os.Stderr.WriteString("ERROR: " + err.Error())
os.Exit(1)
}
}
func run() error {
var in string
var out string
var format string
var width int
flag.StringVar(&in, "in", "", "input file")
flag.StringVar(&out, "out", "", "output file")
flag.StringVar(&format, "format", "csv", "output format (csv,json,stream)")
flag.IntVar(&width, "width", DefaultTabWidth, "spaces per tab")
flag.Parse()
var input io.ReadCloser = os.Stdin
var output io.WriteCloser = os.Stdout
if in != "" {
var err error
if input, err = os.Open(in); err != nil {
return fmt.Errorf("failed to get input %s: %w", in, err)
}
}
if out != "" {
var err error
if output, err = os.Create(out); err != nil {
return fmt.Errorf("failed to get output %s: %w", out, err)
}
}
p := Parser{Width: width}
var err error
switch format {
case FormatCSV:
var once sync.Once
writer := csv.NewWriter(output)
err = p.IterSlice(input, func(headers []string, values []string) error {
var err error
once.Do(func() { err = writer.Write(headers) })
if err != nil {
return err
}
return writer.Write(values)
})
writer.Flush()
case FormatStream:
enc := json.NewEncoder(output)
err = p.IterMap(input, func(values map[string]string) error {
return enc.Encode(values)
})
case FormatJSON:
var doc Document
doc, err = p.Parse(input)
if err != nil {
return fmt.Errorf("failed to parse input: %w",
errors.Join(err, input.Close(), output.Close()))
}
err = json.NewEncoder(output).Encode(doc)
default:
err = UnknownFormatError{Format: format}
}
return errors.Join(err, input.Close(), output.Close())
}