package main import ( "fmt" "os" "log" "flag" "bufio" "strings" "unicode/utf8" ) type Opts struct { Bytes bool Chars bool Words bool Lines bool } type Counts struct { Bytes int Chars int Words int Lines int Filename string } func parse_opts() (Opts, []string) { var opts Opts flag.BoolVar(&opts.Bytes, "c", false, "Count bytes") flag.BoolVar(&opts.Chars, "m", false, "Count chars") flag.BoolVar(&opts.Words, "w", false, "Count words") flag.BoolVar(&opts.Lines, "l", false, "Count lines") flag.Parse() if flag.NArg() == 0 { log.Fatal("USAGE: wc [-l] [-w] [-m] [-c] ") } if !opts.Bytes && !opts.Chars && !opts.Words && !opts.Lines { opts.Lines = true } return opts, flag.Args() } func count_file(opts *Opts, filename string) Counts { var counts Counts in_file, err := os.Open(filename) if err != nil { log.Fatal(err) } defer in_file.Close() scan := bufio.NewScanner(in_file) for scan.Scan() { line := scan.Text() if opts.Lines { counts.Lines++ } if opts.Words { counts.Words += len(strings.Fields(line)) } if opts.Chars { counts.Chars += utf8.RuneCountInString(line) + 1 } if opts.Bytes { counts.Bytes += len(line) + 1 } } if scan.Err() != nil { log.Fatal(scan.Err()) } return counts } func print_count(opts *Opts, count *Counts, file string) { if opts.Lines { fmt.Print(count.Lines, " ") } if opts.Words { fmt.Print(count.Words, " ") } if opts.Chars { fmt.Print(count.Chars, " ") } if opts.Bytes { fmt.Print(count.Bytes, " ") } fmt.Println(" ", file) } func main() { opts, files := parse_opts() for _, file := range files { count := count_file(&opts, file) print_count(&opts, &count, file) } }