Skip to content

Instantly share code, notes, and snippets.

@lestrrat
Last active September 25, 2016 05:33
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lestrrat/94c2e5179999343400a24dfa4649a59f to your computer and use it in GitHub Desktop.
Save lestrrat/94c2e5179999343400a24dfa4649a59f to your computer and use it in GitHub Desktop.
おもしろそうだったので自分もwc書いてみたけど、元のCで書かれたwcをあんまり改良するところがなかった…
package main
import (
"flag"
"fmt"
"io"
"log"
"os"
"runtime/pprof"
"sync"
"unicode"
"unicode/utf8"
)
type result struct {
err error
filename string
bytes int
lines int
words int
}
var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
var showbytes = flag.Bool("c", false, "print bytes")
var showlines = flag.Bool("l", false, "print lines")
var showwords = flag.Bool("w", false, "print words")
var domulti = false
func main() {
flag.Parse()
if *cpuprofile != "" {
f, err := os.Create(*cpuprofile)
if err != nil {
log.Fatal(err)
}
pprof.StartCPUProfile(f)
defer pprof.StopCPUProfile()
}
if *showwords {
domulti = true
} else if !*showlines && !*showwords && !*showbytes {
domulti = true
*showlines = true
*showwords = true
*showbytes = true
}
var wg sync.WaitGroup
results := make(chan *result, flag.NArg())
for i := 0; i < flag.NArg(); i++ {
f := flag.Arg(i)
wg.Add(1)
go func() {
defer wg.Done()
countFile(results, f)
}()
}
wg.Wait()
close(results)
var total result
total.filename = "total"
for r := range results {
format(r)
total.bytes += r.bytes
total.words += r.words
total.lines += r.lines
}
format(&total)
}
func countFile(ch chan *result, fn string) {
r := result{filename: fn}
defer func() {
ch <- &r
}()
if !domulti && *showlines {
f, err := os.Open(fn)
if err != nil {
r.err = err
return
}
defer f.Close()
buf := make([]byte, 8192)
for {
n, err := f.Read(buf)
if n > 0 {
for _, b := range buf[:n] {
if b == '\n' {
r.lines++
}
}
}
switch err {
case nil:
case io.EOF:
return
default:
r.err = err
return
}
}
return
}
if *showbytes || domulti {
st, err := os.Stat(fn)
if err != nil {
r.err = err
return
} else {
r.bytes = int(st.Size())
}
}
if domulti {
f, err := os.Open(fn)
if err != nil {
r.err = err
return
}
defer f.Close()
gotsp := true
buf := make([]byte, 8192)
for {
n, err := f.Read(buf)
for i := 0; i < n; {
v, nv := utf8.DecodeRune(buf[i:n])
switch {
case unicode.IsSpace(v):
if v == '\n' {
r.lines++
}
gotsp = true
default:
if gotsp {
gotsp = false
r.words++
}
}
i += nv
}
switch err {
case nil:
case io.EOF:
return
default:
r.err = err
return
}
}
}
}
func format(r *result) {
if r.err != nil {
log.Printf("%s", r.err)
return
}
if *showlines {
fmt.Printf(" %7d", r.lines)
}
if *showwords {
fmt.Printf(" %7d", r.words)
}
if *showbytes {
fmt.Printf(" %7d", r.bytes)
}
fmt.Printf(" %s\n", r.filename)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment