func main() { flag.Usage = func() { fmt.Printf("Usage: %s [OPTION]... [FILE]\n", flag.Program) fmt.Printf(`Output who is currently logged in according to FILE. If FILE is not specified, use %s. %s as FILE is common. `, utmp.UtmpxFile, utmp.Wtmpxfile) flag.PrintDefaults() fmt.Printf(` Report %s bugs to [email protected] Go coreutils home page: <https://www.github.com/EricLagergren/go-coreutils/> `, flag.Program) os.Exit(0) } flag.Parse() switch flag.NArg() { case 0: users(utmp.UtmpxFile, utmp.CheckPIDs) case 1: users(flag.Arg(0), 0) default: log.Fatalf("extra operand(s) %v", flag.Args()[1:]) } }
func main() { var ok int // return status outStat, err := os.Stdout.Stat() if err != nil { fatal.Fatalln(err) } outReg := outStat.Mode().IsRegular() outBsize := bsize(outStat) // catch (./cat) < /etc/group args := flag.Args() if flag.NArg() == 0 { args = []string{"-"} } var file *os.File for _, arg := range args { file = os.Stdin if arg != "-" { file, err = os.Open(arg) if err != nil { fatal.Fatalln(err) } } inStat, err := file.Stat() if err != nil { fatal.Fatalln(err) } if inStat.IsDir() { fatal.Printf("%s: is a directory\n", file.Name()) } inBsize := bsize(inStat) // prefetch! prefetch! prefetch! unix.Fadvise(int(file.Fd()), 0, 0, unix.FADV_SEQUENTIAL) // Make sure we're not catting a file to itself, // provided it's a regular file. Catting a non-reg // file to itself is cool. // e.g. cat file > file if outReg && os.SameFile(outStat, inStat) { if n, _ := file.Seek(0, os.SEEK_CUR); n < inStat.Size() { fatal.Fatalf("%s: input file is output file\n", file.Name()) } } pageSize := os.Getpagesize() if simple { // Select larger block size size := max(inBsize, outBsize) outBuf := bufio.NewWriterSize(os.Stdout, size+pageSize-1) ok ^= simpleCat(file, outBuf) // Flush because we don't have a chance to in // simpleCat() because we use io.Copy() outBuf.Flush() } else { // If you want to know why, exactly, I chose // outBsize -1 + inBsize*4 + 20, read GNU's cat // source code. The tl;dr is the 20 is the counter // buffer, inBsize*4 is from potentially prepending // the control characters (M-^), and outBsize is // due to new tests for newlines. size := outBsize - 1 + inBsize*4 + 20 outBuf := bufio.NewWriterSize(os.Stdout, size) inBuf := make([]byte, inBsize+pageSize-1) ok ^= cat(file, inBuf, outBuf) } file.Close() } os.Exit(ok) }
func main() { flag.Usage = func() { fmt.Printf(`Usage: %s [OPTION]... [FILE]... or: wc [OPTION]... --files0-from=F Print newline, word, and byte counts for each FILE, and a total line if more than one FILE is specified. A word is a non-zero-length sequence of characters delimited by white space. With no FILE, or when FILE is -, read standard input. The options below may be used to select which counts are printed, always in the following order: newline, word, character, byte, maximum line length. `, flag.Program) flag.PrintDefaults() fmt.Printf(` Report %s bugs to [email protected] Go coreutils home page: <https://www.github.com/EricLagergren/go-coreutils/> `, flag.Program) os.Exit(0) } flag.ProgVersion = "2.2" flag.Parse() if *constVersion { fmt.Printf("Unicode Version: %s\n", unicode.Version) os.Exit(0) } if !(*printBytes || *printChars || *printLines || *printWords || *printLineLength) { *printLines = true *printBytes = true *printWords = true } // This is a gross attempt to simulate this... // (print_lines + print_words + print_chars + // print_bytes + print_linelength) == 1 // // Since Go can't add booleans (e.g. false + true == 1) // and checking that *only* one of 5 bool variables would be sloppy, // we check the number of set flags and the remaining non-'print' flags // which is a much smaller set of conditions to check // // I could just use a loop, but this also removes a branch soooo... printOne = // 1 flag and it's not *filesFrom OR *tabWidth ((flag.NFlag() == 1 && *filesFrom == "" && *tabWidth == 8) || // 2 flags and one is *filesFrom OR *tabWidth (flag.NFlag() == 2 && (*filesFrom != "" || *tabWidth != 8)) || // 3 flags and two are *filesFrom AND *tabWidth (flag.NFlag() == 3 && *filesFrom != "" && *tabWidth != 8)) var ( ok int // Return status. files = flag.Args() // List of files. numFiles = len(files) // Number of files to wc. reasonable = true // Can we read file list into memory? size int64 ) if *filesFrom != "" { // Cannot specify files with --files0-from. if flag.NArg() > 0 { fatal("file operands cannot be combined with --files0-from") } // --files0-from is small enough to fit into RAM. if reasonable, size = isReasonable(*filesFrom); reasonable { files, numFiles = getFileList(*filesFrom, size) } } fs := getFileStatus(files) numberWidth = findNumberWidth(fs) if reasonable { if files == nil || len(files) == 0 { files = []string{"-"} } for i, file := range files { ok ^= wcFile(file, fs[i]) } } else { var err error file := os.Stdin if *filesFrom != "-" { file, err = os.Open(*filesFrom) } if err != nil { fatal("cannot open %q for reading: No such file or directory", *filesFrom) } defer file.Close() s := bufio.NewScanner(file) s.Split(func(data []byte, atEOF bool) (advance int, token []byte, err error) { if atEOF && len(data) == 0 { return 0, nil, nil } if i := bytes.IndexByte(data, nullByte); i >= 0 { // We have a full newline-terminated line. return i + 1, dropnullByte(numFiles, data[0:i]), nil } // If we're at EOF, we have a final, non-terminated line. Return it. if atEOF { return len(data), dropnullByte(numFiles, data), nil } // Request more data. return 0, nil, nil }) for ; s.Scan(); numFiles++ { ok ^= wcFile(s.Text(), fstatus{}) } if err := s.Err(); err != nil { fatal("%v", err) } } if numFiles > 1 { writeCounts(totalLines, totalWords, totalChars, totalBytes, maxLineLength, "total") } // Return status. os.Exit(ok) }