package main import ( "bytes" "flag" "fmt" "io" "os" "slices" ) func byteCounter(f *os.File) { fileInfo, err := f.Stat() if err != nil { fmt.Fprintf(os.Stderr, "error: %v\n", err) os.Exit(1) } fmt.Println(fileInfo.Size()) } func lineCounter(f io.Reader) { buf := make([]byte, 32*1024) count := 0 lineSep := []byte{'\n'} for { c, err := f.Read(buf) // c==0 if EOF switch { case err == io.EOF: fmt.Println(count) return case err != nil: fmt.Fprintf(os.Stderr, "error: %v\n", err) os.Exit(1) } count += bytes.Count(buf[:c], lineSep) } } func wordCounter(f io.Reader) { buf := make([]byte, 32*1024) count := 0 wordSep := []byte{' ', '\t', '\n', '\r', '\f', '\v'} inWord := false for { c, err := f.Read(buf) switch { case err == io.EOF: if inWord { count++ } fmt.Println(count) return case err != nil: fmt.Fprintf(os.Stderr, "error: %v\n", err) os.Exit(1) } for _, b := range buf[:c] { if slices.Contains(wordSep, b) { if inWord { count++ } inWord = false } else { inWord = true } } } } func main() { cFlag := flag.Bool("c", false, "print the byte counts") lFlag := flag.Bool("l", false, "print the line counts") wFlag := flag.Bool("w", false, "print the word counts") flag.Parse() fileName := flag.Arg(0) if len(fileName) == 0 { fmt.Fprintf(os.Stderr, "gowc [flags] filename\n") flag.Usage() os.Exit(1) } f, err := os.Open(fileName) if err != nil { fmt.Fprintf(os.Stderr, "error: %v\n", err) os.Exit(1) } defer f.Close() switch { case *cFlag: byteCounter(f) case *lFlag: lineCounter(f) case *wFlag: wordCounter(f) } }