From 139ed9a344ec50c59b76933668b54e55d7bd0dbd Mon Sep 17 00:00:00 2001 From: Dustin Pianalto Date: Fri, 25 Sep 2020 00:57:34 -0800 Subject: [PATCH] Add support for files0-from and quote filename output --- cmd/wc-go/main.go | 113 ++++++++++++++++++++++++++++++++++++---------- go.mod | 5 +- go.sum | 6 +++ pkg/wc/counter.go | 14 ++++-- 4 files changed, 108 insertions(+), 30 deletions(-) diff --git a/cmd/wc-go/main.go b/cmd/wc-go/main.go index 7652cd6..22bfb6c 100644 --- a/cmd/wc-go/main.go +++ b/cmd/wc-go/main.go @@ -33,9 +33,15 @@ package main // output version information and exit import ( + "bufio" "fmt" + "io" + "log" + "os" + "strings" "github.com/droundy/goopt" + "github.com/dustinpianalto/quotearg" "github.com/dustinpianalto/wc-go/pkg/wc" ) @@ -69,9 +75,10 @@ var ( func main() { goopt.Version = "v0.0.0a" goopt.Parse(nil) - if len(goopt.Args) == 0 { + if len(goopt.Args) == 0 && *fFilesFrom == "" { fmt.Println(goopt.Help()) } else { + if !*fWords && !*fChars && !*fLines && !*fBytes && !*fMaxLineLength { *fWords = true *fChars = false @@ -79,8 +86,59 @@ func main() { *fBytes = true *fMaxLineLength = false } + + var files []string + if *fFilesFrom != "" { + fFile, err := os.Open(*fFilesFrom) + if err != nil { + log.Fatalf("Cannot open file %s: %s", fFilesFrom, err.Error()) + } + reader := bufio.NewReader(fFile) + for { + s, err := reader.ReadString(0x00) + if err == io.EOF { + break + } else if err != nil { + log.Fatal(err) + } + files = append(files, strings.TrimRight(s, "\x00")) + } + + fFile.Close() + } + + files = append(files, goopt.Args...) + + var maxBytes int64 + if len(files) > 1 || + ((*fWords && *fChars) || + (*fWords && *fLines) || + (*fWords && *fBytes) || + (*fWords && *fMaxLineLength) || + (*fChars && *fLines) || + (*fChars && *fBytes) || + (*fChars && *fMaxLineLength) || + (*fLines && *fBytes) || + (*fLines && *fMaxLineLength) || + (*fBytes && *fMaxLineLength)) { + for _, f := range files { + fp, err := os.Open(f) + if err != nil { + continue + } + fi, err := fp.Stat() + if err != nil { + continue + } + b := fi.Size() + maxBytes += b + } + } + + var maxStrLen = intLen(maxBytes) + var TotalCounts wc.Counter - for _, a := range goopt.Args { + for _, a := range files { count, err := wc.Count(a, *fWords, *fChars, *fLines, *fBytes, *fMaxLineLength) if err == nil { TotalCounts.Lines += count.Lines @@ -89,49 +147,56 @@ func main() { TotalCounts.Chars += count.Chars TotalCounts.MaxLineLength += count.MaxLineLength if *fLines { - fmt.Printf("%d", count.Lines) + fmt.Printf("%*d ", maxStrLen, count.Lines) } - fmt.Printf(" ") if *fWords { - fmt.Printf("%d", count.Words) + fmt.Printf("%*d ", maxStrLen, count.Words) } - fmt.Printf(" ") if *fChars { - fmt.Printf("%d", count.Chars) + fmt.Printf("%*d ", maxStrLen, count.Chars) } - fmt.Printf(" ") if *fBytes { - fmt.Printf("%d", count.Bytes) + fmt.Printf("%*d ", maxStrLen, count.Bytes) } - fmt.Printf(" ") if *fMaxLineLength { - fmt.Printf("%d", count.MaxLineLength) + fmt.Printf("%*d ", maxStrLen, count.MaxLineLength) } - fmt.Printf(" %s\n", a) - } + if strings.Contains(a, "\n") { + n := quotearg.Quote([]rune(a), quotearg.ShellEscapeAlwaysQuotingStyle, 0, 0, '\'', '\'') + fmt.Printf("%s\n", string(n)) + } else { + fmt.Printf("%s\n", a) + } + } } - if len(goopt.Args) > 1 { + + if len(files) > 1 { if *fLines { - fmt.Printf("%d", TotalCounts.Lines) + fmt.Printf("%*d ", maxStrLen, TotalCounts.Lines) } - fmt.Printf(" ") if *fWords { - fmt.Printf("%d", TotalCounts.Words) + fmt.Printf("%*d ", maxStrLen, TotalCounts.Words) } - fmt.Printf(" ") if *fChars { - fmt.Printf("%d", TotalCounts.Chars) + fmt.Printf("%*d ", maxStrLen, TotalCounts.Chars) } - fmt.Printf(" ") if *fBytes { - fmt.Printf("%d", TotalCounts.Bytes) + fmt.Printf("%*d ", maxStrLen, TotalCounts.Bytes) } - fmt.Printf(" ") if *fMaxLineLength { - fmt.Printf("%d", TotalCounts.MaxLineLength) + fmt.Printf("%*d ", maxStrLen, TotalCounts.MaxLineLength) } - fmt.Println(" total") + fmt.Println("total") } } } + +func intLen(i int64) int64 { + var count int64 + for i != 0 { + i /= 10 + count++ + } + return count +} diff --git a/go.mod b/go.mod index c0e5b20..10bbf17 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,7 @@ module github.com/dustinpianalto/wc-go go 1.15 -require github.com/droundy/goopt v0.0.0-20170604162106-0b8effe182da // indirect +require ( + github.com/droundy/goopt v0.0.0-20170604162106-0b8effe182da // indirect + github.com/dustinpianalto/quotearg v0.0.3 // indirect +) diff --git a/go.sum b/go.sum index 2a063ec..c2366ff 100644 --- a/go.sum +++ b/go.sum @@ -1,2 +1,8 @@ github.com/droundy/goopt v0.0.0-20170604162106-0b8effe182da h1:79H+mNJWOObWrQgbkSvvZ3t/D2lKWaTi9mu/v7fNRvg= github.com/droundy/goopt v0.0.0-20170604162106-0b8effe182da/go.mod h1:ytRJ64WkuW4kf6/tuYqBATBCRFUP8X9+LDtgcvE+koI= +github.com/dustinpianalto/quotearg v0.0.1 h1:xOFDoVUynWjIroscuIvlVC/ClKTPVEJS3hACgGJS04w= +github.com/dustinpianalto/quotearg v0.0.1/go.mod h1:iTJRlY94fTiBYMJPmHxsjyensPAFut/3ruOMvSTcqg4= +github.com/dustinpianalto/quotearg v0.0.2 h1:4u8pohblUd+aP7/PZ58UiRkDtoimtZgfvfpY211y5tk= +github.com/dustinpianalto/quotearg v0.0.2/go.mod h1:iTJRlY94fTiBYMJPmHxsjyensPAFut/3ruOMvSTcqg4= +github.com/dustinpianalto/quotearg v0.0.3 h1:GWP0yKgjRqIPYev/1rSjhlkLbJQYU+37BnGi7e4MG5g= +github.com/dustinpianalto/quotearg v0.0.3/go.mod h1:iTJRlY94fTiBYMJPmHxsjyensPAFut/3ruOMvSTcqg4= diff --git a/pkg/wc/counter.go b/pkg/wc/counter.go index 016600f..b7a4775 100644 --- a/pkg/wc/counter.go +++ b/pkg/wc/counter.go @@ -25,6 +25,15 @@ func Count(filename string, cw, cc, cl, cb, mll bool) (Counter, error) { return Counter{}, err } defer file.Close() + fi, err := file.Stat() + if err != nil { + fmt.Println(err) + return Counter{}, err + } + if fi.IsDir() { + fmt.Printf("wc-go: %s: Is a directory\n", filename) + return Counter{}, err + } processLine := cw || cc @@ -39,11 +48,6 @@ func Count(filename string, cw, cc, cl, cb, mll bool) (Counter, error) { } if cb { - fi, err := file.Stat() - if err != nil { - fmt.Println(err) - return Counter{}, err - } c.Bytes = fi.Size() } return *c, nil