Source File: go-coreutils/wc/main.go

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] <files>")
  }

  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)
  }
}