diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..4482a74 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,17 @@ +{ + // Utilisez IntelliSense pour en savoir plus sur les attributs possibles. + // Pointez pour afficher la description des attributs existants. + // Pour plus d'informations, visitez : https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Launch Package", + "type": "go", + "request": "launch", + "mode": "auto", + "program": "${fileDirname}", + "env": {}, + "args": ["-c", "test.txt"] +} + ] +} \ No newline at end of file diff --git a/gowc b/gowc deleted file mode 100755 index 4627604..0000000 Binary files a/gowc and /dev/null differ diff --git a/main.go b/main.go index f2f1e66..ee5f072 100644 --- a/main.go +++ b/main.go @@ -11,18 +11,43 @@ import ( "unicode/utf8" ) -func byteCounter(f *os.File) { +func isInputFromPipe() bool { + fileInfo, _ := os.Stdin.Stat() + return fileInfo.Mode()&os.ModeCharDevice == 0 +} + +func fileByteCounter(f *os.File) int64 { fileInfo, err := f.Stat() if err != nil { fmt.Fprintf(os.Stderr, "error: %v\n", err) os.Exit(1) } - fmt.Println(fileInfo.Size()) + return fileInfo.Size() +} + +func stdinByteCounter(f *os.File) int64 { + buf := make([]byte, 32*1024) + count := int64(0) + + for { + c, err := f.Read(buf) // c==0 if EOF + + switch { + case err == io.EOF: + return count + + case err != nil: + fmt.Fprintf(os.Stderr, "error: %v\n", err) + os.Exit(1) + } + + count += int64(c) + } } -func lineCounter(f io.Reader) { +func lineCounter(f io.Reader) int64 { buf := make([]byte, 32*1024) - count := 0 + count := int64(0) lineSep := []byte{'\n'} for { @@ -30,21 +55,20 @@ func lineCounter(f io.Reader) { switch { case err == io.EOF: - fmt.Println(count) - return + return count case err != nil: fmt.Fprintf(os.Stderr, "error: %v\n", err) os.Exit(1) } - count += bytes.Count(buf[:c], lineSep) + count += int64(bytes.Count(buf[:c], lineSep)) } } -func wordCounter(f io.Reader) { +func wordCounter(f io.Reader) int64 { buf := make([]byte, 32*1024) - count := 0 + count := int64(0) wordSep := []byte{' ', '\t', '\n', '\r', '\f', '\v'} inWord := false @@ -56,8 +80,7 @@ func wordCounter(f io.Reader) { if inWord { count++ } - fmt.Println(count) - return + return count case err != nil: fmt.Fprintf(os.Stderr, "error: %v\n", err) @@ -77,15 +100,15 @@ func wordCounter(f io.Reader) { } } -func charCounter(f *os.File) { +func charCounter(f *os.File) int64 { var line string var err error r := bufio.NewReader(f) - count := 0 + count := int64(0) for err == nil { line, err = r.ReadString('\n') - count += utf8.RuneCountInString(line) + count += int64(utf8.RuneCountInString(line)) } if err != io.EOF { @@ -93,39 +116,71 @@ func charCounter(f *os.File) { os.Exit(1) } - fmt.Println(count) + return count } func main() { + var f *os.File + var fileName string + var byteCounter func(f *os.File) int64 cFlag := flag.Bool("c", false, "print the byte count") lFlag := flag.Bool("l", false, "print the line count") wFlag := flag.Bool("w", false, "print the word count") mFlag := flag.Bool("m", false, "print the character count") flag.Parse() - fileName := flag.Arg(0) - if len(fileName) == 0 { - fmt.Fprintf(os.Stderr, "gowc [flags] filename\n") - flag.Usage() - os.Exit(1) - } + if isInputFromPipe() { + f = os.Stdin - f, err := os.Open(fileName) - if err != nil { - fmt.Fprintf(os.Stderr, "error: %v\n", err) - os.Exit(1) + if flag.NFlag() != 1 { + fmt.Fprintf(os.Stderr, "must provide a single flag to gowc when reading from stdin\n") + flag.Usage() + os.Exit(1) + } + + byteCounter = stdinByteCounter + } else { + fileName = flag.Arg(0) + + if len(fileName) == 0 { + fmt.Fprintf(os.Stderr, "gowc [flags] filename\n") + flag.Usage() + os.Exit(1) + } + + var err error + f, err = os.Open(fileName) + if err != nil { + fmt.Fprintf(os.Stderr, "error: %v\n", err) + os.Exit(1) + } + defer f.Close() + + byteCounter = fileByteCounter } - defer f.Close() switch { case *cFlag: - byteCounter(f) + fmt.Print("\t", byteCounter(f)) case *lFlag: - lineCounter(f) + fmt.Print("\t", lineCounter(f)) case *wFlag: - wordCounter(f) + fmt.Print("\t", wordCounter(f)) case *mFlag: - charCounter(f) + fmt.Print("\t", charCounter(f)) + default: + b := byteCounter(f) + f.Seek(0, 0) + l := lineCounter(f) + f.Seek(0, 0) + w := wordCounter(f) + fmt.Print("\t", l, "\t", w, "\t", b) + } + + if len(fileName) > 0 { + fmt.Println("\t", fileName) + } else { + fmt.Println("") } }