This is an education project that attempts to reimplement the GNU coreutils in Go. You can find the full manual here:
https://www.gnu.org/software/coreutils/manual/coreutils.html
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
114 lines
1.8 KiB
114 lines
1.8 KiB
|
2 weeks ago
|
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)
|
||
|
|
}
|
||
|
|
}
|